Merge "x86_64: Updating makefile to avoid early fail of other projects build"
diff --git a/Android.mk b/Android.mk
index 76fb411..0492d3c 100644
--- a/Android.mk
+++ b/Android.mk
@@ -93,9 +93,9 @@
 include $(art_build_path)/Android.oat.mk
 
 # ART_HOST_DEPENDENCIES depends on Android.executable.mk above for ART_HOST_EXECUTABLES
-ART_HOST_DEPENDENCIES := $(ART_HOST_EXECUTABLES) $(HOST_OUT_JAVA_LIBRARIES)/core-hostdex.jar
+ART_HOST_DEPENDENCIES := $(ART_HOST_EXECUTABLES) $(HOST_OUT_JAVA_LIBRARIES)/core-libart-hostdex.jar
 ART_HOST_DEPENDENCIES += $(HOST_OUT_SHARED_LIBRARIES)/libjavacore$(ART_HOST_SHLIB_EXTENSION)
-ART_TARGET_DEPENDENCIES := $(ART_TARGET_EXECUTABLES) $(TARGET_OUT_JAVA_LIBRARIES)/core.jar $(TARGET_OUT_SHARED_LIBRARIES)/libjavacore.so
+ART_TARGET_DEPENDENCIES := $(ART_TARGET_EXECUTABLES) $(TARGET_OUT_JAVA_LIBRARIES)/core-libart.jar $(TARGET_OUT_SHARED_LIBRARIES)/libjavacore.so
 
 ########################################################################
 # test targets
diff --git a/compiler/Android.mk b/compiler/Android.mk
index b7dc9f6..a2419d5 100644
--- a/compiler/Android.mk
+++ b/compiler/Android.mk
@@ -23,7 +23,6 @@
 	dex/local_value_numbering.cc \
 	dex/arena_allocator.cc \
 	dex/arena_bit_vector.cc \
-	dex/quick/arm/arm_dex_file_method_inliner.cc \
 	dex/quick/arm/assemble_arm.cc \
 	dex/quick/arm/call_arm.cc \
 	dex/quick/arm/fp_arm.cc \
@@ -41,7 +40,6 @@
 	dex/quick/mips/call_mips.cc \
 	dex/quick/mips/fp_mips.cc \
 	dex/quick/mips/int_mips.cc \
-	dex/quick/mips/mips_dex_file_method_inliner.cc \
 	dex/quick/mips/target_mips.cc \
 	dex/quick/mips/utility_mips.cc \
 	dex/quick/mir_to_lir.cc \
@@ -52,7 +50,6 @@
 	dex/quick/x86/int_x86.cc \
 	dex/quick/x86/target_x86.cc \
 	dex/quick/x86/utility_x86.cc \
-	dex/quick/x86/x86_dex_file_method_inliner.cc \
 	dex/portable/mir_to_gbc.cc \
 	dex/dex_to_dex_compiler.cc \
 	dex/mir_dataflow.cc \
diff --git a/compiler/dex/arena_allocator.cc b/compiler/dex/arena_allocator.cc
index 95e44b3..132831c 100644
--- a/compiler/dex/arena_allocator.cc
+++ b/compiler/dex/arena_allocator.cc
@@ -28,6 +28,7 @@
 static constexpr bool kUseMemMap = false;
 static constexpr bool kUseMemSet = true && kUseMemMap;
 static constexpr size_t kValgrindRedZoneBytes = 8;
+constexpr size_t Arena::kDefaultSize;
 
 static const char* alloc_names[ArenaAllocator::kNumAllocKinds] = {
   "Misc       ",
diff --git a/compiler/dex/compiler_enums.h b/compiler/dex/compiler_enums.h
index 56facfd..d73f148 100644
--- a/compiler/dex/compiler_enums.h
+++ b/compiler/dex/compiler_enums.h
@@ -374,6 +374,7 @@
   kRegUseA,
   kRegUseC,
   kRegUseD,
+  kRegUseB,
   kRegUseFPCSList0,
   kRegUseFPCSList2,
   kRegUseList0,
diff --git a/compiler/dex/dex_to_dex_compiler.cc b/compiler/dex/dex_to_dex_compiler.cc
index abafbc5..3368132 100644
--- a/compiler/dex/dex_to_dex_compiler.cc
+++ b/compiler/dex/dex_to_dex_compiler.cc
@@ -52,12 +52,6 @@
     return *unit_.GetDexFile();
   }
 
-  // TODO: since the whole compilation pipeline uses a "const DexFile", we need
-  // to "unconst" here. The DEX-to-DEX compiler should work on a non-const DexFile.
-  DexFile& GetModifiableDexFile() {
-    return *const_cast<DexFile*>(unit_.GetDexFile());
-  }
-
   bool PerformOptimizations() const {
     return dex_to_dex_compilation_level_ >= kOptimize;
   }
diff --git a/compiler/dex/frontend.cc b/compiler/dex/frontend.cc
index 197bba5..6aabb2a 100644
--- a/compiler/dex/frontend.cc
+++ b/compiler/dex/frontend.cc
@@ -63,21 +63,21 @@
 LLVMInfo::~LLVMInfo() {
 }
 
-QuickCompilerContext::QuickCompilerContext(CompilerDriver& compiler)
-  : inliner_map_(new DexFileToMethodInlinerMap(&compiler)) {
+QuickCompilerContext::QuickCompilerContext()
+  : inliner_map_(new DexFileToMethodInlinerMap()) {
 }
 
 QuickCompilerContext::~QuickCompilerContext() {
 }
 
-extern "C" void ArtInitQuickCompilerContext(art::CompilerDriver& compiler) {
-  CHECK(compiler.GetCompilerContext() == NULL);
-  compiler.SetCompilerContext(new QuickCompilerContext(compiler));
+extern "C" void ArtInitQuickCompilerContext(art::CompilerDriver& driver) {
+  CHECK(driver.GetCompilerContext() == NULL);
+  driver.SetCompilerContext(new QuickCompilerContext());
 }
 
-extern "C" void ArtUnInitQuickCompilerContext(art::CompilerDriver& compiler) {
-  delete reinterpret_cast<QuickCompilerContext*>(compiler.GetCompilerContext());
-  compiler.SetCompilerContext(NULL);
+extern "C" void ArtUnInitQuickCompilerContext(art::CompilerDriver& driver) {
+  delete reinterpret_cast<QuickCompilerContext*>(driver.GetCompilerContext());
+  driver.SetCompilerContext(NULL);
 }
 
 /* Default optimizer/debug setting for the compiler. */
diff --git a/compiler/dex/frontend.h b/compiler/dex/frontend.h
index 4a863f5..bcb8bf0 100644
--- a/compiler/dex/frontend.h
+++ b/compiler/dex/frontend.h
@@ -115,7 +115,7 @@
 
 class QuickCompilerContext {
   public:
-    explicit QuickCompilerContext(CompilerDriver& compiler);
+    QuickCompilerContext();
     ~QuickCompilerContext();
 
     DexFileToMethodInlinerMap* GetInlinerMap() {
diff --git a/compiler/dex/mir_optimization.cc b/compiler/dex/mir_optimization.cc
index 6353937..5d83991 100644
--- a/compiler/dex/mir_optimization.cc
+++ b/compiler/dex/mir_optimization.cc
@@ -923,11 +923,11 @@
       for (unsigned int i = 0; i < extended_basic_blocks_.size(); i++) {
         BasicBlockOpt(GetBasicBlock(extended_basic_blocks_[i]));
       }
-    }
-  } else {
-    PreOrderDfsIterator iter(this);
-    for (BasicBlock* bb = iter.Next(); bb != NULL; bb = iter.Next()) {
-      BasicBlockOpt(bb);
+    } else {
+      PreOrderDfsIterator iter(this);
+      for (BasicBlock* bb = iter.Next(); bb != NULL; bb = iter.Next()) {
+        BasicBlockOpt(bb);
+      }
     }
   }
   if (cu_->enable_debug & (1 << kDebugDumpCFG)) {
diff --git a/compiler/dex/portable/mir_to_gbc.cc b/compiler/dex/portable/mir_to_gbc.cc
index e5b4876..70b660b 100644
--- a/compiler/dex/portable/mir_to_gbc.cc
+++ b/compiler/dex/portable/mir_to_gbc.cc
@@ -1660,7 +1660,6 @@
       uint16_t arg_reg = cu_->num_regs;
 
       ::llvm::Function::arg_iterator arg_iter(func_->arg_begin());
-      ::llvm::Function::arg_iterator arg_end(func_->arg_end());
 
       const char* shorty = cu_->shorty;
       uint32_t shorty_size = strlen(shorty);
diff --git a/compiler/dex/quick/arm/arm_dex_file_method_inliner.cc b/compiler/dex/quick/arm/arm_dex_file_method_inliner.cc
deleted file mode 100644
index 59f7202..0000000
--- a/compiler/dex/quick/arm/arm_dex_file_method_inliner.cc
+++ /dev/null
@@ -1,105 +0,0 @@
-/*
- * Copyright (C) 2013 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 "base/logging.h"
-#include "base/macros.h"
-#include "dex/compiler_enums.h"
-
-#include "arm_dex_file_method_inliner.h"
-
-namespace art {
-
-const DexFileMethodInliner::IntrinsicDef ArmDexFileMethodInliner::kIntrinsicMethods[] = {
-#define INTRINSIC(c, n, p, o, d) \
-    { { kClassCache ## c, kNameCache ## n, kProtoCache ## p }, { o, d } }
-
-    INTRINSIC(JavaLangDouble, DoubleToRawLongBits, D_J, kIntrinsicDoubleCvt, 0),
-    INTRINSIC(JavaLangDouble, LongBitsToDouble, J_D, kIntrinsicDoubleCvt, 0),
-    INTRINSIC(JavaLangFloat, FloatToRawIntBits, F_I, kIntrinsicFloatCvt, 0),
-    INTRINSIC(JavaLangFloat, IntBitsToFloat, I_F, kIntrinsicFloatCvt, 0),
-
-    INTRINSIC(JavaLangInteger, ReverseBytes, I_I, kIntrinsicReverseBytes, kWord),
-    INTRINSIC(JavaLangLong, ReverseBytes, J_J, kIntrinsicReverseBytes, kLong),
-    INTRINSIC(JavaLangShort, ReverseBytes, S_S, kIntrinsicReverseBytes, kSignedHalf),
-
-    INTRINSIC(JavaLangMath,       Abs, I_I, kIntrinsicAbsInt, 0),
-    INTRINSIC(JavaLangStrictMath, Abs, I_I, kIntrinsicAbsInt, 0),
-    INTRINSIC(JavaLangMath,       Abs, J_J, kIntrinsicAbsLong, 0),
-    INTRINSIC(JavaLangStrictMath, Abs, J_J, kIntrinsicAbsLong, 0),
-    INTRINSIC(JavaLangMath,       Min, II_I, kIntrinsicMinMaxInt, kIntrinsicFlagMin),
-    INTRINSIC(JavaLangStrictMath, Min, II_I, kIntrinsicMinMaxInt, kIntrinsicFlagMin),
-    INTRINSIC(JavaLangMath,       Max, II_I, kIntrinsicMinMaxInt, kIntrinsicFlagMax),
-    INTRINSIC(JavaLangStrictMath, Max, II_I, kIntrinsicMinMaxInt, kIntrinsicFlagMax),
-    INTRINSIC(JavaLangMath,       Sqrt, D_D, kIntrinsicSqrt, 0),
-    INTRINSIC(JavaLangStrictMath, Sqrt, D_D, kIntrinsicSqrt, 0),
-
-    INTRINSIC(JavaLangString, CharAt, I_C, kIntrinsicCharAt, 0),
-    INTRINSIC(JavaLangString, CompareTo, String_I, kIntrinsicCompareTo, 0),
-    INTRINSIC(JavaLangString, IsEmpty, _Z, kIntrinsicIsEmptyOrLength, kIntrinsicFlagIsEmpty),
-    INTRINSIC(JavaLangString, IndexOf, II_I, kIntrinsicIndexOf, kIntrinsicFlagNone),
-    INTRINSIC(JavaLangString, IndexOf, I_I, kIntrinsicIndexOf, kIntrinsicFlagBase0),
-    INTRINSIC(JavaLangString, Length, _I, kIntrinsicIsEmptyOrLength, kIntrinsicFlagLength),
-
-    INTRINSIC(JavaLangThread, CurrentThread, _Thread, kIntrinsicCurrentThread, 0),
-
-    INTRINSIC(LibcoreIoMemory, PeekByte, J_B, kIntrinsicPeek, kSignedByte),
-    INTRINSIC(LibcoreIoMemory, PeekIntNative, J_I, kIntrinsicPeek, kWord),
-    INTRINSIC(LibcoreIoMemory, PeekLongNative, J_J, kIntrinsicPeek, kLong),
-    INTRINSIC(LibcoreIoMemory, PeekShortNative, J_S, kIntrinsicPeek, kSignedHalf),
-    INTRINSIC(LibcoreIoMemory, PokeByte, JB_V, kIntrinsicPoke, kSignedByte),
-    INTRINSIC(LibcoreIoMemory, PokeIntNative, JI_V, kIntrinsicPoke, kWord),
-    INTRINSIC(LibcoreIoMemory, PokeLongNative, JJ_V, kIntrinsicPoke, kLong),
-    INTRINSIC(LibcoreIoMemory, PokeShortNative, JS_V, kIntrinsicPoke, kSignedHalf),
-
-    INTRINSIC(SunMiscUnsafe, CompareAndSwapInt, ObjectJII_Z, kIntrinsicCas,
-              kIntrinsicFlagNone),
-    INTRINSIC(SunMiscUnsafe, CompareAndSwapLong, ObjectJJJ_Z, kIntrinsicCas,
-              kIntrinsicFlagIsLong),
-    INTRINSIC(SunMiscUnsafe, CompareAndSwapObject, ObjectJObjectObject_Z, kIntrinsicCas,
-              kIntrinsicFlagIsObject),
-
-#define UNSAFE_GET_PUT(type, code, type_flags) \
-    INTRINSIC(SunMiscUnsafe, Get ## type, ObjectJ_ ## code, kIntrinsicUnsafeGet, \
-              type_flags & ~kIntrinsicFlagIsObject), \
-    INTRINSIC(SunMiscUnsafe, Get ## type ## Volatile, ObjectJ_ ## code, kIntrinsicUnsafeGet, \
-              (type_flags | kIntrinsicFlagIsVolatile) & ~kIntrinsicFlagIsObject), \
-    INTRINSIC(SunMiscUnsafe, Put ## type, ObjectJ ## code ## _V, kIntrinsicUnsafePut, \
-              type_flags), \
-    INTRINSIC(SunMiscUnsafe, Put ## type ## Volatile, ObjectJ ## code ## _V, kIntrinsicUnsafePut, \
-              type_flags | kIntrinsicFlagIsVolatile), \
-    INTRINSIC(SunMiscUnsafe, PutOrdered ## type, ObjectJ ## code ## _V, kIntrinsicUnsafePut, \
-              type_flags | kIntrinsicFlagIsOrdered)
-
-    UNSAFE_GET_PUT(Int, I, kIntrinsicFlagNone),
-    UNSAFE_GET_PUT(Long, J, kIntrinsicFlagIsLong),
-    UNSAFE_GET_PUT(Object, Object, kIntrinsicFlagIsObject),
-#undef UNSAFE_GET_PUT
-
-#undef INTRINSIC
-};
-
-ArmDexFileMethodInliner::ArmDexFileMethodInliner() {
-}
-
-ArmDexFileMethodInliner::~ArmDexFileMethodInliner() {
-}
-
-void ArmDexFileMethodInliner::FindIntrinsics(const DexFile* dex_file) {
-  IndexCache cache;
-  DoFindIntrinsics(dex_file, &cache, kIntrinsicMethods, arraysize(kIntrinsicMethods));
-}
-
-}  // namespace art
diff --git a/compiler/dex/quick/arm/arm_dex_file_method_inliner.h b/compiler/dex/quick/arm/arm_dex_file_method_inliner.h
deleted file mode 100644
index 3428391..0000000
--- a/compiler/dex/quick/arm/arm_dex_file_method_inliner.h
+++ /dev/null
@@ -1,37 +0,0 @@
-/*
- * Copyright (C) 2013 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_DEX_QUICK_ARM_ARM_DEX_FILE_METHOD_INLINER_H_
-#define ART_COMPILER_DEX_QUICK_ARM_ARM_DEX_FILE_METHOD_INLINER_H_
-
-#include "dex/quick/dex_file_method_inliner.h"
-
-namespace art {
-
-class ArmDexFileMethodInliner : public DexFileMethodInliner {
-  public:
-    ArmDexFileMethodInliner();
-    ~ArmDexFileMethodInliner();
-
-    void FindIntrinsics(const DexFile* dex_file);
-
-  private:
-    static const IntrinsicDef kIntrinsicMethods[];
-};
-
-}  // namespace art
-
-#endif  // ART_COMPILER_DEX_QUICK_ARM_ARM_DEX_FILE_METHOD_INLINER_H_
diff --git a/compiler/dex/quick/arm/call_arm.cc b/compiler/dex/quick/arm/call_arm.cc
index 51aca85..23ea407 100644
--- a/compiler/dex/quick/arm/call_arm.cc
+++ b/compiler/dex/quick/arm/call_arm.cc
@@ -434,7 +434,7 @@
                rARM_LR);
   // Materialize a pointer to the fill data image
   NewLIR3(kThumb2Adr, r1, 0, WrapPointer(tab_rec));
-  ClobberCalleeSave();
+  ClobberCallerSave();
   LIR* call_inst = OpReg(kOpBlx, rARM_LR);
   MarkSafepointPC(call_inst);
 }
@@ -471,7 +471,7 @@
     // TODO: move to a slow path.
     // Go expensive route - artLockObjectFromCode(obj);
     LoadWordDisp(rARM_SELF, QUICK_ENTRYPOINT_OFFSET(pLockObject).Int32Value(), rARM_LR);
-    ClobberCalleeSave();
+    ClobberCallerSave();
     LIR* call_inst = OpReg(kOpBlx, rARM_LR);
     MarkSafepointPC(call_inst);
 
@@ -490,7 +490,7 @@
     OpIT(kCondNe, "T");
     // Go expensive route - artLockObjectFromCode(self, obj);
     LoadWordDisp/*ne*/(rARM_SELF, QUICK_ENTRYPOINT_OFFSET(pLockObject).Int32Value(), rARM_LR);
-    ClobberCalleeSave();
+    ClobberCallerSave();
     LIR* call_inst = OpReg(kOpBlx/*ne*/, rARM_LR);
     MarkSafepointPC(call_inst);
     GenMemBarrier(kLoadLoad);
@@ -530,7 +530,7 @@
     // TODO: move to a slow path.
     // Go expensive route - artUnlockObjectFromCode(obj);
     LoadWordDisp(rARM_SELF, QUICK_ENTRYPOINT_OFFSET(pUnlockObject).Int32Value(), rARM_LR);
-    ClobberCalleeSave();
+    ClobberCallerSave();
     LIR* call_inst = OpReg(kOpBlx, rARM_LR);
     MarkSafepointPC(call_inst);
 
@@ -549,7 +549,7 @@
     StoreWordDisp/*eq*/(r0, mirror::Object::MonitorOffset().Int32Value(), r3);
     // Go expensive route - UnlockObjectFromCode(obj);
     LoadWordDisp/*ne*/(rARM_SELF, QUICK_ENTRYPOINT_OFFSET(pUnlockObject).Int32Value(), rARM_LR);
-    ClobberCalleeSave();
+    ClobberCallerSave();
     LIR* call_inst = OpReg(kOpBlx/*ne*/, rARM_LR);
     MarkSafepointPC(call_inst);
     GenMemBarrier(kStoreLoad);
diff --git a/compiler/dex/quick/arm/codegen_arm.h b/compiler/dex/quick/arm/codegen_arm.h
index de3223a..25ddc94 100644
--- a/compiler/dex/quick/arm/codegen_arm.h
+++ b/compiler/dex/quick/arm/codegen_arm.h
@@ -60,7 +60,7 @@
     uint32_t FpRegMask();
     uint64_t GetRegMaskCommon(int reg);
     void AdjustSpillMask();
-    void ClobberCalleeSave();
+    void ClobberCallerSave();
     void FlushReg(int reg);
     void FlushRegWide(int reg1, int reg2);
     void FreeCallTemps();
diff --git a/compiler/dex/quick/arm/fp_arm.cc b/compiler/dex/quick/arm/fp_arm.cc
index 1575ece..dc2e0d0 100644
--- a/compiler/dex/quick/arm/fp_arm.cc
+++ b/compiler/dex/quick/arm/fp_arm.cc
@@ -315,7 +315,7 @@
           S2d(rl_result.low_reg, rl_result.high_reg));
   NewLIR0(kThumb2Fmstat);
   branch = NewLIR2(kThumbBCond, 0, kArmCondEq);
-  ClobberCalleeSave();
+  ClobberCallerSave();
   LockCallTemps();  // Using fixed registers
   int r_tgt = LoadHelper(QUICK_ENTRYPOINT_OFFSET(pSqrt));
   NewLIR3(kThumb2Fmrrd, r0, r1, S2d(rl_src.low_reg, rl_src.high_reg));
diff --git a/compiler/dex/quick/arm/target_arm.cc b/compiler/dex/quick/arm/target_arm.cc
index 52aba9b..48c9af5 100644
--- a/compiler/dex/quick/arm/target_arm.cc
+++ b/compiler/dex/quick/arm/target_arm.cc
@@ -653,7 +653,7 @@
 }
 
 /* Clobber all regs that might be used by an external C call */
-void ArmMir2Lir::ClobberCalleeSave() {
+void ArmMir2Lir::ClobberCallerSave() {
   Clobber(r0);
   Clobber(r1);
   Clobber(r2);
diff --git a/compiler/dex/quick/codegen_util.cc b/compiler/dex/quick/codegen_util.cc
index 4bc0b35..5d78ed5 100644
--- a/compiler/dex/quick/codegen_util.cc
+++ b/compiler/dex/quick/codegen_util.cc
@@ -24,6 +24,28 @@
 
 namespace art {
 
+namespace {
+
+/* Dump a mapping table */
+template <typename It>
+void DumpMappingTable(const char* table_name, const char* descriptor, const char* name,
+                      const Signature& signature, uint32_t size, It first) {
+  if (size != 0) {
+    std::string line(StringPrintf("\n  %s %s%s_%s_table[%zu] = {", table_name,
+                     descriptor, name, signature.ToString().c_str(), size));
+    std::replace(line.begin(), line.end(), ';', '_');
+    LOG(INFO) << line;
+    for (uint32_t i = 0; i != size; ++i) {
+      line = StringPrintf("    {0x%05x, 0x%04x},", first.NativePcOffset(), first.DexPc());
+      ++first;
+      LOG(INFO) << line;
+    }
+    LOG(INFO) <<"  };\n\n";
+  }
+}
+
+}  // anonymous namespace
+
 bool Mir2Lir::IsInexpensiveConstant(RegLocation rl_src) {
   bool res = false;
   if (rl_src.is_const) {
@@ -251,23 +273,6 @@
   }
 }
 
-/* Dump a mapping table */
-void Mir2Lir::DumpMappingTable(const char* table_name, const char* descriptor,
-                               const char* name, const Signature& signature,
-                               const std::vector<uint32_t>& v) {
-  if (v.size() > 0) {
-    std::string line(StringPrintf("\n  %s %s%s_%s_table[%zu] = {", table_name,
-                     descriptor, name, signature.ToString().c_str(), v.size()));
-    std::replace(line.begin(), line.end(), ';', '_');
-    LOG(INFO) << line;
-    for (uint32_t i = 0; i < v.size(); i+=2) {
-      line = StringPrintf("    {0x%05x, 0x%04x},", v[i], v[i+1]);
-      LOG(INFO) << line;
-    }
-    LOG(INFO) <<"  };\n\n";
-  }
-}
-
 /* Dump instructions and constant pool contents */
 void Mir2Lir::CodegenDump() {
   LOG(INFO) << "Dumping LIR insns for "
@@ -302,8 +307,13 @@
   const char* descriptor(cu_->dex_file->GetMethodDeclaringClassDescriptor(method_id));
 
   // Dump mapping tables
-  DumpMappingTable("PC2Dex_MappingTable", descriptor, name, signature, pc2dex_mapping_table_);
-  DumpMappingTable("Dex2PC_MappingTable", descriptor, name, signature, dex2pc_mapping_table_);
+  if (!encoded_mapping_table_.empty()) {
+    MappingTable table(&encoded_mapping_table_[0]);
+    DumpMappingTable("PC2Dex_MappingTable", descriptor, name, signature,
+                     table.PcToDexSize(), table.PcToDexBegin());
+    DumpMappingTable("Dex2PC_MappingTable", descriptor, name, signature,
+                     table.DexToPcSize(), table.DexToPcBegin());
+  }
 }
 
 /*
@@ -522,79 +532,128 @@
 
 // Make sure we have a code address for every declared catch entry
 bool Mir2Lir::VerifyCatchEntries() {
+  MappingTable table(&encoded_mapping_table_[0]);
+  std::vector<uint32_t> dex_pcs;
+  dex_pcs.reserve(table.DexToPcSize());
+  for (auto it = table.DexToPcBegin(), end = table.DexToPcEnd(); it != end; ++it) {
+    dex_pcs.push_back(it.DexPc());
+  }
+  // Sort dex_pcs, so that we can quickly check it against the ordered mir_graph_->catches_.
+  std::sort(dex_pcs.begin(), dex_pcs.end());
+
   bool success = true;
-  for (std::set<uint32_t>::const_iterator it = mir_graph_->catches_.begin();
-       it != mir_graph_->catches_.end(); ++it) {
-    uint32_t dex_pc = *it;
-    bool found = false;
-    for (size_t i = 0; i < dex2pc_mapping_table_.size(); i += 2) {
-      if (dex_pc == dex2pc_mapping_table_[i+1]) {
-        found = true;
-        break;
-      }
+  auto it = dex_pcs.begin(), end = dex_pcs.end();
+  for (uint32_t dex_pc : mir_graph_->catches_) {
+    while (it != end && *it < dex_pc) {
+      LOG(INFO) << "Unexpected catch entry @ dex pc 0x" << std::hex << *it;
+      ++it;
+      success = false;
     }
-    if (!found) {
+    if (it == end || *it > dex_pc) {
       LOG(INFO) << "Missing native PC for catch entry @ 0x" << std::hex << dex_pc;
       success = false;
-    }
-  }
-  // Now, try in the other direction
-  for (size_t i = 0; i < dex2pc_mapping_table_.size(); i += 2) {
-    uint32_t dex_pc = dex2pc_mapping_table_[i+1];
-    if (mir_graph_->catches_.find(dex_pc) == mir_graph_->catches_.end()) {
-      LOG(INFO) << "Unexpected catch entry @ dex pc 0x" << std::hex << dex_pc;
-      success = false;
+    } else {
+      ++it;
     }
   }
   if (!success) {
     LOG(INFO) << "Bad dex2pcMapping table in " << PrettyMethod(cu_->method_idx, *cu_->dex_file);
     LOG(INFO) << "Entries @ decode: " << mir_graph_->catches_.size() << ", Entries in table: "
-              << dex2pc_mapping_table_.size()/2;
+              << table.DexToPcSize();
   }
   return success;
 }
 
 
 void Mir2Lir::CreateMappingTables() {
+  uint32_t pc2dex_data_size = 0u;
+  uint32_t pc2dex_entries = 0u;
+  uint32_t pc2dex_offset = 0u;
+  uint32_t pc2dex_dalvik_offset = 0u;
+  uint32_t dex2pc_data_size = 0u;
+  uint32_t dex2pc_entries = 0u;
+  uint32_t dex2pc_offset = 0u;
+  uint32_t dex2pc_dalvik_offset = 0u;
   for (LIR* tgt_lir = first_lir_insn_; tgt_lir != NULL; tgt_lir = NEXT_LIR(tgt_lir)) {
     if (!tgt_lir->flags.is_nop && (tgt_lir->opcode == kPseudoSafepointPC)) {
-      pc2dex_mapping_table_.push_back(tgt_lir->offset);
-      pc2dex_mapping_table_.push_back(tgt_lir->dalvik_offset);
+      pc2dex_entries += 1;
+      DCHECK(pc2dex_offset <= tgt_lir->offset);
+      pc2dex_data_size += UnsignedLeb128Size(tgt_lir->offset - pc2dex_offset);
+      pc2dex_data_size += SignedLeb128Size(static_cast<int32_t>(tgt_lir->dalvik_offset) -
+                                           static_cast<int32_t>(pc2dex_dalvik_offset));
+      pc2dex_offset = tgt_lir->offset;
+      pc2dex_dalvik_offset = tgt_lir->dalvik_offset;
     }
     if (!tgt_lir->flags.is_nop && (tgt_lir->opcode == kPseudoExportedPC)) {
-      dex2pc_mapping_table_.push_back(tgt_lir->offset);
-      dex2pc_mapping_table_.push_back(tgt_lir->dalvik_offset);
+      dex2pc_entries += 1;
+      DCHECK(dex2pc_offset <= tgt_lir->offset);
+      dex2pc_data_size += UnsignedLeb128Size(tgt_lir->offset - dex2pc_offset);
+      dex2pc_data_size += SignedLeb128Size(static_cast<int32_t>(tgt_lir->dalvik_offset) -
+                                           static_cast<int32_t>(dex2pc_dalvik_offset));
+      dex2pc_offset = tgt_lir->offset;
+      dex2pc_dalvik_offset = tgt_lir->dalvik_offset;
     }
   }
+
+  uint32_t total_entries = pc2dex_entries + dex2pc_entries;
+  uint32_t hdr_data_size = UnsignedLeb128Size(total_entries) + UnsignedLeb128Size(pc2dex_entries);
+  uint32_t data_size = hdr_data_size + pc2dex_data_size + dex2pc_data_size;
+  encoded_mapping_table_.resize(data_size);
+  uint8_t* write_pos = &encoded_mapping_table_[0];
+  write_pos = EncodeUnsignedLeb128(write_pos, total_entries);
+  write_pos = EncodeUnsignedLeb128(write_pos, pc2dex_entries);
+  DCHECK_EQ(static_cast<size_t>(write_pos - &encoded_mapping_table_[0]), hdr_data_size);
+  uint8_t* write_pos2 = write_pos + pc2dex_data_size;
+
+  pc2dex_offset = 0u;
+  pc2dex_dalvik_offset = 0u;
+  dex2pc_offset = 0u;
+  dex2pc_dalvik_offset = 0u;
+  for (LIR* tgt_lir = first_lir_insn_; tgt_lir != NULL; tgt_lir = NEXT_LIR(tgt_lir)) {
+    if (!tgt_lir->flags.is_nop && (tgt_lir->opcode == kPseudoSafepointPC)) {
+      DCHECK(pc2dex_offset <= tgt_lir->offset);
+      write_pos = EncodeUnsignedLeb128(write_pos, tgt_lir->offset - pc2dex_offset);
+      write_pos = EncodeSignedLeb128(write_pos, static_cast<int32_t>(tgt_lir->dalvik_offset) -
+                                     static_cast<int32_t>(pc2dex_dalvik_offset));
+      pc2dex_offset = tgt_lir->offset;
+      pc2dex_dalvik_offset = tgt_lir->dalvik_offset;
+    }
+    if (!tgt_lir->flags.is_nop && (tgt_lir->opcode == kPseudoExportedPC)) {
+      DCHECK(dex2pc_offset <= tgt_lir->offset);
+      write_pos2 = EncodeUnsignedLeb128(write_pos2, tgt_lir->offset - dex2pc_offset);
+      write_pos2 = EncodeSignedLeb128(write_pos2, static_cast<int32_t>(tgt_lir->dalvik_offset) -
+                                      static_cast<int32_t>(dex2pc_dalvik_offset));
+      dex2pc_offset = tgt_lir->offset;
+      dex2pc_dalvik_offset = tgt_lir->dalvik_offset;
+    }
+  }
+  DCHECK_EQ(static_cast<size_t>(write_pos - &encoded_mapping_table_[0]),
+            hdr_data_size + pc2dex_data_size);
+  DCHECK_EQ(static_cast<size_t>(write_pos2 - &encoded_mapping_table_[0]), data_size);
+
   if (kIsDebugBuild) {
     CHECK(VerifyCatchEntries());
-  }
-  CHECK_EQ(pc2dex_mapping_table_.size() & 1, 0U);
-  CHECK_EQ(dex2pc_mapping_table_.size() & 1, 0U);
-  uint32_t total_entries = (pc2dex_mapping_table_.size() + dex2pc_mapping_table_.size()) / 2;
-  uint32_t pc2dex_entries = pc2dex_mapping_table_.size() / 2;
-  encoded_mapping_table_.PushBack(total_entries);
-  encoded_mapping_table_.PushBack(pc2dex_entries);
-  encoded_mapping_table_.InsertBack(pc2dex_mapping_table_.begin(), pc2dex_mapping_table_.end());
-  encoded_mapping_table_.InsertBack(dex2pc_mapping_table_.begin(), dex2pc_mapping_table_.end());
-  if (kIsDebugBuild) {
+
     // Verify the encoded table holds the expected data.
-    MappingTable table(&encoded_mapping_table_.GetData()[0]);
+    MappingTable table(&encoded_mapping_table_[0]);
     CHECK_EQ(table.TotalSize(), total_entries);
     CHECK_EQ(table.PcToDexSize(), pc2dex_entries);
-    CHECK_EQ(table.DexToPcSize(), dex2pc_mapping_table_.size() / 2);
-    MappingTable::PcToDexIterator it = table.PcToDexBegin();
-    for (uint32_t i = 0; i < pc2dex_mapping_table_.size(); ++i, ++it) {
-      CHECK_EQ(pc2dex_mapping_table_.at(i), it.NativePcOffset());
-      ++i;
-      CHECK_EQ(pc2dex_mapping_table_.at(i), it.DexPc());
+    auto it = table.PcToDexBegin();
+    auto it2 = table.DexToPcBegin();
+    for (LIR* tgt_lir = first_lir_insn_; tgt_lir != NULL; tgt_lir = NEXT_LIR(tgt_lir)) {
+      if (!tgt_lir->flags.is_nop && (tgt_lir->opcode == kPseudoSafepointPC)) {
+        CHECK_EQ(tgt_lir->offset, it.NativePcOffset());
+        CHECK_EQ(tgt_lir->dalvik_offset, it.DexPc());
+        ++it;
+      }
+      if (!tgt_lir->flags.is_nop && (tgt_lir->opcode == kPseudoExportedPC)) {
+        CHECK_EQ(tgt_lir->offset, it2.NativePcOffset());
+        CHECK_EQ(tgt_lir->dalvik_offset, it2.DexPc());
+        ++it2;
+      }
     }
-    MappingTable::DexToPcIterator it2 = table.DexToPcBegin();
-    for (uint32_t i = 0; i < dex2pc_mapping_table_.size(); ++i, ++it2) {
-      CHECK_EQ(dex2pc_mapping_table_.at(i), it2.NativePcOffset());
-      ++i;
-      CHECK_EQ(dex2pc_mapping_table_.at(i), it2.DexPc());
-    }
+    CHECK(it == table.PcToDexEnd());
+    CHECK(it2 == table.DexToPcEnd());
   }
 }
 
@@ -677,25 +736,27 @@
 };
 
 void Mir2Lir::CreateNativeGcMap() {
-  const std::vector<uint32_t>& mapping_table = pc2dex_mapping_table_;
+  DCHECK(!encoded_mapping_table_.empty());
+  MappingTable mapping_table(&encoded_mapping_table_[0]);
   uint32_t max_native_offset = 0;
-  for (size_t i = 0; i < mapping_table.size(); i += 2) {
-    uint32_t native_offset = mapping_table[i + 0];
+  for (auto it = mapping_table.PcToDexBegin(), end = mapping_table.PcToDexEnd(); it != end; ++it) {
+    uint32_t native_offset = it.NativePcOffset();
     if (native_offset > max_native_offset) {
       max_native_offset = native_offset;
     }
   }
   MethodReference method_ref(cu_->dex_file, cu_->method_idx);
   const std::vector<uint8_t>* gc_map_raw = verifier::MethodVerifier::GetDexGcMap(method_ref);
-  verifier::DexPcToReferenceMap dex_gc_map(&(*gc_map_raw)[4], gc_map_raw->size() - 4);
+  verifier::DexPcToReferenceMap dex_gc_map(&(*gc_map_raw)[0]);
+  DCHECK_EQ(gc_map_raw->size(), dex_gc_map.RawSize());
   // Compute native offset to references size.
   NativePcToReferenceMapBuilder native_gc_map_builder(&native_gc_map_,
-                                                      mapping_table.size() / 2, max_native_offset,
-                                                      dex_gc_map.RegWidth());
+                                                      mapping_table.PcToDexSize(),
+                                                      max_native_offset, dex_gc_map.RegWidth());
 
-  for (size_t i = 0; i < mapping_table.size(); i += 2) {
-    uint32_t native_offset = mapping_table[i + 0];
-    uint32_t dex_pc = mapping_table[i + 1];
+  for (auto it = mapping_table.PcToDexBegin(), end = mapping_table.PcToDexEnd(); it != end; ++it) {
+    uint32_t native_offset = it.NativePcOffset();
+    uint32_t dex_pc = it.DexPc();
     const uint8_t* references = dex_gc_map.FindBitMap(dex_pc, false);
     CHECK(references != NULL) << "Missing ref for dex pc 0x" << std::hex << dex_pc;
     native_gc_map_builder.AddEntry(native_offset, references);
@@ -986,15 +1047,15 @@
   for (uint32_t i = 0; i < fp_vmap_table_.size(); i++) {
     raw_vmap_table.push_back(fp_vmap_table_[i]);
   }
-  UnsignedLeb128EncodingVector vmap_encoder;
+  Leb128EncodingVector vmap_encoder;
   // Prefix the encoded data with its size.
-  vmap_encoder.PushBack(raw_vmap_table.size());
+  vmap_encoder.PushBackUnsigned(raw_vmap_table.size());
   for (uint16_t cur : raw_vmap_table) {
-    vmap_encoder.PushBack(cur);
+    vmap_encoder.PushBackUnsigned(cur);
   }
   CompiledMethod* result =
       new CompiledMethod(*cu_->compiler_driver, cu_->instruction_set, code_buffer_, frame_size_,
-                         core_spill_mask_, fp_spill_mask_, encoded_mapping_table_.GetData(),
+                         core_spill_mask_, fp_spill_mask_, encoded_mapping_table_,
                          vmap_encoder.GetData(), native_gc_map_);
   return result;
 }
diff --git a/compiler/dex/quick/dex_file_method_inliner.cc b/compiler/dex/quick/dex_file_method_inliner.cc
index 6c0328e..b21e37e 100644
--- a/compiler/dex/quick/dex_file_method_inliner.cc
+++ b/compiler/dex/quick/dex_file_method_inliner.cc
@@ -22,6 +22,7 @@
 
 namespace art {
 
+const uint32_t DexFileMethodInliner::kIndexUnresolved;
 const char* DexFileMethodInliner::kClassCacheNames[] = {
     "Z",                       // kClassCacheBoolean
     "B",                       // kClassCacheByte
@@ -157,8 +158,74 @@
         kClassCacheJavaLangObject } },
 };
 
-DexFileMethodInliner::~DexFileMethodInliner() {
-}
+const DexFileMethodInliner::IntrinsicDef DexFileMethodInliner::kIntrinsicMethods[] = {
+#define INTRINSIC(c, n, p, o, d) \
+    { { kClassCache ## c, kNameCache ## n, kProtoCache ## p }, { o, d } }
+
+    INTRINSIC(JavaLangDouble, DoubleToRawLongBits, D_J, kIntrinsicDoubleCvt, 0),
+    INTRINSIC(JavaLangDouble, LongBitsToDouble, J_D, kIntrinsicDoubleCvt, 0),
+    INTRINSIC(JavaLangFloat, FloatToRawIntBits, F_I, kIntrinsicFloatCvt, 0),
+    INTRINSIC(JavaLangFloat, IntBitsToFloat, I_F, kIntrinsicFloatCvt, 0),
+
+    INTRINSIC(JavaLangInteger, ReverseBytes, I_I, kIntrinsicReverseBytes, kWord),
+    INTRINSIC(JavaLangLong, ReverseBytes, J_J, kIntrinsicReverseBytes, kLong),
+    INTRINSIC(JavaLangShort, ReverseBytes, S_S, kIntrinsicReverseBytes, kSignedHalf),
+
+    INTRINSIC(JavaLangMath,       Abs, I_I, kIntrinsicAbsInt, 0),
+    INTRINSIC(JavaLangStrictMath, Abs, I_I, kIntrinsicAbsInt, 0),
+    INTRINSIC(JavaLangMath,       Abs, J_J, kIntrinsicAbsLong, 0),
+    INTRINSIC(JavaLangStrictMath, Abs, J_J, kIntrinsicAbsLong, 0),
+    INTRINSIC(JavaLangMath,       Min, II_I, kIntrinsicMinMaxInt, kIntrinsicFlagMin),
+    INTRINSIC(JavaLangStrictMath, Min, II_I, kIntrinsicMinMaxInt, kIntrinsicFlagMin),
+    INTRINSIC(JavaLangMath,       Max, II_I, kIntrinsicMinMaxInt, kIntrinsicFlagMax),
+    INTRINSIC(JavaLangStrictMath, Max, II_I, kIntrinsicMinMaxInt, kIntrinsicFlagMax),
+    INTRINSIC(JavaLangMath,       Sqrt, D_D, kIntrinsicSqrt, 0),
+    INTRINSIC(JavaLangStrictMath, Sqrt, D_D, kIntrinsicSqrt, 0),
+
+    INTRINSIC(JavaLangString, CharAt, I_C, kIntrinsicCharAt, 0),
+    INTRINSIC(JavaLangString, CompareTo, String_I, kIntrinsicCompareTo, 0),
+    INTRINSIC(JavaLangString, IsEmpty, _Z, kIntrinsicIsEmptyOrLength, kIntrinsicFlagIsEmpty),
+    INTRINSIC(JavaLangString, IndexOf, II_I, kIntrinsicIndexOf, kIntrinsicFlagNone),
+    INTRINSIC(JavaLangString, IndexOf, I_I, kIntrinsicIndexOf, kIntrinsicFlagBase0),
+    INTRINSIC(JavaLangString, Length, _I, kIntrinsicIsEmptyOrLength, kIntrinsicFlagLength),
+
+    INTRINSIC(JavaLangThread, CurrentThread, _Thread, kIntrinsicCurrentThread, 0),
+
+    INTRINSIC(LibcoreIoMemory, PeekByte, J_B, kIntrinsicPeek, kSignedByte),
+    INTRINSIC(LibcoreIoMemory, PeekIntNative, J_I, kIntrinsicPeek, kWord),
+    INTRINSIC(LibcoreIoMemory, PeekLongNative, J_J, kIntrinsicPeek, kLong),
+    INTRINSIC(LibcoreIoMemory, PeekShortNative, J_S, kIntrinsicPeek, kSignedHalf),
+    INTRINSIC(LibcoreIoMemory, PokeByte, JB_V, kIntrinsicPoke, kSignedByte),
+    INTRINSIC(LibcoreIoMemory, PokeIntNative, JI_V, kIntrinsicPoke, kWord),
+    INTRINSIC(LibcoreIoMemory, PokeLongNative, JJ_V, kIntrinsicPoke, kLong),
+    INTRINSIC(LibcoreIoMemory, PokeShortNative, JS_V, kIntrinsicPoke, kSignedHalf),
+
+    INTRINSIC(SunMiscUnsafe, CompareAndSwapInt, ObjectJII_Z, kIntrinsicCas,
+              kIntrinsicFlagNone),
+    INTRINSIC(SunMiscUnsafe, CompareAndSwapLong, ObjectJJJ_Z, kIntrinsicCas,
+              kIntrinsicFlagIsLong),
+    INTRINSIC(SunMiscUnsafe, CompareAndSwapObject, ObjectJObjectObject_Z, kIntrinsicCas,
+              kIntrinsicFlagIsObject),
+
+#define UNSAFE_GET_PUT(type, code, type_flags) \
+    INTRINSIC(SunMiscUnsafe, Get ## type, ObjectJ_ ## code, kIntrinsicUnsafeGet, \
+              type_flags & ~kIntrinsicFlagIsObject), \
+    INTRINSIC(SunMiscUnsafe, Get ## type ## Volatile, ObjectJ_ ## code, kIntrinsicUnsafeGet, \
+              (type_flags | kIntrinsicFlagIsVolatile) & ~kIntrinsicFlagIsObject), \
+    INTRINSIC(SunMiscUnsafe, Put ## type, ObjectJ ## code ## _V, kIntrinsicUnsafePut, \
+              type_flags), \
+    INTRINSIC(SunMiscUnsafe, Put ## type ## Volatile, ObjectJ ## code ## _V, kIntrinsicUnsafePut, \
+              type_flags | kIntrinsicFlagIsVolatile), \
+    INTRINSIC(SunMiscUnsafe, PutOrdered ## type, ObjectJ ## code ## _V, kIntrinsicUnsafePut, \
+              type_flags | kIntrinsicFlagIsOrdered)
+
+    UNSAFE_GET_PUT(Int, I, kIntrinsicFlagNone),
+    UNSAFE_GET_PUT(Long, J, kIntrinsicFlagIsLong),
+    UNSAFE_GET_PUT(Object, Object, kIntrinsicFlagIsObject),
+#undef UNSAFE_GET_PUT
+
+#undef INTRINSIC
+};
 
 DexFileMethodInliner::DexFileMethodInliner()
     : dex_file_(NULL) {
@@ -170,6 +237,9 @@
   COMPILE_ASSERT(arraysize(kProtoCacheDefs) == kProtoCacheLast, bad_arraysize_kProtoCacheNames);
 }
 
+DexFileMethodInliner::~DexFileMethodInliner() {
+}
+
 bool DexFileMethodInliner::IsIntrinsic(uint32_t method_index) const {
   return intrinsics_.find(method_index) != intrinsics_.end();
 }
@@ -333,15 +403,15 @@
   std::fill_n(proto_indexes, arraysize(proto_indexes), kIndexUnresolved);
 }
 
-void DexFileMethodInliner::DoFindIntrinsics(const DexFile* dex_file, IndexCache* cache,
-                                            const IntrinsicDef* defs, uint32_t def_count) {
+void DexFileMethodInliner::FindIntrinsics(const DexFile* dex_file) {
   DCHECK(dex_file != nullptr);
   DCHECK(dex_file_ == nullptr);
-  for (uint32_t i = 0u; i != def_count; ++i) {
-    uint32_t method_id = FindMethodIndex(dex_file, cache, defs[i].method_def);
+  IndexCache cache;
+  for (const IntrinsicDef& def : kIntrinsicMethods) {
+    uint32_t method_id = FindMethodIndex(dex_file, &cache, def.method_def);
     if (method_id != kIndexNotFound) {
       DCHECK(intrinsics_.find(method_id) == intrinsics_.end());
-      intrinsics_[method_id] = defs[i].intrinsic;
+      intrinsics_[method_id] = def.intrinsic;
     }
   }
   dex_file_ = dex_file;
diff --git a/compiler/dex/quick/dex_file_method_inliner.h b/compiler/dex/quick/dex_file_method_inliner.h
index bc00513..948f4bb 100644
--- a/compiler/dex/quick/dex_file_method_inliner.h
+++ b/compiler/dex/quick/dex_file_method_inliner.h
@@ -89,12 +89,8 @@
  */
 class DexFileMethodInliner {
   public:
-    virtual ~DexFileMethodInliner();
-
-    /**
-     * Find all known intrinsic methods in the dex_file and cache their indices.
-     */
-    virtual void FindIntrinsics(const DexFile* dex_file) = 0;
+    DexFileMethodInliner();
+    ~DexFileMethodInliner();
 
     /**
      * Check whether a particular method index corresponds to an intrinsic function.
@@ -103,15 +99,10 @@
 
     /**
      * Generate code for an intrinsic function invocation.
-     *
-     * TODO: This should be target-specific. For the time being,
-     * it's shared since it dispatches everything to backend.
      */
     bool GenIntrinsic(Mir2Lir* backend, CallInfo* info) const;
 
-  protected:
-    DexFileMethodInliner();
-
+  private:
     /**
      * To avoid multiple lookups of a class by its descriptor, we cache its
      * type index in the IndexCache. These are the indexes into the IndexCache
@@ -290,6 +281,7 @@
     static const char* kClassCacheNames[];
     static const char* kNameCacheNames[];
     static const ProtoDef kProtoCacheDefs[];
+    static const IntrinsicDef kIntrinsicMethods[];
 
     static const uint32_t kIndexNotFound = static_cast<uint32_t>(-1);
     static const uint32_t kIndexUnresolved = static_cast<uint32_t>(-2);
@@ -303,14 +295,22 @@
     static uint32_t FindMethodIndex(const DexFile* dex_file, IndexCache* cache,
                                     const MethodDef& method_def);
 
-    void DoFindIntrinsics(const DexFile* dex_file, IndexCache* cache,
-                          const IntrinsicDef* defs, uint32_t def_count);
+    /**
+     * Find all known intrinsic methods in the dex_file and cache their indices.
+     *
+     * Only DexFileToMethodInlinerMap may call this function to initialize the inliner.
+     */
+    void FindIntrinsics(const DexFile* dex_file);
+
+    friend class DexFileToMethodInlinerMap;
 
     /*
      * Maps method indexes (for the particular DexFile) to Intrinsic defintions.
      */
     std::map<uint32_t, Intrinsic> intrinsics_;
     const DexFile* dex_file_;
+
+    DISALLOW_COPY_AND_ASSIGN(DexFileMethodInliner);
 };
 
 }  // namespace art
diff --git a/compiler/dex/quick/dex_file_to_method_inliner_map.cc b/compiler/dex/quick/dex_file_to_method_inliner_map.cc
index 56a42bc..0107ed3 100644
--- a/compiler/dex/quick/dex_file_to_method_inliner_map.cc
+++ b/compiler/dex/quick/dex_file_to_method_inliner_map.cc
@@ -22,17 +22,13 @@
 #include "base/mutex-inl.h"
 #include "base/logging.h"
 #include "driver/compiler_driver.h"
-#include "dex/quick/arm/arm_dex_file_method_inliner.h"
-#include "dex/quick/mips/mips_dex_file_method_inliner.h"
-#include "dex/quick/x86/x86_dex_file_method_inliner.h"
 
 #include "dex_file_to_method_inliner_map.h"
 
 namespace art {
 
-DexFileToMethodInlinerMap::DexFileToMethodInlinerMap(const CompilerDriver* compiler)
-    : compiler_(compiler),
-      mutex_("inline_helper_mutex") {
+DexFileToMethodInlinerMap::DexFileToMethodInlinerMap()
+    : lock_("inline_helper_mutex") {
 }
 
 DexFileToMethodInlinerMap::~DexFileToMethodInlinerMap() {
@@ -44,31 +40,19 @@
 const DexFileMethodInliner& DexFileToMethodInlinerMap::GetMethodInliner(const DexFile* dex_file) {
   Thread* self = Thread::Current();
   {
-    ReaderMutexLock lock(self, mutex_);
+    ReaderMutexLock lock(self, lock_);
     auto it = inliners_.find(dex_file);
     if (it != inliners_.end()) {
       return *it->second;
     }
   }
 
-  WriterMutexLock lock(self, mutex_);
+  WriterMutexLock lock(self, lock_);
   DexFileMethodInliner** inliner = &inliners_[dex_file];  // inserts new entry if not found
   if (*inliner) {
     return **inliner;
   }
-  switch (compiler_->GetInstructionSet()) {
-    case kThumb2:
-      *inliner = new ArmDexFileMethodInliner;
-      break;
-    case kX86:
-      *inliner = new X86DexFileMethodInliner;
-      break;
-    case kMips:
-      *inliner = new MipsDexFileMethodInliner;
-      break;
-    default:
-      LOG(FATAL) << "Unexpected instruction set: " << compiler_->GetInstructionSet();
-  }
+  *inliner = new DexFileMethodInliner();
   DCHECK(*inliner != nullptr);
   // TODO: per-dex file locking for the intrinsics container filling.
   (*inliner)->FindIntrinsics(dex_file);
diff --git a/compiler/dex/quick/dex_file_to_method_inliner_map.h b/compiler/dex/quick/dex_file_to_method_inliner_map.h
index 77f2648..476f002 100644
--- a/compiler/dex/quick/dex_file_to_method_inliner_map.h
+++ b/compiler/dex/quick/dex_file_to_method_inliner_map.h
@@ -37,15 +37,16 @@
  */
 class DexFileToMethodInlinerMap {
   public:
-    explicit DexFileToMethodInlinerMap(const CompilerDriver* compiler);
+    DexFileToMethodInlinerMap();
     ~DexFileToMethodInlinerMap();
 
-    const DexFileMethodInliner& GetMethodInliner(const DexFile* dex_file) LOCKS_EXCLUDED(mutex_);
+    const DexFileMethodInliner& GetMethodInliner(const DexFile* dex_file) LOCKS_EXCLUDED(lock_);
 
   private:
-    const CompilerDriver* const compiler_;
-    ReaderWriterMutex mutex_;
-    std::map<const DexFile*, DexFileMethodInliner*> inliners_ GUARDED_BY(mutex_);
+    ReaderWriterMutex lock_;
+    std::map<const DexFile*, DexFileMethodInliner*> inliners_ GUARDED_BY(lock_);
+
+    DISALLOW_COPY_AND_ASSIGN(DexFileToMethodInlinerMap);
 };
 
 }  // namespace art
diff --git a/compiler/dex/quick/gen_common.cc b/compiler/dex/quick/gen_common.cc
index df6493d..a426cc7 100644
--- a/compiler/dex/quick/gen_common.cc
+++ b/compiler/dex/quick/gen_common.cc
@@ -611,7 +611,7 @@
       default:
         LOG(FATAL) << "Unexpected throw kind: " << lab->operands[0];
     }
-    ClobberCalleeSave();
+    ClobberCallerSave();
     int r_tgt = CallHelperSetup(func_offset);
     CallHelper(r_tgt, func_offset, true /* MarkSafepointPC */);
   }
@@ -1026,7 +1026,7 @@
     }
   }
   // TODO: only clobber when type isn't final?
-  ClobberCalleeSave();
+  ClobberCallerSave();
   /* branch targets here */
   LIR* target = NewLIR0(kPseudoTargetLabel);
   StoreValue(rl_dest, rl_result);
diff --git a/compiler/dex/quick/gen_invoke.cc b/compiler/dex/quick/gen_invoke.cc
index 469c577..e66d4ea 100644
--- a/compiler/dex/quick/gen_invoke.cc
+++ b/compiler/dex/quick/gen_invoke.cc
@@ -62,14 +62,14 @@
 void Mir2Lir::CallRuntimeHelperImm(ThreadOffset helper_offset, int arg0, bool safepoint_pc) {
   int r_tgt = CallHelperSetup(helper_offset);
   LoadConstant(TargetReg(kArg0), arg0);
-  ClobberCalleeSave();
+  ClobberCallerSave();
   CallHelper(r_tgt, helper_offset, safepoint_pc);
 }
 
 void Mir2Lir::CallRuntimeHelperReg(ThreadOffset helper_offset, int arg0, bool safepoint_pc) {
   int r_tgt = CallHelperSetup(helper_offset);
   OpRegCopy(TargetReg(kArg0), arg0);
-  ClobberCalleeSave();
+  ClobberCallerSave();
   CallHelper(r_tgt, helper_offset, safepoint_pc);
 }
 
@@ -81,7 +81,7 @@
   } else {
     LoadValueDirectWideFixed(arg0, TargetReg(kArg0), TargetReg(kArg1));
   }
-  ClobberCalleeSave();
+  ClobberCallerSave();
   CallHelper(r_tgt, helper_offset, safepoint_pc);
 }
 
@@ -90,7 +90,7 @@
   int r_tgt = CallHelperSetup(helper_offset);
   LoadConstant(TargetReg(kArg0), arg0);
   LoadConstant(TargetReg(kArg1), arg1);
-  ClobberCalleeSave();
+  ClobberCallerSave();
   CallHelper(r_tgt, helper_offset, safepoint_pc);
 }
 
@@ -103,7 +103,7 @@
     LoadValueDirectWideFixed(arg1, TargetReg(kArg1), TargetReg(kArg2));
   }
   LoadConstant(TargetReg(kArg0), arg0);
-  ClobberCalleeSave();
+  ClobberCallerSave();
   CallHelper(r_tgt, helper_offset, safepoint_pc);
 }
 
@@ -112,7 +112,7 @@
   int r_tgt = CallHelperSetup(helper_offset);
   LoadValueDirectFixed(arg0, TargetReg(kArg0));
   LoadConstant(TargetReg(kArg1), arg1);
-  ClobberCalleeSave();
+  ClobberCallerSave();
   CallHelper(r_tgt, helper_offset, safepoint_pc);
 }
 
@@ -121,7 +121,7 @@
   int r_tgt = CallHelperSetup(helper_offset);
   OpRegCopy(TargetReg(kArg1), arg1);
   LoadConstant(TargetReg(kArg0), arg0);
-  ClobberCalleeSave();
+  ClobberCallerSave();
   CallHelper(r_tgt, helper_offset, safepoint_pc);
 }
 
@@ -130,7 +130,7 @@
   int r_tgt = CallHelperSetup(helper_offset);
   OpRegCopy(TargetReg(kArg0), arg0);
   LoadConstant(TargetReg(kArg1), arg1);
-  ClobberCalleeSave();
+  ClobberCallerSave();
   CallHelper(r_tgt, helper_offset, safepoint_pc);
 }
 
@@ -138,7 +138,7 @@
   int r_tgt = CallHelperSetup(helper_offset);
   LoadCurrMethodDirect(TargetReg(kArg1));
   LoadConstant(TargetReg(kArg0), arg0);
-  ClobberCalleeSave();
+  ClobberCallerSave();
   CallHelper(r_tgt, helper_offset, safepoint_pc);
 }
 
@@ -168,7 +168,7 @@
       LoadValueDirectWideFixed(arg1, arg1.fp ? TargetReg(kFArg2) : TargetReg(kArg2), arg1.fp ? TargetReg(kFArg3) : TargetReg(kArg3));
     }
   }
-  ClobberCalleeSave();
+  ClobberCallerSave();
   CallHelper(r_tgt, helper_offset, safepoint_pc);
 }
 
@@ -178,7 +178,7 @@
   DCHECK_NE(TargetReg(kArg0), arg1);  // check copy into arg0 won't clobber arg1
   OpRegCopy(TargetReg(kArg0), arg0);
   OpRegCopy(TargetReg(kArg1), arg1);
-  ClobberCalleeSave();
+  ClobberCallerSave();
   CallHelper(r_tgt, helper_offset, safepoint_pc);
 }
 
@@ -189,7 +189,7 @@
   OpRegCopy(TargetReg(kArg0), arg0);
   OpRegCopy(TargetReg(kArg1), arg1);
   LoadConstant(TargetReg(kArg2), arg2);
-  ClobberCalleeSave();
+  ClobberCallerSave();
   CallHelper(r_tgt, helper_offset, safepoint_pc);
 }
 
@@ -199,7 +199,7 @@
   LoadValueDirectFixed(arg2, TargetReg(kArg2));
   LoadCurrMethodDirect(TargetReg(kArg1));
   LoadConstant(TargetReg(kArg0), arg0);
-  ClobberCalleeSave();
+  ClobberCallerSave();
   CallHelper(r_tgt, helper_offset, safepoint_pc);
 }
 
@@ -209,7 +209,7 @@
   LoadCurrMethodDirect(TargetReg(kArg1));
   LoadConstant(TargetReg(kArg2), arg2);
   LoadConstant(TargetReg(kArg0), arg0);
-  ClobberCalleeSave();
+  ClobberCallerSave();
   CallHelper(r_tgt, helper_offset, safepoint_pc);
 }
 
@@ -225,7 +225,7 @@
     LoadValueDirectWideFixed(arg2, TargetReg(kArg2), TargetReg(kArg3));
   }
   LoadConstant(TargetReg(kArg0), arg0);
-  ClobberCalleeSave();
+  ClobberCallerSave();
   CallHelper(r_tgt, helper_offset, safepoint_pc);
 }
 
@@ -240,7 +240,7 @@
   LoadValueDirectFixed(arg1, TargetReg(kArg1));
   DCHECK_EQ(arg1.wide, 0U);
   LoadValueDirectFixed(arg2, TargetReg(kArg2));
-  ClobberCalleeSave();
+  ClobberCallerSave();
   CallHelper(r_tgt, helper_offset, safepoint_pc);
 }
 
@@ -971,10 +971,17 @@
   RegLocation rl_result = EvalLoc(rl_dest, kCoreReg, true);
   if (size == kLong) {
     RegLocation rl_i = LoadValueWide(rl_src_i, kCoreReg);
-    int reg_tmp = AllocTemp();
-    OpRegCopy(reg_tmp, rl_result.low_reg);
+    int r_i_low = rl_i.low_reg;
+    if (rl_i.low_reg == rl_result.low_reg) {
+      // First REV shall clobber rl_result.low_reg, save the value in a temp for the second REV.
+      r_i_low = AllocTemp();
+      OpRegCopy(r_i_low, rl_i.low_reg);
+    }
     OpRegReg(kOpRev, rl_result.low_reg, rl_i.high_reg);
-    OpRegReg(kOpRev, rl_result.high_reg, reg_tmp);
+    OpRegReg(kOpRev, rl_result.high_reg, r_i_low);
+    if (rl_i.low_reg == rl_result.low_reg) {
+      FreeTemp(r_i_low);
+    }
     StoreValueWide(rl_dest, rl_result);
   } else {
     DCHECK(size == kWord || size == kSignedHalf);
@@ -1076,7 +1083,7 @@
     // TODO - add Mips implementation
     return false;
   }
-  ClobberCalleeSave();
+  ClobberCallerSave();
   LockCallTemps();  // Using fixed registers
   int reg_ptr = TargetReg(kArg0);
   int reg_char = TargetReg(kArg1);
@@ -1119,7 +1126,7 @@
     // TODO - add Mips implementation
     return false;
   }
-  ClobberCalleeSave();
+  ClobberCallerSave();
   LockCallTemps();  // Using fixed registers
   int reg_this = TargetReg(kArg0);
   int reg_cmp = TargetReg(kArg1);
@@ -1334,7 +1341,7 @@
   }
   MarkSafepointPC(call_inst);
 
-  ClobberCalleeSave();
+  ClobberCallerSave();
   if (info->result.location != kLocInvalid) {
     // We have a following MOVE_RESULT - do it now.
     if (info->result.wide) {
diff --git a/compiler/dex/quick/mips/call_mips.cc b/compiler/dex/quick/mips/call_mips.cc
index 18c8cf8..21d5563 100644
--- a/compiler/dex/quick/mips/call_mips.cc
+++ b/compiler/dex/quick/mips/call_mips.cc
@@ -253,7 +253,7 @@
   NewLIR4(kMipsDelta, rMIPS_ARG1, 0, WrapPointer(base_label), WrapPointer(tab_rec));
 
   // And go...
-  ClobberCalleeSave();
+  ClobberCallerSave();
   LIR* call_inst = OpReg(kOpBlx, r_tgt);  // ( array*, fill_data* )
   MarkSafepointPC(call_inst);
 }
diff --git a/compiler/dex/quick/mips/codegen_mips.h b/compiler/dex/quick/mips/codegen_mips.h
index 5dda445..450a44f 100644
--- a/compiler/dex/quick/mips/codegen_mips.h
+++ b/compiler/dex/quick/mips/codegen_mips.h
@@ -61,7 +61,7 @@
     uint32_t FpRegMask();
     uint64_t GetRegMaskCommon(int reg);
     void AdjustSpillMask();
-    void ClobberCalleeSave();
+    void ClobberCallerSave();
     void FlushReg(int reg);
     void FlushRegWide(int reg1, int reg2);
     void FreeCallTemps();
diff --git a/compiler/dex/quick/mips/mips_dex_file_method_inliner.cc b/compiler/dex/quick/mips/mips_dex_file_method_inliner.cc
deleted file mode 100644
index 05d8ac8..0000000
--- a/compiler/dex/quick/mips/mips_dex_file_method_inliner.cc
+++ /dev/null
@@ -1,105 +0,0 @@
-/*
- * Copyright (C) 2013 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 "base/logging.h"
-#include "base/macros.h"
-#include "dex/compiler_enums.h"
-
-#include "mips_dex_file_method_inliner.h"
-
-namespace art {
-
-const DexFileMethodInliner::IntrinsicDef MipsDexFileMethodInliner::kIntrinsicMethods[] = {
-#define INTRINSIC(c, n, p, o, d) \
-    { { kClassCache ## c, kNameCache ## n, kProtoCache ## p }, { o, d } }
-
-    // INTRINSIC(JavaLangDouble, DoubleToRawLongBits, D_J, kIntrinsicDoubleCvt, 0),
-    // INTRINSIC(JavaLangDouble, LongBitsToDouble, J_D, kIntrinsicDoubleCvt, 0),
-    // INTRINSIC(JavaLangFloat, FloatToRawIntBits, F_I, kIntrinsicFloatCvt, 0),
-    // INTRINSIC(JavaLangFloat, IntBitsToFloat, I_F, kIntrinsicFloatCvt, 0),
-
-    // INTRINSIC(JavaLangInteger, ReverseBytes, I_I, kIntrinsicReverseBytes, kWord),
-    // INTRINSIC(JavaLangLong, ReverseBytes, J_J, kIntrinsicReverseBytes, kLong),
-    // INTRINSIC(JavaLangShort, ReverseBytes, S_S, kIntrinsicReverseBytes, kSignedHalf),
-
-    // INTRINSIC(JavaLangMath,       Abs, I_I, kIntrinsicAbsInt, 0),
-    // INTRINSIC(JavaLangStrictMath, Abs, I_I, kIntrinsicAbsInt, 0),
-    // INTRINSIC(JavaLangMath,       Abs, J_J, kIntrinsicAbsLong, 0),
-    // INTRINSIC(JavaLangStrictMath, Abs, J_J, kIntrinsicAbsLong, 0),
-    // INTRINSIC(JavaLangMath,       Min, II_I, kIntrinsicMinMaxInt, kIntrinsicFlagMin),
-    // INTRINSIC(JavaLangStrictMath, Min, II_I, kIntrinsicMinMaxInt, kIntrinsicFlagMin),
-    // INTRINSIC(JavaLangMath,       Max, II_I, kIntrinsicMinMaxInt, kIntrinsicFlagMax),
-    // INTRINSIC(JavaLangStrictMath, Max, II_I, kIntrinsicMinMaxInt, kIntrinsicFlagMax),
-    // INTRINSIC(JavaLangMath,       Sqrt, D_D, kIntrinsicSqrt, 0),
-    // INTRINSIC(JavaLangStrictMath, Sqrt, D_D, kIntrinsicSqrt, 0),
-
-    // INTRINSIC(JavaLangString, CharAt, I_C, kIntrinsicCharAt, 0),
-    // INTRINSIC(JavaLangString, CompareTo, String_I, kIntrinsicCompareTo, 0),
-    // INTRINSIC(JavaLangString, IsEmpty, _Z, kIntrinsicIsEmptyOrLength, kIntrinsicFlagIsEmpty),
-    // INTRINSIC(JavaLangString, IndexOf, II_I, kIntrinsicIndexOf, kIntrinsicFlagNone),
-    // INTRINSIC(JavaLangString, IndexOf, I_I, kIntrinsicIndexOf, kIntrinsicFlagBase0),
-    // INTRINSIC(JavaLangString, Length, _I, kIntrinsicIsEmptyOrLength, kIntrinsicFlagLength),
-
-    INTRINSIC(JavaLangThread, CurrentThread, _Thread, kIntrinsicCurrentThread, 0),
-
-    INTRINSIC(LibcoreIoMemory, PeekByte, J_B, kIntrinsicPeek, kSignedByte),
-    // INTRINSIC(LibcoreIoMemory, PeekIntNative, J_I, kIntrinsicPeek, kWord),
-    // INTRINSIC(LibcoreIoMemory, PeekLongNative, J_J, kIntrinsicPeek, kLong),
-    // INTRINSIC(LibcoreIoMemory, PeekShortNative, J_S, kIntrinsicPeek, kSignedHalf),
-    INTRINSIC(LibcoreIoMemory, PokeByte, JB_V, kIntrinsicPoke, kSignedByte),
-    // INTRINSIC(LibcoreIoMemory, PokeIntNative, JI_V, kIntrinsicPoke, kWord),
-    // INTRINSIC(LibcoreIoMemory, PokeLongNative, JJ_V, kIntrinsicPoke, kLong),
-    // INTRINSIC(LibcoreIoMemory, PokeShortNative, JS_V, kIntrinsicPoke, kSignedHalf),
-
-    // INTRINSIC(SunMiscUnsafe, CompareAndSwapInt, ObjectJII_Z, kIntrinsicCas,
-    //           kIntrinsicFlagNone),
-    // INTRINSIC(SunMiscUnsafe, CompareAndSwapLong, ObjectJJJ_Z, kIntrinsicCas,
-    //           kIntrinsicFlagIsLong),
-    // INTRINSIC(SunMiscUnsafe, CompareAndSwapObject, ObjectJObjectObject_Z, kIntrinsicCas,
-    //           kIntrinsicFlagIsObject),
-
-#define UNSAFE_GET_PUT(type, code, type_flags) \
-    INTRINSIC(SunMiscUnsafe, Get ## type, ObjectJ_ ## code, kIntrinsicUnsafeGet, \
-              type_flags & ~kIntrinsicFlagIsObject), \
-    INTRINSIC(SunMiscUnsafe, Get ## type ## Volatile, ObjectJ_ ## code, kIntrinsicUnsafeGet, \
-              (type_flags | kIntrinsicFlagIsVolatile) & ~kIntrinsicFlagIsObject), \
-    INTRINSIC(SunMiscUnsafe, Put ## type, ObjectJ ## code ## _V, kIntrinsicUnsafePut, \
-              type_flags), \
-    INTRINSIC(SunMiscUnsafe, Put ## type ## Volatile, ObjectJ ## code ## _V, kIntrinsicUnsafePut, \
-              type_flags | kIntrinsicFlagIsVolatile), \
-    INTRINSIC(SunMiscUnsafe, PutOrdered ## type, ObjectJ ## code ## _V, kIntrinsicUnsafePut, \
-              type_flags | kIntrinsicFlagIsOrdered)
-
-    // UNSAFE_GET_PUT(Int, I, kIntrinsicFlagNone),
-    // UNSAFE_GET_PUT(Long, J, kIntrinsicFlagIsLong),
-    // UNSAFE_GET_PUT(Object, Object, kIntrinsicFlagIsObject),
-#undef UNSAFE_GET_PUT
-
-#undef INTRINSIC
-};
-
-MipsDexFileMethodInliner::MipsDexFileMethodInliner() {
-}
-
-MipsDexFileMethodInliner::~MipsDexFileMethodInliner() {
-}
-
-void MipsDexFileMethodInliner::FindIntrinsics(const DexFile* dex_file) {
-  IndexCache cache;
-  DoFindIntrinsics(dex_file, &cache, kIntrinsicMethods, arraysize(kIntrinsicMethods));
-}
-
-}  // namespace art
diff --git a/compiler/dex/quick/mips/mips_dex_file_method_inliner.h b/compiler/dex/quick/mips/mips_dex_file_method_inliner.h
deleted file mode 100644
index 8fe7ec7..0000000
--- a/compiler/dex/quick/mips/mips_dex_file_method_inliner.h
+++ /dev/null
@@ -1,37 +0,0 @@
-/*
- * Copyright (C) 2013 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_DEX_QUICK_MIPS_MIPS_DEX_FILE_METHOD_INLINER_H_
-#define ART_COMPILER_DEX_QUICK_MIPS_MIPS_DEX_FILE_METHOD_INLINER_H_
-
-#include "dex/quick/dex_file_method_inliner.h"
-
-namespace art {
-
-class MipsDexFileMethodInliner : public DexFileMethodInliner {
-  public:
-    MipsDexFileMethodInliner();
-    ~MipsDexFileMethodInliner();
-
-    void FindIntrinsics(const DexFile* dex_file);
-
-  private:
-    static const IntrinsicDef kIntrinsicMethods[];
-};
-
-}  // namespace art
-
-#endif  // ART_COMPILER_DEX_QUICK_MIPS_MIPS_DEX_FILE_METHOD_INLINER_H_
diff --git a/compiler/dex/quick/mips/target_mips.cc b/compiler/dex/quick/mips/target_mips.cc
index 9c598e6..869706f 100644
--- a/compiler/dex/quick/mips/target_mips.cc
+++ b/compiler/dex/quick/mips/target_mips.cc
@@ -346,7 +346,7 @@
 }
 
 /* Clobber all regs that might be used by an external C call */
-void MipsMir2Lir::ClobberCalleeSave() {
+void MipsMir2Lir::ClobberCallerSave() {
   Clobber(r_ZERO);
   Clobber(r_AT);
   Clobber(r_V0);
diff --git a/compiler/dex/quick/mips/utility_mips.cc b/compiler/dex/quick/mips/utility_mips.cc
index 2ba2c84..65c82c0 100644
--- a/compiler/dex/quick/mips/utility_mips.cc
+++ b/compiler/dex/quick/mips/utility_mips.cc
@@ -504,13 +504,13 @@
     }
   } else {
     if (pair) {
-      int r_tmp = AllocFreeTemp();
+      int r_tmp = AllocTemp();
       res = OpRegRegImm(kOpAdd, r_tmp, rBase, displacement);
       load = NewLIR3(opcode, r_dest, LOWORD_OFFSET, r_tmp);
       load2 = NewLIR3(opcode, r_dest_hi, HIWORD_OFFSET, r_tmp);
       FreeTemp(r_tmp);
     } else {
-      int r_tmp = (rBase == r_dest) ? AllocFreeTemp() : r_dest;
+      int r_tmp = (rBase == r_dest) ? AllocTemp() : r_dest;
       res = OpRegRegImm(kOpAdd, r_tmp, rBase, displacement);
       load = NewLIR3(opcode, r_dest, 0, r_tmp);
       if (r_tmp != r_dest)
diff --git a/compiler/dex/quick/mir_to_lir.h b/compiler/dex/quick/mir_to_lir.h
index f8a2d03..2a54eb3 100644
--- a/compiler/dex/quick/mir_to_lir.h
+++ b/compiler/dex/quick/mir_to_lir.h
@@ -71,6 +71,7 @@
 #define REG_USEA             (1ULL << kRegUseA)
 #define REG_USEC             (1ULL << kRegUseC)
 #define REG_USED             (1ULL << kRegUseD)
+#define REG_USEB             (1ULL << kRegUseB)
 #define REG_USE_FPCS_LIST0   (1ULL << kRegUseFPCSList0)
 #define REG_USE_FPCS_LIST2   (1ULL << kRegUseFPCSList2)
 #define REG_USE_LIST0        (1ULL << kRegUseList0)
@@ -341,9 +342,6 @@
     bool EvaluateBranch(Instruction::Code opcode, int src1, int src2);
     bool IsInexpensiveConstant(RegLocation rl_src);
     ConditionCode FlipComparisonOrder(ConditionCode before);
-    void DumpMappingTable(const char* table_name, const char* descriptor,
-                          const char* name, const Signature& signature,
-                          const std::vector<uint32_t>& v);
     void InstallLiteralPools();
     void InstallSwitchTables();
     void InstallFillArrayData();
@@ -624,7 +622,7 @@
     virtual uint32_t FpRegMask() = 0;
     virtual uint64_t GetRegMaskCommon(int reg) = 0;
     virtual void AdjustSpillMask() = 0;
-    virtual void ClobberCalleeSave() = 0;
+    virtual void ClobberCallerSave() = 0;
     virtual void FlushReg(int reg) = 0;
     virtual void FlushRegWide(int reg1, int reg2) = 0;
     virtual void FreeCallTemps() = 0;
@@ -792,17 +790,6 @@
     GrowableArray<RegisterInfo*> tempreg_info_;
     GrowableArray<RegisterInfo*> reginfo_map_;
     GrowableArray<void*> pointer_storage_;
-    /*
-     * Holds mapping from native PC to dex PC for safepoints where we may deoptimize.
-     * Native PC is on the return address of the safepointed operation.  Dex PC is for
-     * the instruction being executed at the safepoint.
-     */
-    std::vector<uint32_t> pc2dex_mapping_table_;
-    /*
-     * Holds mapping from Dex PC to native PC for catch entry points.  Native PC and Dex PC
-     * immediately preceed the instruction.
-     */
-    std::vector<uint32_t> dex2pc_mapping_table_;
     CodeOffset current_code_offset_;    // Working byte offset of machine instructons.
     CodeOffset data_offset_;            // starting offset of literal pool.
     size_t total_size_;                   // header + code size.
@@ -828,7 +815,7 @@
     int live_sreg_;
     CodeBuffer code_buffer_;
     // The encoding mapping table data (dex -> pc offset and pc offset -> dex) with a size prefix.
-    UnsignedLeb128EncodingVector encoded_mapping_table_;
+    std::vector<uint8_t> encoded_mapping_table_;
     std::vector<uint32_t> core_vmap_table_;
     std::vector<uint32_t> fp_vmap_table_;
     std::vector<uint8_t> native_gc_map_;
diff --git a/compiler/dex/quick/ralloc_util.cc b/compiler/dex/quick/ralloc_util.cc
index 41a57af..cef013e 100644
--- a/compiler/dex/quick/ralloc_util.cc
+++ b/compiler/dex/quick/ralloc_util.cc
@@ -338,7 +338,7 @@
 int Mir2Lir::AllocFreeTemp() {
   return AllocTempBody(reg_pool_->core_regs,
              reg_pool_->num_core_regs,
-             &reg_pool_->next_core_reg, true);
+             &reg_pool_->next_core_reg, false);
 }
 
 int Mir2Lir::AllocTemp() {
diff --git a/compiler/dex/quick/x86/assemble_x86.cc b/compiler/dex/quick/x86/assemble_x86.cc
index 191c9c7..96dc6ee 100644
--- a/compiler/dex/quick/x86/assemble_x86.cc
+++ b/compiler/dex/quick/x86/assemble_x86.cc
@@ -246,7 +246,9 @@
   UNARY_ENCODING_MAP(Idivmod, 0x7, 0, SETS_CCODES, DaR, kRegRegReg, IS_UNARY_OP | REG_USE0, DaM, kRegRegMem, IS_BINARY_OP | REG_USE0, DaA, kRegRegArray, IS_QUAD_OP | REG_USE01, 0, REG_DEFA_USEA, REG_DEFAD_USEAD, REG_DEFAD_USEAD, "ah:al,ax,", "dx:ax,dx:ax,", "edx:eax,edx:eax,"),
 #undef UNARY_ENCODING_MAP
 
-  { kX86Bswap32R, kRegOpcode, IS_UNARY_OP | REG_DEF0_USE0, { 0, 0, 0x0F, 0xC8, 0, 0, 0, 0 }, "Bswap32R", "!0r" },
+  { kX86Bswap32R, kRegOpcode, IS_UNARY_OP | REG_DEF0_USE0,       { 0, 0, 0x0F, 0xC8, 0, 0, 0, 0 }, "Bswap32R", "!0r" },
+  { kX86Push32R,  kRegOpcode, IS_UNARY_OP | REG_USE0 | IS_STORE, { 0, 0, 0x50, 0,    0, 0, 0, 0 }, "Push32R",  "!0r" },
+  { kX86Pop32R,   kRegOpcode, IS_UNARY_OP | REG_DEF0 | IS_LOAD,  { 0, 0, 0x58, 0,    0, 0, 0, 0 }, "Pop32R",   "!0r" },
 
 #define EXT_0F_ENCODING_MAP(opname, prefix, opcode, reg_def) \
 { kX86 ## opname ## RR, kRegReg,             IS_BINARY_OP   | reg_def | REG_USE01,  { prefix, 0, 0x0F, opcode, 0, 0, 0, 0 }, #opname "RR", "!0r,!1r" }, \
@@ -306,9 +308,10 @@
   { kX86CmpxchgRR, kRegRegStore, IS_BINARY_OP | REG_DEF0 | REG_USE01 | REG_DEFA_USEA | SETS_CCODES, { 0, 0, 0x0F, 0xB1, 0, 0, 0, 0 }, "Cmpxchg", "!0r,!1r" },
   { kX86CmpxchgMR, kMemReg,   IS_STORE | IS_TERTIARY_OP | REG_USE02 | REG_DEFA_USEA | SETS_CCODES, { 0, 0, 0x0F, 0xB1, 0, 0, 0, 0 }, "Cmpxchg", "[!0r+!1d],!2r" },
   { kX86CmpxchgAR, kArrayReg, IS_STORE | IS_QUIN_OP | REG_USE014 | REG_DEFA_USEA | SETS_CCODES, { 0, 0, 0x0F, 0xB1, 0, 0, 0, 0 }, "Cmpxchg", "[!0r+!1r<<!2d+!3d],!4r" },
-  { kX86LockCmpxchgRR, kRegRegStore, IS_BINARY_OP | REG_DEF0 | REG_USE01 | REG_DEFA_USEA | SETS_CCODES, { 0xF0, 0, 0x0F, 0xB1, 0, 0, 0, 0 }, "Lock Cmpxchg", "!0r,!1r" },
   { kX86LockCmpxchgMR, kMemReg,   IS_STORE | IS_TERTIARY_OP | REG_USE02 | REG_DEFA_USEA | SETS_CCODES, { 0xF0, 0, 0x0F, 0xB1, 0, 0, 0, 0 }, "Lock Cmpxchg", "[!0r+!1d],!2r" },
   { kX86LockCmpxchgAR, kArrayReg, IS_STORE | IS_QUIN_OP | REG_USE014 | REG_DEFA_USEA | SETS_CCODES, { 0xF0, 0, 0x0F, 0xB1, 0, 0, 0, 0 }, "Lock Cmpxchg", "[!0r+!1r<<!2d+!3d],!4r" },
+  { kX86LockCmpxchg8bM, kMem,   IS_STORE | IS_BINARY_OP | REG_USE0 | REG_DEFAD_USEAD | REG_USEC | REG_USEB | SETS_CCODES, { 0xF0, 0, 0x0F, 0xC7, 0, 1, 0, 0 }, "Lock Cmpxchg8b", "[!0r+!1d]" },
+  { kX86LockCmpxchg8bA, kArray, IS_STORE | IS_QUAD_OP | REG_USE01 | REG_DEFAD_USEAD | REG_USEC | REG_USEB | SETS_CCODES, { 0xF0, 0, 0x0F, 0xC7, 0, 1, 0, 0 }, "Lock Cmpxchg8b", "[!0r+!1r<<!2d+!3d]" },
 
   EXT_0F_ENCODING_MAP(Movzx8,  0x00, 0xB6, REG_DEF0),
   EXT_0F_ENCODING_MAP(Movzx16, 0x00, 0xB7, REG_DEF0),
@@ -493,6 +496,37 @@
   return 0;
 }
 
+void X86Mir2Lir::EmitPrefix(const X86EncodingMap* entry) {
+  if (entry->skeleton.prefix1 != 0) {
+    code_buffer_.push_back(entry->skeleton.prefix1);
+    if (entry->skeleton.prefix2 != 0) {
+      code_buffer_.push_back(entry->skeleton.prefix2);
+    }
+  } else {
+    DCHECK_EQ(0, entry->skeleton.prefix2);
+  }
+}
+
+void X86Mir2Lir::EmitOpcode(const X86EncodingMap* entry) {
+  code_buffer_.push_back(entry->skeleton.opcode);
+  if (entry->skeleton.opcode == 0x0F) {
+    code_buffer_.push_back(entry->skeleton.extra_opcode1);
+    if (entry->skeleton.extra_opcode1 == 0x38 || entry->skeleton.extra_opcode1 == 0x3A) {
+      code_buffer_.push_back(entry->skeleton.extra_opcode2);
+    } else {
+      DCHECK_EQ(0, entry->skeleton.extra_opcode2);
+    }
+  } else {
+    DCHECK_EQ(0, entry->skeleton.extra_opcode1);
+    DCHECK_EQ(0, entry->skeleton.extra_opcode2);
+  }
+}
+
+void X86Mir2Lir::EmitPrefixAndOpcode(const X86EncodingMap* entry) {
+  EmitPrefix(entry);
+  EmitOpcode(entry);
+}
+
 static uint8_t ModrmForDisp(int base, int disp) {
   // BP requires an explicit disp, so do not omit it in the 0 case
   if (disp == 0 && base != rBP) {
@@ -504,7 +538,7 @@
   }
 }
 
-void X86Mir2Lir::EmitDisp(int base, int disp) {
+void X86Mir2Lir::EmitDisp(uint8_t base, int disp) {
   // BP requires an explicit disp, so do not omit it in the 0 case
   if (disp == 0 && base != rBP) {
     return;
@@ -518,167 +552,22 @@
   }
 }
 
-void X86Mir2Lir::EmitOpRegOpcode(const X86EncodingMap* entry, uint8_t reg) {
-  if (entry->skeleton.prefix1 != 0) {
-    code_buffer_.push_back(entry->skeleton.prefix1);
-    if (entry->skeleton.prefix2 != 0) {
-      code_buffer_.push_back(entry->skeleton.prefix2);
-    }
-  } else {
-    DCHECK_EQ(0, entry->skeleton.prefix2);
-  }
-  code_buffer_.push_back(entry->skeleton.opcode);
-  if (entry->skeleton.opcode == 0x0F) {
-    code_buffer_.push_back(entry->skeleton.extra_opcode1);
-    // There's no 3-byte instruction with +rd
-    DCHECK_NE(0x38, entry->skeleton.extra_opcode1);
-    DCHECK_NE(0x3A, entry->skeleton.extra_opcode1);
-    DCHECK_EQ(0, entry->skeleton.extra_opcode2);
-  } else {
-    DCHECK_EQ(0, entry->skeleton.extra_opcode1);
-    DCHECK_EQ(0, entry->skeleton.extra_opcode2);
-  }
-  DCHECK(!X86_FPREG(reg));
-  DCHECK_LT(reg, 8);
-  code_buffer_.back() += reg;
-  DCHECK_EQ(0, entry->skeleton.ax_opcode);
-  DCHECK_EQ(0, entry->skeleton.immediate_bytes);
-}
-
-void X86Mir2Lir::EmitOpReg(const X86EncodingMap* entry, uint8_t reg) {
-  if (entry->skeleton.prefix1 != 0) {
-    code_buffer_.push_back(entry->skeleton.prefix1);
-    if (entry->skeleton.prefix2 != 0) {
-      code_buffer_.push_back(entry->skeleton.prefix2);
-    }
-  } else {
-    DCHECK_EQ(0, entry->skeleton.prefix2);
-  }
-  code_buffer_.push_back(entry->skeleton.opcode);
-  if (entry->skeleton.opcode == 0x0F) {
-    code_buffer_.push_back(entry->skeleton.extra_opcode1);
-    if (entry->skeleton.extra_opcode1 == 0x38 || entry->skeleton.extra_opcode1 == 0x3A) {
-      code_buffer_.push_back(entry->skeleton.extra_opcode2);
-    } else {
-      DCHECK_EQ(0, entry->skeleton.extra_opcode2);
-    }
-  } else {
-    DCHECK_EQ(0, entry->skeleton.extra_opcode1);
-    DCHECK_EQ(0, entry->skeleton.extra_opcode2);
-  }
-  if (X86_FPREG(reg)) {
-    reg = reg & X86_FP_REG_MASK;
-  }
-  if (reg >= 4) {
-    DCHECK(strchr(entry->name, '8') == NULL) << entry->name << " " << static_cast<int>(reg)
-        << " in " << PrettyMethod(cu_->method_idx, *cu_->dex_file);
-  }
-  DCHECK_LT(reg, 8);
-  uint8_t modrm = (3 << 6) | (entry->skeleton.modrm_opcode << 3) | reg;
-  code_buffer_.push_back(modrm);
-  DCHECK_EQ(0, entry->skeleton.ax_opcode);
-  DCHECK_EQ(0, entry->skeleton.immediate_bytes);
-}
-
-void X86Mir2Lir::EmitOpMem(const X86EncodingMap* entry, uint8_t base, int disp) {
-  if (entry->skeleton.prefix1 != 0) {
-    code_buffer_.push_back(entry->skeleton.prefix1);
-    if (entry->skeleton.prefix2 != 0) {
-      code_buffer_.push_back(entry->skeleton.prefix2);
-    }
-  } else {
-    DCHECK_EQ(0, entry->skeleton.prefix2);
-  }
-  code_buffer_.push_back(entry->skeleton.opcode);
-  DCHECK_EQ(0, entry->skeleton.extra_opcode1);
-  DCHECK_EQ(0, entry->skeleton.extra_opcode2);
-  DCHECK_LT(entry->skeleton.modrm_opcode, 8);
+void X86Mir2Lir::EmitModrmDisp(uint8_t reg_or_opcode, uint8_t base, int disp) {
+  DCHECK_LT(reg_or_opcode, 8);
   DCHECK_LT(base, 8);
-  uint8_t modrm = (ModrmForDisp(base, disp) << 6) | (entry->skeleton.modrm_opcode << 3) | base;
-  code_buffer_.push_back(modrm);
-  EmitDisp(base, disp);
-  DCHECK_EQ(0, entry->skeleton.ax_opcode);
-  DCHECK_EQ(0, entry->skeleton.immediate_bytes);
-}
-
-void X86Mir2Lir::EmitMemReg(const X86EncodingMap* entry,
-                       uint8_t base, int disp, uint8_t reg) {
-  if (entry->skeleton.prefix1 != 0) {
-    code_buffer_.push_back(entry->skeleton.prefix1);
-    if (entry->skeleton.prefix2 != 0) {
-      code_buffer_.push_back(entry->skeleton.prefix2);
-    }
-  } else {
-    DCHECK_EQ(0, entry->skeleton.prefix2);
-  }
-  code_buffer_.push_back(entry->skeleton.opcode);
-  if (entry->skeleton.opcode == 0x0F) {
-    code_buffer_.push_back(entry->skeleton.extra_opcode1);
-    if (entry->skeleton.extra_opcode1 == 0x38 || entry->skeleton.extra_opcode1 == 0x3A) {
-      code_buffer_.push_back(entry->skeleton.extra_opcode2);
-    } else {
-      DCHECK_EQ(0, entry->skeleton.extra_opcode2);
-    }
-  } else {
-    DCHECK_EQ(0, entry->skeleton.extra_opcode1);
-    DCHECK_EQ(0, entry->skeleton.extra_opcode2);
-  }
-  if (X86_FPREG(reg)) {
-    reg = reg & X86_FP_REG_MASK;
-  }
-  if (reg >= 4) {
-    DCHECK(strchr(entry->name, '8') == NULL ||
-           entry->opcode == kX86Movzx8RM || entry->opcode == kX86Movsx8RM)
-        << entry->name << " " << static_cast<int>(reg)
-        << " in " << PrettyMethod(cu_->method_idx, *cu_->dex_file);
-  }
-  DCHECK_LT(reg, 8);
-  DCHECK_LT(base, 8);
-  uint8_t modrm = (ModrmForDisp(base, disp) << 6) | (reg << 3) | base;
+  uint8_t modrm = (ModrmForDisp(base, disp) << 6) | (reg_or_opcode << 3) | base;
   code_buffer_.push_back(modrm);
   if (base == rX86_SP) {
     // Special SIB for SP base
     code_buffer_.push_back(0 << 6 | (rX86_SP << 3) | rX86_SP);
   }
   EmitDisp(base, disp);
-  DCHECK_EQ(0, entry->skeleton.modrm_opcode);
-  DCHECK_EQ(0, entry->skeleton.ax_opcode);
-  DCHECK_EQ(0, entry->skeleton.immediate_bytes);
 }
 
-void X86Mir2Lir::EmitRegMem(const X86EncodingMap* entry,
-                       uint8_t reg, uint8_t base, int disp) {
-  // Opcode will flip operands.
-  EmitMemReg(entry, base, disp, reg);
-}
-
-void X86Mir2Lir::EmitRegArray(const X86EncodingMap* entry, uint8_t reg, uint8_t base, uint8_t index,
-                  int scale, int disp) {
-  if (entry->skeleton.prefix1 != 0) {
-    code_buffer_.push_back(entry->skeleton.prefix1);
-    if (entry->skeleton.prefix2 != 0) {
-      code_buffer_.push_back(entry->skeleton.prefix2);
-    }
-  } else {
-    DCHECK_EQ(0, entry->skeleton.prefix2);
-  }
-  code_buffer_.push_back(entry->skeleton.opcode);
-  if (entry->skeleton.opcode == 0x0F) {
-    code_buffer_.push_back(entry->skeleton.extra_opcode1);
-    if (entry->skeleton.extra_opcode1 == 0x38 || entry->skeleton.extra_opcode1 == 0x3A) {
-      code_buffer_.push_back(entry->skeleton.extra_opcode2);
-    } else {
-      DCHECK_EQ(0, entry->skeleton.extra_opcode2);
-    }
-  } else {
-    DCHECK_EQ(0, entry->skeleton.extra_opcode1);
-    DCHECK_EQ(0, entry->skeleton.extra_opcode2);
-  }
-  if (X86_FPREG(reg)) {
-    reg = reg & X86_FP_REG_MASK;
-  }
-  DCHECK_LT(reg, 8);
-  uint8_t modrm = (ModrmForDisp(base, disp) << 6) | (reg << 3) | rX86_SP;
+void X86Mir2Lir::EmitModrmSibDisp(uint8_t reg_or_opcode, uint8_t base, uint8_t index,
+                                  int scale, int disp) {
+  DCHECK_LT(reg_or_opcode, 8);
+  uint8_t modrm = (ModrmForDisp(base, disp) << 6) | (reg_or_opcode << 3) | rX86_SP;
   code_buffer_.push_back(modrm);
   DCHECK_LT(scale, 4);
   DCHECK_LT(index, 8);
@@ -686,124 +575,9 @@
   uint8_t sib = (scale << 6) | (index << 3) | base;
   code_buffer_.push_back(sib);
   EmitDisp(base, disp);
-  DCHECK_EQ(0, entry->skeleton.modrm_opcode);
-  DCHECK_EQ(0, entry->skeleton.ax_opcode);
-  DCHECK_EQ(0, entry->skeleton.immediate_bytes);
 }
 
-void X86Mir2Lir::EmitArrayReg(const X86EncodingMap* entry, uint8_t base, uint8_t index, int scale, int disp,
-                  uint8_t reg) {
-  // Opcode will flip operands.
-  EmitRegArray(entry, reg, base, index, scale, disp);
-}
-
-void X86Mir2Lir::EmitRegThread(const X86EncodingMap* entry, uint8_t reg, int disp) {
-  DCHECK_NE(entry->skeleton.prefix1, 0);
-  code_buffer_.push_back(entry->skeleton.prefix1);
-  if (entry->skeleton.prefix2 != 0) {
-    code_buffer_.push_back(entry->skeleton.prefix2);
-  }
-  code_buffer_.push_back(entry->skeleton.opcode);
-  if (entry->skeleton.opcode == 0x0F) {
-    code_buffer_.push_back(entry->skeleton.extra_opcode1);
-    if (entry->skeleton.extra_opcode1 == 0x38 || entry->skeleton.extra_opcode1 == 0x3A) {
-      code_buffer_.push_back(entry->skeleton.extra_opcode2);
-    } else {
-      DCHECK_EQ(0, entry->skeleton.extra_opcode2);
-    }
-  } else {
-    DCHECK_EQ(0, entry->skeleton.extra_opcode1);
-    DCHECK_EQ(0, entry->skeleton.extra_opcode2);
-  }
-  if (X86_FPREG(reg)) {
-    reg = reg & X86_FP_REG_MASK;
-  }
-  if (reg >= 4) {
-    DCHECK(strchr(entry->name, '8') == NULL) << entry->name << " " << static_cast<int>(reg)
-        << " in " << PrettyMethod(cu_->method_idx, *cu_->dex_file);
-  }
-  DCHECK_LT(reg, 8);
-  uint8_t modrm = (0 << 6) | (reg << 3) | rBP;
-  code_buffer_.push_back(modrm);
-  code_buffer_.push_back(disp & 0xFF);
-  code_buffer_.push_back((disp >> 8) & 0xFF);
-  code_buffer_.push_back((disp >> 16) & 0xFF);
-  code_buffer_.push_back((disp >> 24) & 0xFF);
-  DCHECK_EQ(0, entry->skeleton.modrm_opcode);
-  DCHECK_EQ(0, entry->skeleton.ax_opcode);
-  DCHECK_EQ(0, entry->skeleton.immediate_bytes);
-}
-
-void X86Mir2Lir::EmitRegReg(const X86EncodingMap* entry, uint8_t reg1, uint8_t reg2) {
-  if (entry->skeleton.prefix1 != 0) {
-    code_buffer_.push_back(entry->skeleton.prefix1);
-    if (entry->skeleton.prefix2 != 0) {
-      code_buffer_.push_back(entry->skeleton.prefix2);
-    }
-  } else {
-    DCHECK_EQ(0, entry->skeleton.prefix2);
-  }
-  code_buffer_.push_back(entry->skeleton.opcode);
-  if (entry->skeleton.opcode == 0x0F) {
-    code_buffer_.push_back(entry->skeleton.extra_opcode1);
-    if (entry->skeleton.extra_opcode1 == 0x38 || entry->skeleton.extra_opcode1 == 0x3A) {
-      code_buffer_.push_back(entry->skeleton.extra_opcode2);
-    } else {
-      DCHECK_EQ(0, entry->skeleton.extra_opcode2);
-    }
-  } else {
-    DCHECK_EQ(0, entry->skeleton.extra_opcode1);
-    DCHECK_EQ(0, entry->skeleton.extra_opcode2);
-  }
-  if (X86_FPREG(reg1)) {
-    reg1 = reg1 & X86_FP_REG_MASK;
-  }
-  if (X86_FPREG(reg2)) {
-    reg2 = reg2 & X86_FP_REG_MASK;
-  }
-  DCHECK_LT(reg1, 8);
-  DCHECK_LT(reg2, 8);
-  uint8_t modrm = (3 << 6) | (reg1 << 3) | reg2;
-  code_buffer_.push_back(modrm);
-  DCHECK_EQ(0, entry->skeleton.modrm_opcode);
-  DCHECK_EQ(0, entry->skeleton.ax_opcode);
-  DCHECK_EQ(0, entry->skeleton.immediate_bytes);
-}
-
-void X86Mir2Lir::EmitRegRegImm(const X86EncodingMap* entry,
-                          uint8_t reg1, uint8_t reg2, int32_t imm) {
-  if (entry->skeleton.prefix1 != 0) {
-    code_buffer_.push_back(entry->skeleton.prefix1);
-    if (entry->skeleton.prefix2 != 0) {
-      code_buffer_.push_back(entry->skeleton.prefix2);
-    }
-  } else {
-    DCHECK_EQ(0, entry->skeleton.prefix2);
-  }
-  code_buffer_.push_back(entry->skeleton.opcode);
-  if (entry->skeleton.opcode == 0x0F) {
-    code_buffer_.push_back(entry->skeleton.extra_opcode1);
-    if (entry->skeleton.extra_opcode1 == 0x38 || entry->skeleton.extra_opcode1 == 0x3A) {
-      code_buffer_.push_back(entry->skeleton.extra_opcode2);
-    } else {
-      DCHECK_EQ(0, entry->skeleton.extra_opcode2);
-    }
-  } else {
-    DCHECK_EQ(0, entry->skeleton.extra_opcode1);
-    DCHECK_EQ(0, entry->skeleton.extra_opcode2);
-  }
-  if (X86_FPREG(reg1)) {
-    reg1 = reg1 & X86_FP_REG_MASK;
-  }
-  if (X86_FPREG(reg2)) {
-    reg2 = reg2 & X86_FP_REG_MASK;
-  }
-  DCHECK_LT(reg1, 8);
-  DCHECK_LT(reg2, 8);
-  uint8_t modrm = (3 << 6) | (reg1 << 3) | reg2;
-  code_buffer_.push_back(modrm);
-  DCHECK_EQ(0, entry->skeleton.modrm_opcode);
-  DCHECK_EQ(0, entry->skeleton.ax_opcode);
+void X86Mir2Lir::EmitImm(const X86EncodingMap* entry, int imm) {
   switch (entry->skeleton.immediate_bytes) {
     case 1:
       DCHECK(IS_SIMM8(imm));
@@ -827,6 +601,153 @@
   }
 }
 
+void X86Mir2Lir::EmitOpRegOpcode(const X86EncodingMap* entry, uint8_t reg) {
+  EmitPrefixAndOpcode(entry);
+  // There's no 3-byte instruction with +rd
+  DCHECK(entry->skeleton.opcode != 0x0F ||
+         (entry->skeleton.extra_opcode1 != 0x38 && entry->skeleton.extra_opcode1 != 0x3A));
+  DCHECK(!X86_FPREG(reg));
+  DCHECK_LT(reg, 8);
+  code_buffer_.back() += reg;
+  DCHECK_EQ(0, entry->skeleton.ax_opcode);
+  DCHECK_EQ(0, entry->skeleton.immediate_bytes);
+}
+
+void X86Mir2Lir::EmitOpReg(const X86EncodingMap* entry, uint8_t reg) {
+  EmitPrefixAndOpcode(entry);
+  if (X86_FPREG(reg)) {
+    reg = reg & X86_FP_REG_MASK;
+  }
+  if (reg >= 4) {
+    DCHECK(strchr(entry->name, '8') == NULL) << entry->name << " " << static_cast<int>(reg)
+        << " in " << PrettyMethod(cu_->method_idx, *cu_->dex_file);
+  }
+  DCHECK_LT(reg, 8);
+  uint8_t modrm = (3 << 6) | (entry->skeleton.modrm_opcode << 3) | reg;
+  code_buffer_.push_back(modrm);
+  DCHECK_EQ(0, entry->skeleton.ax_opcode);
+  DCHECK_EQ(0, entry->skeleton.immediate_bytes);
+}
+
+void X86Mir2Lir::EmitOpMem(const X86EncodingMap* entry, uint8_t base, int disp) {
+  EmitPrefix(entry);
+  code_buffer_.push_back(entry->skeleton.opcode);
+  DCHECK_NE(0x0F, entry->skeleton.opcode);
+  DCHECK_EQ(0, entry->skeleton.extra_opcode1);
+  DCHECK_EQ(0, entry->skeleton.extra_opcode2);
+  DCHECK_NE(rX86_SP, base);
+  EmitModrmDisp(entry->skeleton.modrm_opcode, base, disp);
+  DCHECK_EQ(0, entry->skeleton.ax_opcode);
+  DCHECK_EQ(0, entry->skeleton.immediate_bytes);
+}
+
+void X86Mir2Lir::EmitOpArray(const X86EncodingMap* entry, uint8_t base, uint8_t index,
+                             int scale, int disp) {
+  EmitPrefixAndOpcode(entry);
+  EmitModrmSibDisp(entry->skeleton.modrm_opcode, base, index, scale, disp);
+  DCHECK_EQ(0, entry->skeleton.ax_opcode);
+  DCHECK_EQ(0, entry->skeleton.immediate_bytes);
+}
+
+void X86Mir2Lir::EmitMemReg(const X86EncodingMap* entry,
+                       uint8_t base, int disp, uint8_t reg) {
+  EmitPrefixAndOpcode(entry);
+  if (X86_FPREG(reg)) {
+    reg = reg & X86_FP_REG_MASK;
+  }
+  if (reg >= 4) {
+    DCHECK(strchr(entry->name, '8') == NULL ||
+           entry->opcode == kX86Movzx8RM || entry->opcode == kX86Movsx8RM)
+        << entry->name << " " << static_cast<int>(reg)
+        << " in " << PrettyMethod(cu_->method_idx, *cu_->dex_file);
+  }
+  EmitModrmDisp(reg, base, disp);
+  DCHECK_EQ(0, entry->skeleton.modrm_opcode);
+  DCHECK_EQ(0, entry->skeleton.ax_opcode);
+  DCHECK_EQ(0, entry->skeleton.immediate_bytes);
+}
+
+void X86Mir2Lir::EmitRegMem(const X86EncodingMap* entry,
+                       uint8_t reg, uint8_t base, int disp) {
+  // Opcode will flip operands.
+  EmitMemReg(entry, base, disp, reg);
+}
+
+void X86Mir2Lir::EmitRegArray(const X86EncodingMap* entry, uint8_t reg, uint8_t base, uint8_t index,
+                              int scale, int disp) {
+  EmitPrefixAndOpcode(entry);
+  if (X86_FPREG(reg)) {
+    reg = reg & X86_FP_REG_MASK;
+  }
+  EmitModrmSibDisp(reg, base, index, scale, disp);
+  DCHECK_EQ(0, entry->skeleton.modrm_opcode);
+  DCHECK_EQ(0, entry->skeleton.ax_opcode);
+  DCHECK_EQ(0, entry->skeleton.immediate_bytes);
+}
+
+void X86Mir2Lir::EmitArrayReg(const X86EncodingMap* entry, uint8_t base, uint8_t index, int scale, int disp,
+                  uint8_t reg) {
+  // Opcode will flip operands.
+  EmitRegArray(entry, reg, base, index, scale, disp);
+}
+
+void X86Mir2Lir::EmitRegThread(const X86EncodingMap* entry, uint8_t reg, int disp) {
+  DCHECK_NE(entry->skeleton.prefix1, 0);
+  EmitPrefixAndOpcode(entry);
+  if (X86_FPREG(reg)) {
+    reg = reg & X86_FP_REG_MASK;
+  }
+  if (reg >= 4) {
+    DCHECK(strchr(entry->name, '8') == NULL) << entry->name << " " << static_cast<int>(reg)
+        << " in " << PrettyMethod(cu_->method_idx, *cu_->dex_file);
+  }
+  DCHECK_LT(reg, 8);
+  uint8_t modrm = (0 << 6) | (reg << 3) | rBP;
+  code_buffer_.push_back(modrm);
+  code_buffer_.push_back(disp & 0xFF);
+  code_buffer_.push_back((disp >> 8) & 0xFF);
+  code_buffer_.push_back((disp >> 16) & 0xFF);
+  code_buffer_.push_back((disp >> 24) & 0xFF);
+  DCHECK_EQ(0, entry->skeleton.modrm_opcode);
+  DCHECK_EQ(0, entry->skeleton.ax_opcode);
+  DCHECK_EQ(0, entry->skeleton.immediate_bytes);
+}
+
+void X86Mir2Lir::EmitRegReg(const X86EncodingMap* entry, uint8_t reg1, uint8_t reg2) {
+  EmitPrefixAndOpcode(entry);
+  if (X86_FPREG(reg1)) {
+    reg1 = reg1 & X86_FP_REG_MASK;
+  }
+  if (X86_FPREG(reg2)) {
+    reg2 = reg2 & X86_FP_REG_MASK;
+  }
+  DCHECK_LT(reg1, 8);
+  DCHECK_LT(reg2, 8);
+  uint8_t modrm = (3 << 6) | (reg1 << 3) | reg2;
+  code_buffer_.push_back(modrm);
+  DCHECK_EQ(0, entry->skeleton.modrm_opcode);
+  DCHECK_EQ(0, entry->skeleton.ax_opcode);
+  DCHECK_EQ(0, entry->skeleton.immediate_bytes);
+}
+
+void X86Mir2Lir::EmitRegRegImm(const X86EncodingMap* entry,
+                          uint8_t reg1, uint8_t reg2, int32_t imm) {
+  EmitPrefixAndOpcode(entry);
+  if (X86_FPREG(reg1)) {
+    reg1 = reg1 & X86_FP_REG_MASK;
+  }
+  if (X86_FPREG(reg2)) {
+    reg2 = reg2 & X86_FP_REG_MASK;
+  }
+  DCHECK_LT(reg1, 8);
+  DCHECK_LT(reg2, 8);
+  uint8_t modrm = (3 << 6) | (reg1 << 3) | reg2;
+  code_buffer_.push_back(modrm);
+  DCHECK_EQ(0, entry->skeleton.modrm_opcode);
+  DCHECK_EQ(0, entry->skeleton.ax_opcode);
+  EmitImm(entry, imm);
+}
+
 void X86Mir2Lir::EmitRegImm(const X86EncodingMap* entry, uint8_t reg, int imm) {
   if (entry->skeleton.prefix1 != 0) {
     code_buffer_.push_back(entry->skeleton.prefix1);
@@ -839,95 +760,25 @@
   if (reg == rAX && entry->skeleton.ax_opcode != 0) {
     code_buffer_.push_back(entry->skeleton.ax_opcode);
   } else {
-    code_buffer_.push_back(entry->skeleton.opcode);
-    if (entry->skeleton.opcode == 0x0F) {
-      code_buffer_.push_back(entry->skeleton.extra_opcode1);
-      if (entry->skeleton.extra_opcode1 == 0x38 || entry->skeleton.extra_opcode1 == 0x3A) {
-        code_buffer_.push_back(entry->skeleton.extra_opcode2);
-      } else {
-        DCHECK_EQ(0, entry->skeleton.extra_opcode2);
-      }
-    } else {
-      DCHECK_EQ(0, entry->skeleton.extra_opcode1);
-      DCHECK_EQ(0, entry->skeleton.extra_opcode2);
-    }
+    EmitOpcode(entry);
     if (X86_FPREG(reg)) {
       reg = reg & X86_FP_REG_MASK;
     }
     uint8_t modrm = (3 << 6) | (entry->skeleton.modrm_opcode << 3) | reg;
     code_buffer_.push_back(modrm);
   }
-  switch (entry->skeleton.immediate_bytes) {
-    case 1:
-      DCHECK(IS_SIMM8(imm));
-      code_buffer_.push_back(imm & 0xFF);
-      break;
-    case 2:
-      DCHECK(IS_SIMM16(imm));
-      code_buffer_.push_back(imm & 0xFF);
-      code_buffer_.push_back((imm >> 8) & 0xFF);
-      break;
-    case 4:
-      code_buffer_.push_back(imm & 0xFF);
-      code_buffer_.push_back((imm >> 8) & 0xFF);
-      code_buffer_.push_back((imm >> 16) & 0xFF);
-      code_buffer_.push_back((imm >> 24) & 0xFF);
-      break;
-    default:
-      LOG(FATAL) << "Unexpected immediate bytes (" << entry->skeleton.immediate_bytes
-          << ") for instruction: " << entry->name;
-      break;
-  }
+  EmitImm(entry, imm);
 }
 
 void X86Mir2Lir::EmitThreadImm(const X86EncodingMap* entry, int disp, int imm) {
-  if (entry->skeleton.prefix1 != 0) {
-    code_buffer_.push_back(entry->skeleton.prefix1);
-    if (entry->skeleton.prefix2 != 0) {
-      code_buffer_.push_back(entry->skeleton.prefix2);
-    }
-  } else {
-    DCHECK_EQ(0, entry->skeleton.prefix2);
-  }
-  code_buffer_.push_back(entry->skeleton.opcode);
-  if (entry->skeleton.opcode == 0x0F) {
-    code_buffer_.push_back(entry->skeleton.extra_opcode1);
-    if (entry->skeleton.extra_opcode1 == 0x38 || entry->skeleton.extra_opcode1 == 0x3A) {
-      code_buffer_.push_back(entry->skeleton.extra_opcode2);
-    } else {
-      DCHECK_EQ(0, entry->skeleton.extra_opcode2);
-    }
-  } else {
-    DCHECK_EQ(0, entry->skeleton.extra_opcode1);
-    DCHECK_EQ(0, entry->skeleton.extra_opcode2);
-  }
+  EmitPrefixAndOpcode(entry);
   uint8_t modrm = (0 << 6) | (entry->skeleton.modrm_opcode << 3) | rBP;
   code_buffer_.push_back(modrm);
   code_buffer_.push_back(disp & 0xFF);
   code_buffer_.push_back((disp >> 8) & 0xFF);
   code_buffer_.push_back((disp >> 16) & 0xFF);
   code_buffer_.push_back((disp >> 24) & 0xFF);
-  switch (entry->skeleton.immediate_bytes) {
-    case 1:
-      DCHECK(IS_SIMM8(imm));
-      code_buffer_.push_back(imm & 0xFF);
-      break;
-    case 2:
-      DCHECK(IS_SIMM16(imm));
-      code_buffer_.push_back(imm & 0xFF);
-      code_buffer_.push_back((imm >> 8) & 0xFF);
-      break;
-    case 4:
-      code_buffer_.push_back(imm & 0xFF);
-      code_buffer_.push_back((imm >> 8) & 0xFF);
-      code_buffer_.push_back((imm >> 16) & 0xFF);
-      code_buffer_.push_back((imm >> 24) & 0xFF);
-      break;
-    default:
-      LOG(FATAL) << "Unexpected immediate bytes (" << entry->skeleton.immediate_bytes
-          << ") for instruction: " << entry->name;
-      break;
-  }
+  EmitImm(entry, imm);
   DCHECK_EQ(entry->skeleton.ax_opcode, 0);
 }
 
@@ -941,31 +792,16 @@
 }
 
 void X86Mir2Lir::EmitShiftRegImm(const X86EncodingMap* entry, uint8_t reg, int imm) {
-  if (entry->skeleton.prefix1 != 0) {
-    code_buffer_.push_back(entry->skeleton.prefix1);
-    if (entry->skeleton.prefix2 != 0) {
-      code_buffer_.push_back(entry->skeleton.prefix2);
-    }
-  } else {
-    DCHECK_EQ(0, entry->skeleton.prefix2);
-  }
+  EmitPrefix(entry);
   if (imm != 1) {
     code_buffer_.push_back(entry->skeleton.opcode);
   } else {
     // Shorter encoding for 1 bit shift
     code_buffer_.push_back(entry->skeleton.ax_opcode);
   }
-  if (entry->skeleton.opcode == 0x0F) {
-    code_buffer_.push_back(entry->skeleton.extra_opcode1);
-    if (entry->skeleton.extra_opcode1 == 0x38 || entry->skeleton.extra_opcode1 == 0x3A) {
-      code_buffer_.push_back(entry->skeleton.extra_opcode2);
-    } else {
-      DCHECK_EQ(0, entry->skeleton.extra_opcode2);
-    }
-  } else {
-    DCHECK_EQ(0, entry->skeleton.extra_opcode1);
-    DCHECK_EQ(0, entry->skeleton.extra_opcode2);
-  }
+  DCHECK_NE(0x0F, entry->skeleton.opcode);
+  DCHECK_EQ(0, entry->skeleton.extra_opcode1);
+  DCHECK_EQ(0, entry->skeleton.extra_opcode2);
   if (reg >= 4) {
     DCHECK(strchr(entry->name, '8') == NULL) << entry->name << " " << static_cast<int>(reg)
         << " in " << PrettyMethod(cu_->method_idx, *cu_->dex_file);
@@ -982,15 +818,9 @@
 
 void X86Mir2Lir::EmitShiftRegCl(const X86EncodingMap* entry, uint8_t reg, uint8_t cl) {
   DCHECK_EQ(cl, static_cast<uint8_t>(rCX));
-  if (entry->skeleton.prefix1 != 0) {
-    code_buffer_.push_back(entry->skeleton.prefix1);
-    if (entry->skeleton.prefix2 != 0) {
-      code_buffer_.push_back(entry->skeleton.prefix2);
-    }
-  } else {
-    DCHECK_EQ(0, entry->skeleton.prefix2);
-  }
+  EmitPrefix(entry);
   code_buffer_.push_back(entry->skeleton.opcode);
+  DCHECK_NE(0x0F, entry->skeleton.opcode);
   DCHECK_EQ(0, entry->skeleton.extra_opcode1);
   DCHECK_EQ(0, entry->skeleton.extra_opcode2);
   DCHECK_LT(reg, 8);
@@ -1060,55 +890,15 @@
 }
 
 void X86Mir2Lir::EmitCallMem(const X86EncodingMap* entry, uint8_t base, int disp) {
-  if (entry->skeleton.prefix1 != 0) {
-    code_buffer_.push_back(entry->skeleton.prefix1);
-    if (entry->skeleton.prefix2 != 0) {
-      code_buffer_.push_back(entry->skeleton.prefix2);
-    }
-  } else {
-    DCHECK_EQ(0, entry->skeleton.prefix2);
-  }
-  code_buffer_.push_back(entry->skeleton.opcode);
-  if (entry->skeleton.opcode == 0x0F) {
-    code_buffer_.push_back(entry->skeleton.extra_opcode1);
-    if (entry->skeleton.extra_opcode1 == 0x38 || entry->skeleton.extra_opcode1 == 0x3A) {
-      code_buffer_.push_back(entry->skeleton.extra_opcode2);
-    } else {
-      DCHECK_EQ(0, entry->skeleton.extra_opcode2);
-    }
-  } else {
-    DCHECK_EQ(0, entry->skeleton.extra_opcode1);
-    DCHECK_EQ(0, entry->skeleton.extra_opcode2);
-  }
-  uint8_t modrm = (ModrmForDisp(base, disp) << 6) | (entry->skeleton.modrm_opcode << 3) | base;
-  code_buffer_.push_back(modrm);
-  if (base == rX86_SP) {
-    // Special SIB for SP base
-    code_buffer_.push_back(0 << 6 | (rX86_SP << 3) | rX86_SP);
-  }
-  EmitDisp(base, disp);
+  EmitPrefixAndOpcode(entry);
+  EmitModrmDisp(entry->skeleton.modrm_opcode, base, disp);
   DCHECK_EQ(0, entry->skeleton.ax_opcode);
   DCHECK_EQ(0, entry->skeleton.immediate_bytes);
 }
 
 void X86Mir2Lir::EmitCallThread(const X86EncodingMap* entry, int disp) {
   DCHECK_NE(entry->skeleton.prefix1, 0);
-  code_buffer_.push_back(entry->skeleton.prefix1);
-  if (entry->skeleton.prefix2 != 0) {
-    code_buffer_.push_back(entry->skeleton.prefix2);
-  }
-  code_buffer_.push_back(entry->skeleton.opcode);
-  if (entry->skeleton.opcode == 0x0F) {
-    code_buffer_.push_back(entry->skeleton.extra_opcode1);
-    if (entry->skeleton.extra_opcode1 == 0x38 || entry->skeleton.extra_opcode1 == 0x3A) {
-      code_buffer_.push_back(entry->skeleton.extra_opcode2);
-    } else {
-      DCHECK_EQ(0, entry->skeleton.extra_opcode2);
-    }
-  } else {
-    DCHECK_EQ(0, entry->skeleton.extra_opcode1);
-    DCHECK_EQ(0, entry->skeleton.extra_opcode2);
-  }
+  EmitPrefixAndOpcode(entry);
   uint8_t modrm = (0 << 6) | (entry->skeleton.modrm_opcode << 3) | rBP;
   code_buffer_.push_back(modrm);
   code_buffer_.push_back(disp & 0xFF);
@@ -1132,20 +922,14 @@
         reinterpret_cast<Mir2Lir::EmbeddedData*>(UnwrapPointer(base_or_table));
     disp = tab_rec->offset;
   }
-  if (entry->skeleton.prefix1 != 0) {
-    code_buffer_.push_back(entry->skeleton.prefix1);
-    if (entry->skeleton.prefix2 != 0) {
-      code_buffer_.push_back(entry->skeleton.prefix2);
-    }
-  } else {
-    DCHECK_EQ(0, entry->skeleton.prefix2);
-  }
+  EmitPrefix(entry);
   if (X86_FPREG(reg)) {
     reg = reg & X86_FP_REG_MASK;
   }
   DCHECK_LT(reg, 8);
   if (entry->opcode == kX86PcRelLoadRA) {
     code_buffer_.push_back(entry->skeleton.opcode);
+    DCHECK_NE(0x0F, entry->skeleton.opcode);
     DCHECK_EQ(0, entry->skeleton.extra_opcode1);
     DCHECK_EQ(0, entry->skeleton.extra_opcode2);
     uint8_t modrm = (2 << 6) | (reg << 3) | rX86_SP;
@@ -1321,15 +1105,7 @@
       case kNullary:  // 1 byte of opcode
         DCHECK_EQ(0, entry->skeleton.prefix1);
         DCHECK_EQ(0, entry->skeleton.prefix2);
-        code_buffer_.push_back(entry->skeleton.opcode);
-        if (entry->skeleton.extra_opcode1 != 0) {
-          code_buffer_.push_back(entry->skeleton.extra_opcode1);
-          if (entry->skeleton.extra_opcode2 != 0) {
-            code_buffer_.push_back(entry->skeleton.extra_opcode2);
-          }
-        } else {
-          DCHECK_EQ(0, entry->skeleton.extra_opcode2);
-        }
+        EmitOpcode(entry);
         DCHECK_EQ(0, entry->skeleton.modrm_opcode);
         DCHECK_EQ(0, entry->skeleton.ax_opcode);
         DCHECK_EQ(0, entry->skeleton.immediate_bytes);
@@ -1343,6 +1119,9 @@
       case kMem:  // lir operands - 0: base, 1: disp
         EmitOpMem(entry, lir->operands[0], lir->operands[1]);
         break;
+      case kArray:  // lir operands - 0: base, 1: index, 2: scale, 3: disp
+        EmitOpArray(entry, lir->operands[0], lir->operands[1], lir->operands[2], lir->operands[3]);
+        break;
       case kMemReg:  // lir operands - 0: base, 1: disp, 2: reg
         EmitMemReg(entry, lir->operands[0], lir->operands[1], lir->operands[2]);
         break;
diff --git a/compiler/dex/quick/x86/codegen_x86.h b/compiler/dex/quick/x86/codegen_x86.h
index ffe2d67..6552607 100644
--- a/compiler/dex/quick/x86/codegen_x86.h
+++ b/compiler/dex/quick/x86/codegen_x86.h
@@ -61,7 +61,7 @@
     uint32_t FpRegMask();
     uint64_t GetRegMaskCommon(int reg);
     void AdjustSpillMask();
-    void ClobberCalleeSave();
+    void ClobberCallerSave();
     void FlushReg(int reg);
     void FlushRegWide(int reg1, int reg2);
     void FreeCallTemps();
@@ -171,10 +171,18 @@
     bool InexpensiveConstantDouble(int64_t value);
 
   private:
-    void EmitDisp(int base, int disp);
+    void EmitPrefix(const X86EncodingMap* entry);
+    void EmitOpcode(const X86EncodingMap* entry);
+    void EmitPrefixAndOpcode(const X86EncodingMap* entry);
+    void EmitDisp(uint8_t base, int disp);
+    void EmitModrmDisp(uint8_t reg_or_opcode, uint8_t base, int disp);
+    void EmitModrmSibDisp(uint8_t reg_or_opcode, uint8_t base, uint8_t index, int scale, int disp);
+    void EmitImm(const X86EncodingMap* entry, int imm);
     void EmitOpRegOpcode(const X86EncodingMap* entry, uint8_t reg);
     void EmitOpReg(const X86EncodingMap* entry, uint8_t reg);
     void EmitOpMem(const X86EncodingMap* entry, uint8_t base, int disp);
+    void EmitOpArray(const X86EncodingMap* entry, uint8_t base, uint8_t index,
+                     int scale, int disp);
     void EmitMemReg(const X86EncodingMap* entry, uint8_t base, int disp, uint8_t reg);
     void EmitRegMem(const X86EncodingMap* entry, uint8_t reg, uint8_t base, int disp);
     void EmitRegArray(const X86EncodingMap* entry, uint8_t reg, uint8_t base, uint8_t index,
diff --git a/compiler/dex/quick/x86/int_x86.cc b/compiler/dex/quick/x86/int_x86.cc
index 01d5c17..0133a0a 100644
--- a/compiler/dex/quick/x86/int_x86.cc
+++ b/compiler/dex/quick/x86/int_x86.cc
@@ -282,8 +282,69 @@
 }
 
 bool X86Mir2Lir::GenInlinedCas(CallInfo* info, bool is_long, bool is_object) {
-  DCHECK_NE(cu_->instruction_set, kThumb2);
-  return false;
+  DCHECK_EQ(cu_->instruction_set, kX86);
+  // Unused - RegLocation rl_src_unsafe = info->args[0];
+  RegLocation rl_src_obj = info->args[1];  // Object - known non-null
+  RegLocation rl_src_offset = info->args[2];  // long low
+  rl_src_offset.wide = 0;  // ignore high half in info->args[3]
+  RegLocation rl_src_expected = info->args[4];  // int, long or Object
+  // If is_long, high half is in info->args[5]
+  RegLocation rl_src_new_value = info->args[is_long ? 6 : 5];  // int, long or Object
+  // If is_long, high half is in info->args[7]
+
+  if (is_long) {
+    FlushAllRegs();
+    LockCallTemps();
+    NewLIR1(kX86Push32R, rDI);
+    MarkTemp(rDI);
+    LockTemp(rDI);
+    NewLIR1(kX86Push32R, rSI);
+    MarkTemp(rSI);
+    LockTemp(rSI);
+    LoadValueDirectFixed(rl_src_obj, rDI);
+    LoadValueDirectFixed(rl_src_offset, rSI);
+    LoadValueDirectWideFixed(rl_src_expected, rAX, rDX);
+    LoadValueDirectWideFixed(rl_src_new_value, rBX, rCX);
+    NewLIR4(kX86LockCmpxchg8bA, rDI, rSI, 0, 0);
+    FreeTemp(rSI);
+    UnmarkTemp(rSI);
+    NewLIR1(kX86Pop32R, rSI);
+    FreeTemp(rDI);
+    UnmarkTemp(rDI);
+    NewLIR1(kX86Pop32R, rDI);
+    FreeCallTemps();
+  } else {
+    // EAX must hold expected for CMPXCHG. Neither rl_new_value, nor r_ptr may be in EAX.
+    FlushReg(r0);
+    LockTemp(r0);
+
+    // Release store semantics, get the barrier out of the way.  TODO: revisit
+    GenMemBarrier(kStoreLoad);
+
+    RegLocation rl_object = LoadValue(rl_src_obj, kCoreReg);
+    RegLocation rl_new_value = LoadValue(rl_src_new_value, kCoreReg);
+
+    if (is_object && !mir_graph_->IsConstantNullRef(rl_new_value)) {
+      // Mark card for object assuming new value is stored.
+      FreeTemp(r0);  // Temporarily release EAX for MarkGCCard().
+      MarkGCCard(rl_new_value.low_reg, rl_object.low_reg);
+      LockTemp(r0);
+    }
+
+    RegLocation rl_offset = LoadValue(rl_src_offset, kCoreReg);
+    LoadValueDirect(rl_src_expected, r0);
+    NewLIR5(kX86LockCmpxchgAR, rl_object.low_reg, rl_offset.low_reg, 0, 0, rl_new_value.low_reg);
+
+    FreeTemp(r0);
+  }
+
+  // Convert ZF to boolean
+  RegLocation rl_dest = InlineTarget(info);  // boolean place for result
+  RegLocation rl_result = EvalLoc(rl_dest, kCoreReg, true);
+  NewLIR2(kX86Set8R, rl_result.low_reg, kX86CondZ);
+  NewLIR2(kX86Movzx8RR, rl_result.low_reg, rl_result.low_reg);
+  StoreValue(rl_dest, rl_result);
+  return true;
 }
 
 LIR* X86Mir2Lir::OpPcRelLoad(int reg, LIR* target) {
diff --git a/compiler/dex/quick/x86/target_x86.cc b/compiler/dex/quick/x86/target_x86.cc
index 878fa76..0b8c07e 100644
--- a/compiler/dex/quick/x86/target_x86.cc
+++ b/compiler/dex/quick/x86/target_x86.cc
@@ -165,6 +165,10 @@
   if (flags & REG_USED) {
     SetupRegMask(&lir->u.m.use_mask, rDX);
   }
+
+  if (flags & REG_USEB) {
+    SetupRegMask(&lir->u.m.use_mask, rBX);
+  }
 }
 
 /* For dumping instructions */
@@ -350,10 +354,11 @@
 }
 
 /* Clobber all regs that might be used by an external C call */
-void X86Mir2Lir::ClobberCalleeSave() {
+void X86Mir2Lir::ClobberCallerSave() {
   Clobber(rAX);
   Clobber(rCX);
   Clobber(rDX);
+  Clobber(rBX);
 }
 
 RegLocation X86Mir2Lir::GetReturnWideAlt() {
diff --git a/compiler/dex/quick/x86/x86_dex_file_method_inliner.cc b/compiler/dex/quick/x86/x86_dex_file_method_inliner.cc
deleted file mode 100644
index b788c3c..0000000
--- a/compiler/dex/quick/x86/x86_dex_file_method_inliner.cc
+++ /dev/null
@@ -1,111 +0,0 @@
-/*
- * Copyright (C) 2013 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 "base/logging.h"
-#include "base/macros.h"
-#include "dex/compiler_enums.h"
-
-#include "x86_dex_file_method_inliner.h"
-
-namespace art {
-
-const DexFileMethodInliner::IntrinsicDef X86DexFileMethodInliner::kIntrinsicMethods[] = {
-#define INTRINSIC(c, n, p, o, d) \
-    { { kClassCache ## c, kNameCache ## n, kProtoCache ## p }, { o, d } }
-
-    INTRINSIC(JavaLangDouble, DoubleToRawLongBits, D_J, kIntrinsicDoubleCvt, 0),
-    INTRINSIC(JavaLangDouble, LongBitsToDouble, J_D, kIntrinsicDoubleCvt, 0),
-    INTRINSIC(JavaLangFloat, FloatToRawIntBits, F_I, kIntrinsicFloatCvt, 0),
-    INTRINSIC(JavaLangFloat, IntBitsToFloat, I_F, kIntrinsicFloatCvt, 0),
-
-    INTRINSIC(JavaLangInteger, ReverseBytes, I_I, kIntrinsicReverseBytes, kWord),
-    INTRINSIC(JavaLangLong, ReverseBytes, J_J, kIntrinsicReverseBytes, kLong),
-    INTRINSIC(JavaLangShort, ReverseBytes, S_S, kIntrinsicReverseBytes, kSignedHalf),
-
-    INTRINSIC(JavaLangMath,       Abs, I_I, kIntrinsicAbsInt, 0),
-    INTRINSIC(JavaLangStrictMath, Abs, I_I, kIntrinsicAbsInt, 0),
-    INTRINSIC(JavaLangMath,       Abs, J_J, kIntrinsicAbsLong, 0),
-    INTRINSIC(JavaLangStrictMath, Abs, J_J, kIntrinsicAbsLong, 0),
-    INTRINSIC(JavaLangMath,       Min, II_I, kIntrinsicMinMaxInt, kIntrinsicFlagMin),
-    INTRINSIC(JavaLangStrictMath, Min, II_I, kIntrinsicMinMaxInt, kIntrinsicFlagMin),
-    INTRINSIC(JavaLangMath,       Max, II_I, kIntrinsicMinMaxInt, kIntrinsicFlagMax),
-    INTRINSIC(JavaLangStrictMath, Max, II_I, kIntrinsicMinMaxInt, kIntrinsicFlagMax),
-    // INTRINSIC(JavaLangMath,       Sqrt, D_D, kIntrinsicSqrt, 0),
-    // INTRINSIC(JavaLangStrictMath, Sqrt, D_D, kIntrinsicSqrt, 0),
-
-    INTRINSIC(JavaLangString, CharAt, I_C, kIntrinsicCharAt, 0),
-    INTRINSIC(JavaLangString, CompareTo, String_I, kIntrinsicCompareTo, 0),
-    INTRINSIC(JavaLangString, IsEmpty, _Z, kIntrinsicIsEmptyOrLength, kIntrinsicFlagIsEmpty),
-    INTRINSIC(JavaLangString, IndexOf, II_I, kIntrinsicIndexOf, kIntrinsicFlagNone),
-    INTRINSIC(JavaLangString, IndexOf, I_I, kIntrinsicIndexOf, kIntrinsicFlagBase0),
-    INTRINSIC(JavaLangString, Length, _I, kIntrinsicIsEmptyOrLength, kIntrinsicFlagLength),
-
-    INTRINSIC(JavaLangThread, CurrentThread, _Thread, kIntrinsicCurrentThread, 0),
-
-    INTRINSIC(LibcoreIoMemory, PeekByte, J_B, kIntrinsicPeek, kSignedByte),
-    INTRINSIC(LibcoreIoMemory, PeekIntNative, J_I, kIntrinsicPeek, kWord),
-    INTRINSIC(LibcoreIoMemory, PeekLongNative, J_J, kIntrinsicPeek, kLong),
-    INTRINSIC(LibcoreIoMemory, PeekShortNative, J_S, kIntrinsicPeek, kSignedHalf),
-    INTRINSIC(LibcoreIoMemory, PokeByte, JB_V, kIntrinsicPoke, kSignedByte),
-    INTRINSIC(LibcoreIoMemory, PokeIntNative, JI_V, kIntrinsicPoke, kWord),
-    INTRINSIC(LibcoreIoMemory, PokeLongNative, JJ_V, kIntrinsicPoke, kLong),
-    INTRINSIC(LibcoreIoMemory, PokeShortNative, JS_V, kIntrinsicPoke, kSignedHalf),
-
-    // INTRINSIC(SunMiscUnsafe, CompareAndSwapInt, ObjectJII_Z, kIntrinsicCas,
-    //           kIntrinsicFlagNone),
-    // INTRINSIC(SunMiscUnsafe, CompareAndSwapLong, ObjectJJJ_Z, kIntrinsicCas,
-    //           kIntrinsicFlagIsLong),
-    // INTRINSIC(SunMiscUnsafe, CompareAndSwapObject, ObjectJObjectObject_Z, kIntrinsicCas,
-    //           kIntrinsicFlagIsObject),
-
-#define UNSAFE_GET_PUT(type, code, type_flags) \
-    INTRINSIC(SunMiscUnsafe, Get ## type, ObjectJ_ ## code, kIntrinsicUnsafeGet, \
-              type_flags & ~kIntrinsicFlagIsObject), \
-    INTRINSIC(SunMiscUnsafe, Get ## type ## Volatile, ObjectJ_ ## code, kIntrinsicUnsafeGet, \
-              (type_flags | kIntrinsicFlagIsVolatile) & ~kIntrinsicFlagIsObject), \
-    INTRINSIC(SunMiscUnsafe, Put ## type, ObjectJ ## code ## _V, kIntrinsicUnsafePut, \
-              type_flags), \
-    INTRINSIC(SunMiscUnsafe, Put ## type ## Volatile, ObjectJ ## code ## _V, kIntrinsicUnsafePut, \
-              type_flags | kIntrinsicFlagIsVolatile), \
-    INTRINSIC(SunMiscUnsafe, PutOrdered ## type, ObjectJ ## code ## _V, kIntrinsicUnsafePut, \
-              type_flags | kIntrinsicFlagIsOrdered)
-
-    UNSAFE_GET_PUT(Int, I, kIntrinsicFlagNone),
-    UNSAFE_GET_PUT(Long, J, kIntrinsicFlagIsLong),
-
-    // UNSAFE_GET_PUT(Object, Object, kIntrinsicFlagIsObject),
-    // PutObject: "TODO: fix X86, it exhausts registers for card marking."
-    INTRINSIC(SunMiscUnsafe, GetObject, ObjectJ_Object, kIntrinsicUnsafeGet,
-              kIntrinsicFlagNone),
-    INTRINSIC(SunMiscUnsafe, GetObjectVolatile, ObjectJ_Object, kIntrinsicUnsafeGet,
-              kIntrinsicFlagIsVolatile),
-#undef UNSAFE_GET_PUT
-
-#undef INTRINSIC
-};
-
-X86DexFileMethodInliner::X86DexFileMethodInliner() {
-}
-
-X86DexFileMethodInliner::~X86DexFileMethodInliner() {
-}
-
-void X86DexFileMethodInliner::FindIntrinsics(const DexFile* dex_file) {
-  IndexCache cache;
-  DoFindIntrinsics(dex_file, &cache, kIntrinsicMethods, arraysize(kIntrinsicMethods));
-}
-
-}  // namespace art
diff --git a/compiler/dex/quick/x86/x86_dex_file_method_inliner.h b/compiler/dex/quick/x86/x86_dex_file_method_inliner.h
deleted file mode 100644
index 7813e44..0000000
--- a/compiler/dex/quick/x86/x86_dex_file_method_inliner.h
+++ /dev/null
@@ -1,37 +0,0 @@
-/*
- * Copyright (C) 2013 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_DEX_QUICK_X86_X86_DEX_FILE_METHOD_INLINER_H_
-#define ART_COMPILER_DEX_QUICK_X86_X86_DEX_FILE_METHOD_INLINER_H_
-
-#include "dex/quick/dex_file_method_inliner.h"
-
-namespace art {
-
-class X86DexFileMethodInliner : public DexFileMethodInliner {
-  public:
-    X86DexFileMethodInliner();
-    ~X86DexFileMethodInliner();
-
-    void FindIntrinsics(const DexFile* dex_file);
-
-  private:
-    static const IntrinsicDef kIntrinsicMethods[];
-};
-
-}  // namespace art
-
-#endif  // ART_COMPILER_DEX_QUICK_X86_X86_DEX_FILE_METHOD_INLINER_H_
diff --git a/compiler/dex/quick/x86/x86_lir.h b/compiler/dex/quick/x86/x86_lir.h
index 3518131..5fe76fe 100644
--- a/compiler/dex/quick/x86/x86_lir.h
+++ b/compiler/dex/quick/x86/x86_lir.h
@@ -314,6 +314,7 @@
   UnaryOpcode(kX86Divmod,  DaR, DaM, DaA),
   UnaryOpcode(kX86Idivmod, DaR, DaM, DaA),
   kX86Bswap32R,
+  kX86Push32R, kX86Pop32R,
 #undef UnaryOpcode
 #define Binary0fOpCode(opcode) \
   opcode ## RR, opcode ## RM, opcode ## RA
@@ -354,7 +355,8 @@
   Binary0fOpCode(kX86Imul16),   // 16bit multiply
   Binary0fOpCode(kX86Imul32),   // 32bit multiply
   kX86CmpxchgRR, kX86CmpxchgMR, kX86CmpxchgAR,  // compare and exchange
-  kX86LockCmpxchgRR, kX86LockCmpxchgMR, kX86LockCmpxchgAR,  // locked compare and exchange
+  kX86LockCmpxchgMR, kX86LockCmpxchgAR,  // locked compare and exchange
+  kX86LockCmpxchg8bM, kX86LockCmpxchg8bA,  // locked compare and exchange
   Binary0fOpCode(kX86Movzx8),   // zero-extend 8-bit value
   Binary0fOpCode(kX86Movzx16),  // zero-extend 16-bit value
   Binary0fOpCode(kX86Movsx8),   // sign-extend 8-bit value
diff --git a/compiler/driver/compiler_driver.cc b/compiler/driver/compiler_driver.cc
index 7b42879..43ed28c 100644
--- a/compiler/driver/compiler_driver.cc
+++ b/compiler/driver/compiler_driver.cc
@@ -1430,7 +1430,7 @@
    private:
     ParallelCompilationManager* const manager_;
     const size_t end_;
-    const Callback* const callback_;
+    Callback* const callback_;
   };
 
   AtomicInteger index_;
@@ -1596,7 +1596,8 @@
   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()));
+  SirtRef<mirror::ClassLoader> class_loader(
+      soa.Self(), soa.Decode<mirror::ClassLoader*>(manager->GetClassLoader()));
   mirror::Class* klass = class_linker->ResolveType(dex_file, type_idx, dex_cache, class_loader);
 
   if (klass == NULL) {
@@ -1651,8 +1652,8 @@
   jobject jclass_loader = manager->GetClassLoader();
   SirtRef<mirror::ClassLoader> class_loader(
       soa.Self(), soa.Decode<mirror::ClassLoader*>(jclass_loader));
-  mirror::Class* klass = class_linker->FindClass(descriptor, class_loader);
-  if (klass == NULL) {
+  SirtRef<mirror::Class> klass(soa.Self(), class_linker->FindClass(descriptor, class_loader));
+  if (klass.get() == nullptr) {
     CHECK(soa.Self()->IsExceptionPending());
     soa.Self()->ClearException();
 
@@ -1669,8 +1670,8 @@
       LOG(ERROR) << "Verification failed on class " << PrettyDescriptor(descriptor)
                  << " because: " << error_msg;
     }
-  } else if (!SkipClass(jclass_loader, dex_file, klass)) {
-    CHECK(klass->IsResolved()) << PrettyClass(klass);
+  } else if (!SkipClass(jclass_loader, dex_file, klass.get())) {
+    CHECK(klass->IsResolved()) << PrettyClass(klass.get());
     class_linker->VerifyClass(klass);
 
     if (klass->IsErroneous()) {
@@ -1680,7 +1681,7 @@
     }
 
     CHECK(klass->IsCompileTimeVerified() || klass->IsErroneous())
-        << PrettyDescriptor(klass) << ": state=" << klass->GetStatus();
+        << PrettyDescriptor(klass.get()) << ": state=" << klass->GetStatus();
   }
   soa.Self()->AssertNoPendingException();
 }
@@ -2123,9 +2124,10 @@
   ScopedObjectAccess soa(Thread::Current());
   SirtRef<mirror::ClassLoader> class_loader(soa.Self(),
                                             soa.Decode<mirror::ClassLoader*>(jclass_loader));
-  mirror::Class* klass = manager->GetClassLinker()->FindClass(descriptor, class_loader);
+  SirtRef<mirror::Class> klass(soa.Self(),
+                               manager->GetClassLinker()->FindClass(descriptor, class_loader));
 
-  if (klass != NULL && !SkipClass(jclass_loader, dex_file, klass)) {
+  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
@@ -2140,7 +2142,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.
-        ObjectLock lock(soa.Self(), klass->GetClass());
+        SirtRef<mirror::Class> sirt_klass(soa.Self(), klass->GetClass());
+        ObjectLock<mirror::Class> lock(soa.Self(), &sirt_klass);
         // Attempt to initialize allowing initialization of parent classes but still not static
         // fields.
         manager->GetClassLinker()->EnsureInitialized(klass, false, true);
@@ -2164,10 +2167,11 @@
               VLOG(compiler) << "Initializing: " << descriptor;
               if (strcmp("Ljava/lang/Void;", descriptor) == 0) {
                 // Hand initialize j.l.Void to avoid Dex file operations in un-started runtime.
-                ObjectLock lock(soa.Self(), klass);
+                ObjectLock<mirror::Class> lock(soa.Self(), &klass);
                 mirror::ObjectArray<mirror::ArtField>* fields = klass->GetSFields();
                 CHECK_EQ(fields->GetLength(), 1);
-                fields->Get(0)->SetObj(klass, manager->GetClassLinker()->FindPrimitiveClass('V'));
+                fields->Get(0)->SetObj(klass.get(),
+                                       manager->GetClassLinker()->FindPrimitiveClass('V'));
                 klass->SetStatus(mirror::Class::kStatusInitialized, soa.Self());
               } else {
                 manager->GetClassLinker()->EnsureInitialized(klass, true, true);
@@ -2180,7 +2184,7 @@
       // If successfully initialized place in SSB array.
       if (klass->IsInitialized()) {
         int32_t ssb_index = klass->GetDexTypeIndex();
-        klass->GetDexCache()->GetInitializedStaticStorage()->Set(ssb_index, klass);
+        klass->GetDexCache()->GetInitializedStaticStorage()->Set(ssb_index, klass.get());
       }
     }
     // Record the final class status if necessary.
diff --git a/compiler/image_test.cc b/compiler/image_test.cc
index c71cc97..3406fe6 100644
--- a/compiler/image_test.cc
+++ b/compiler/image_test.cc
@@ -152,14 +152,14 @@
     const DexFile::ClassDef& class_def = dex->GetClassDef(i);
     const char* descriptor = dex->GetClassDescriptor(class_def);
     mirror::Class* klass = class_linker_->FindSystemClass(descriptor);
-    EXPECT_TRUE(klass != NULL) << descriptor;
-    EXPECT_LT(image_begin, reinterpret_cast<byte*>(klass)) << descriptor;
+    EXPECT_TRUE(klass != nullptr) << descriptor;
     if (image_classes.find(descriptor) != image_classes.end()) {
-      // image classes should be located before the end of the image.
+      // Image classes should be located inside the image.
+      EXPECT_LT(image_begin, reinterpret_cast<byte*>(klass)) << descriptor;
       EXPECT_LT(reinterpret_cast<byte*>(klass), image_end) << descriptor;
     } else {
-      // non image classes should be in a space after the image.
-      EXPECT_GT(reinterpret_cast<byte*>(klass), image_end) << descriptor;
+      EXPECT_TRUE(reinterpret_cast<byte*>(klass) >= image_end ||
+                  reinterpret_cast<byte*>(klass) < image_begin) << descriptor;
     }
     EXPECT_TRUE(Monitor::IsValidLockWord(klass->GetLockWord()));
   }
diff --git a/compiler/image_writer.cc b/compiler/image_writer.cc
index 90e2c65..02654ad 100644
--- a/compiler/image_writer.cc
+++ b/compiler/image_writer.cc
@@ -630,10 +630,10 @@
       copy->SetEntryPointFromCompiledCode(GetOatAddress(quick_to_interpreter_bridge_offset_));
 #endif
       copy->SetEntryPointFromInterpreter(reinterpret_cast<EntryPointFromInterpreter*>
-      (GetOatAddress(interpreter_to_interpreter_bridge_offset_)));
+      (const_cast<byte*>(GetOatAddress(interpreter_to_interpreter_bridge_offset_))));
     } else {
       copy->SetEntryPointFromInterpreter(reinterpret_cast<EntryPointFromInterpreter*>
-      (GetOatAddress(interpreter_to_compiled_code_bridge_offset_)));
+      (const_cast<byte*>(GetOatAddress(interpreter_to_compiled_code_bridge_offset_))));
       // Use original code if it exists. Otherwise, set the code pointer to the resolution
       // trampoline.
       const byte* code = GetOatAddress(orig->GetOatCodeOffset());
diff --git a/compiler/leb128_encoder.h b/compiler/leb128_encoder.h
index e9a1c32..6766683 100644
--- a/compiler/leb128_encoder.h
+++ b/compiler/leb128_encoder.h
@@ -18,33 +18,79 @@
 #define ART_COMPILER_LEB128_ENCODER_H_
 
 #include "base/macros.h"
+#include "leb128.h"
 
 namespace art {
 
+static inline uint8_t* EncodeUnsignedLeb128(uint8_t* dest, uint32_t value) {
+  uint8_t out = value & 0x7f;
+  value >>= 7;
+  while (value != 0) {
+    *dest++ = out | 0x80;
+    out = value & 0x7f;
+    value >>= 7;
+  }
+  *dest++ = out;
+  return dest;
+}
+
+static inline uint8_t* EncodeSignedLeb128(uint8_t* dest, int32_t value) {
+  uint32_t extra_bits = static_cast<uint32_t>(value ^ (value >> 31)) >> 6;
+  uint8_t out = value & 0x7f;
+  while (extra_bits != 0u) {
+    *dest++ = out | 0x80;
+    value >>= 7;
+    out = value & 0x7f;
+    extra_bits >>= 7;
+  }
+  *dest++ = out;
+  return dest;
+}
+
 // An encoder with an API similar to vector<uint32_t> where the data is captured in ULEB128 format.
-class UnsignedLeb128EncodingVector {
+class Leb128EncodingVector {
  public:
-  UnsignedLeb128EncodingVector() {
+  Leb128EncodingVector() {
   }
 
-  void PushBack(uint32_t value) {
-    bool done = false;
-    do {
-      uint8_t out = value & 0x7f;
-      if (out != value) {
-        data_.push_back(out | 0x80);
-        value >>= 7;
-      } else {
-        data_.push_back(out);
-        done = true;
-      }
-    } while (!done);
+  void Reserve(uint32_t size) {
+    data_.reserve(size);
+  }
+
+  void PushBackUnsigned(uint32_t value) {
+    uint8_t out = value & 0x7f;
+    value >>= 7;
+    while (value != 0) {
+      data_.push_back(out | 0x80);
+      out = value & 0x7f;
+      value >>= 7;
+    }
+    data_.push_back(out);
   }
 
   template<typename It>
-  void InsertBack(It cur, It end) {
+  void InsertBackUnsigned(It cur, It end) {
     for (; cur != end; ++cur) {
-      PushBack(*cur);
+      PushBackUnsigned(*cur);
+    }
+  }
+
+  void PushBackSigned(int32_t value) {
+    uint32_t extra_bits = static_cast<uint32_t>(value ^ (value >> 31)) >> 6;
+    uint8_t out = value & 0x7f;
+    while (extra_bits != 0u) {
+      data_.push_back(out | 0x80);
+      value >>= 7;
+      out = value & 0x7f;
+      extra_bits >>= 7;
+    }
+    data_.push_back(out);
+  }
+
+  template<typename It>
+  void InsertBackSigned(It cur, It end) {
+    for (; cur != end; ++cur) {
+      PushBackSigned(*cur);
     }
   }
 
@@ -55,7 +101,7 @@
  private:
   std::vector<uint8_t> data_;
 
-  DISALLOW_COPY_AND_ASSIGN(UnsignedLeb128EncodingVector);
+  DISALLOW_COPY_AND_ASSIGN(Leb128EncodingVector);
 };
 
 }  // namespace art
diff --git a/compiler/leb128_encoder_test.cc b/compiler/leb128_encoder_test.cc
index 4fa8075..c63dfa2 100644
--- a/compiler/leb128_encoder_test.cc
+++ b/compiler/leb128_encoder_test.cc
@@ -42,11 +42,62 @@
     {0xFFFFFFFF, {0xFF, 0xFF, 0xFF, 0xFF, 0xF}},
 };
 
-TEST_F(Leb128Test, Singles) {
+struct DecodeSignedLeb128TestCase {
+  int32_t decoded;
+  uint8_t leb128_data[5];
+};
+
+static DecodeSignedLeb128TestCase sleb128_tests[] = {
+    {0,          {0, 0, 0, 0, 0}},
+    {1,          {1, 0, 0, 0, 0}},
+    {0x3F,       {0x3F, 0, 0, 0, 0}},
+    {0x40,       {0xC0, 0 /* sign bit */, 0, 0, 0}},
+    {0x41,       {0xC1, 0 /* sign bit */, 0, 0, 0}},
+    {0x80,       {0x80, 1, 0, 0, 0}},
+    {0xFF,       {0xFF, 1, 0, 0, 0}},
+    {0x1FFF,     {0xFF, 0x3F, 0, 0, 0}},
+    {0x2000,     {0x80, 0xC0, 0 /* sign bit */, 0, 0}},
+    {0x2001,     {0x81, 0xC0, 0 /* sign bit */, 0, 0}},
+    {0x2081,     {0x81, 0xC1, 0 /* sign bit */, 0, 0}},
+    {0x4000,     {0x80, 0x80, 1, 0, 0}},
+    {0x0FFFFF,   {0xFF, 0xFF, 0x3F, 0, 0}},
+    {0x100000,   {0x80, 0x80, 0xC0, 0 /* sign bit */, 0}},
+    {0x100001,   {0x81, 0x80, 0xC0, 0 /* sign bit */, 0}},
+    {0x100081,   {0x81, 0x81, 0xC0, 0 /* sign bit */, 0}},
+    {0x104081,   {0x81, 0x81, 0xC1, 0 /* sign bit */, 0}},
+    {0x200000,   {0x80, 0x80, 0x80, 1, 0}},
+    {0x7FFFFFF,  {0xFF, 0xFF, 0xFF, 0x3F, 0}},
+    {0x8000000,  {0x80, 0x80, 0x80, 0xC0, 0 /* sign bit */}},
+    {0x8000001,  {0x81, 0x80, 0x80, 0xC0, 0 /* sign bit */}},
+    {0x8000081,  {0x81, 0x81, 0x80, 0xC0, 0 /* sign bit */}},
+    {0x8004081,  {0x81, 0x81, 0x81, 0xC0, 0 /* sign bit */}},
+    {0x8204081,  {0x81, 0x81, 0x81, 0xC1, 0 /* sign bit */}},
+    {0x0FFFFFFF, {0xFF, 0xFF, 0xFF, 0xFF, 0 /* sign bit */}},
+    {0x10000000, {0x80, 0x80, 0x80, 0x80, 1}},
+    {0x7FFFFFFF, {0xFF, 0xFF, 0xFF, 0xFF, 0x7}},
+    {-1,         {0x7F, 0, 0, 0, 0}},
+    {-2,         {0x7E, 0, 0, 0, 0}},
+    {-0x3F,      {0x41, 0, 0, 0, 0}},
+    {-0x40,      {0x40, 0, 0, 0, 0}},
+    {-0x41,      {0xBF, 0x7F, 0, 0, 0}},
+    {-0x80,      {0x80, 0x7F, 0, 0, 0}},
+    {-0x81,      {0xFF, 0x7E, 0, 0, 0}},
+    {-0x00002000, {0x80, 0x40, 0, 0, 0}},
+    {-0x00002001, {0xFF, 0xBF, 0x7F, 0, 0}},
+    {-0x00100000, {0x80, 0x80, 0x40, 0, 0}},
+    {-0x00100001, {0xFF, 0xFF, 0xBF, 0x7F, 0}},
+    {-0x08000000, {0x80, 0x80, 0x80, 0x40, 0}},
+    {-0x08000001, {0xFF, 0xFF, 0xFF, 0xBF, 0x7F}},
+    {-0x20000000, {0x80, 0x80, 0x80, 0x80, 0x7E}},
+    {(-1) << 31, {0x80, 0x80, 0x80, 0x80, 0x78}},
+};
+
+TEST_F(Leb128Test, UnsignedSinglesVector) {
   // Test individual encodings.
   for (size_t i = 0; i < arraysize(uleb128_tests); ++i) {
-    UnsignedLeb128EncodingVector builder;
-    builder.PushBack(uleb128_tests[i].decoded);
+    Leb128EncodingVector builder;
+    builder.PushBackUnsigned(uleb128_tests[i].decoded);
+    EXPECT_EQ(UnsignedLeb128Size(uleb128_tests[i].decoded), builder.GetData().size());
     const uint8_t* data_ptr = &uleb128_tests[i].leb128_data[0];
     const uint8_t* encoded_data_ptr = &builder.GetData()[0];
     for (size_t j = 0; j < 5; ++j) {
@@ -60,33 +111,158 @@
   }
 }
 
-TEST_F(Leb128Test, Stream) {
-  // Encode a number of entries.
-  UnsignedLeb128EncodingVector builder;
+TEST_F(Leb128Test, UnsignedSingles) {
+  // Test individual encodings.
   for (size_t i = 0; i < arraysize(uleb128_tests); ++i) {
-    builder.PushBack(uleb128_tests[i].decoded);
+    uint8_t encoded_data[5];
+    uint8_t* end = EncodeUnsignedLeb128(encoded_data, uleb128_tests[i].decoded);
+    size_t data_size = static_cast<size_t>(end - encoded_data);
+    EXPECT_EQ(UnsignedLeb128Size(uleb128_tests[i].decoded), data_size);
+    const uint8_t* data_ptr = &uleb128_tests[i].leb128_data[0];
+    for (size_t j = 0; j < 5; ++j) {
+      if (j < data_size) {
+        EXPECT_EQ(data_ptr[j], encoded_data[j]) << " i = " << i << " j = " << j;
+      } else {
+        EXPECT_EQ(data_ptr[j], 0U) << " i = " << i << " j = " << j;
+      }
+    }
+    EXPECT_EQ(DecodeUnsignedLeb128(&data_ptr), uleb128_tests[i].decoded) << " i = " << i;
+  }
+}
+
+TEST_F(Leb128Test, UnsignedStreamVector) {
+  // Encode a number of entries.
+  Leb128EncodingVector builder;
+  for (size_t i = 0; i < arraysize(uleb128_tests); ++i) {
+    builder.PushBackUnsigned(uleb128_tests[i].decoded);
   }
   const uint8_t* encoded_data_ptr = &builder.GetData()[0];
   for (size_t i = 0; i < arraysize(uleb128_tests); ++i) {
     const uint8_t* data_ptr = &uleb128_tests[i].leb128_data[0];
-    for (size_t j = 0; j < 5; ++j) {
-      if (data_ptr[j] != 0) {
-        EXPECT_EQ(data_ptr[j], encoded_data_ptr[j]) << " i = " << i << " j = " << j;
-      }
+    for (size_t j = 0; j < UnsignedLeb128Size(uleb128_tests[i].decoded); ++j) {
+      EXPECT_EQ(data_ptr[j], encoded_data_ptr[j]) << " i = " << i << " j = " << j;
+    }
+    for (size_t j = UnsignedLeb128Size(uleb128_tests[i].decoded); j < 5; ++j) {
+      EXPECT_EQ(data_ptr[j], 0) << " i = " << i << " j = " << j;
     }
     EXPECT_EQ(DecodeUnsignedLeb128(&encoded_data_ptr), uleb128_tests[i].decoded) << " i = " << i;
   }
+  EXPECT_EQ(builder.GetData().size(),
+            static_cast<size_t>(encoded_data_ptr - &builder.GetData()[0]));
+}
+
+TEST_F(Leb128Test, UnsignedStream) {
+  // Encode a number of entries.
+  uint8_t encoded_data[5 * arraysize(uleb128_tests)];
+  uint8_t* end = encoded_data;
+  for (size_t i = 0; i < arraysize(uleb128_tests); ++i) {
+    end = EncodeUnsignedLeb128(end, uleb128_tests[i].decoded);
+  }
+  size_t data_size = static_cast<size_t>(end - encoded_data);
+  const uint8_t* encoded_data_ptr = encoded_data;
+  for (size_t i = 0; i < arraysize(uleb128_tests); ++i) {
+    const uint8_t* data_ptr = &uleb128_tests[i].leb128_data[0];
+    for (size_t j = 0; j < UnsignedLeb128Size(uleb128_tests[i].decoded); ++j) {
+      EXPECT_EQ(data_ptr[j], encoded_data_ptr[j]) << " i = " << i << " j = " << j;
+    }
+    for (size_t j = UnsignedLeb128Size(uleb128_tests[i].decoded); j < 5; ++j) {
+      EXPECT_EQ(data_ptr[j], 0) << " i = " << i << " j = " << j;
+    }
+    EXPECT_EQ(DecodeUnsignedLeb128(&encoded_data_ptr), uleb128_tests[i].decoded) << " i = " << i;
+  }
+  EXPECT_EQ(data_size, static_cast<size_t>(encoded_data_ptr - encoded_data));
+}
+
+TEST_F(Leb128Test, SignedSinglesVector) {
+  // Test individual encodings.
+  for (size_t i = 0; i < arraysize(sleb128_tests); ++i) {
+    Leb128EncodingVector builder;
+    builder.PushBackSigned(sleb128_tests[i].decoded);
+    EXPECT_EQ(SignedLeb128Size(sleb128_tests[i].decoded), builder.GetData().size());
+    const uint8_t* data_ptr = &sleb128_tests[i].leb128_data[0];
+    const uint8_t* encoded_data_ptr = &builder.GetData()[0];
+    for (size_t j = 0; j < 5; ++j) {
+      if (j < builder.GetData().size()) {
+        EXPECT_EQ(data_ptr[j], encoded_data_ptr[j]) << " i = " << i << " j = " << j;
+      } else {
+        EXPECT_EQ(data_ptr[j], 0U) << " i = " << i << " j = " << j;
+      }
+    }
+    EXPECT_EQ(DecodeSignedLeb128(&data_ptr), sleb128_tests[i].decoded) << " i = " << i;
+  }
+}
+
+TEST_F(Leb128Test, SignedSingles) {
+  // Test individual encodings.
+  for (size_t i = 0; i < arraysize(sleb128_tests); ++i) {
+    uint8_t encoded_data[5];
+    uint8_t* end = EncodeSignedLeb128(encoded_data, sleb128_tests[i].decoded);
+    size_t data_size = static_cast<size_t>(end - encoded_data);
+    EXPECT_EQ(SignedLeb128Size(sleb128_tests[i].decoded), data_size);
+    const uint8_t* data_ptr = &sleb128_tests[i].leb128_data[0];
+    for (size_t j = 0; j < 5; ++j) {
+      if (j < data_size) {
+        EXPECT_EQ(data_ptr[j], encoded_data[j]) << " i = " << i << " j = " << j;
+      } else {
+        EXPECT_EQ(data_ptr[j], 0U) << " i = " << i << " j = " << j;
+      }
+    }
+    EXPECT_EQ(DecodeSignedLeb128(&data_ptr), sleb128_tests[i].decoded) << " i = " << i;
+  }
+}
+
+TEST_F(Leb128Test, SignedStreamVector) {
+  // Encode a number of entries.
+  Leb128EncodingVector builder;
+  for (size_t i = 0; i < arraysize(sleb128_tests); ++i) {
+    builder.PushBackSigned(sleb128_tests[i].decoded);
+  }
+  const uint8_t* encoded_data_ptr = &builder.GetData()[0];
+  for (size_t i = 0; i < arraysize(sleb128_tests); ++i) {
+    const uint8_t* data_ptr = &sleb128_tests[i].leb128_data[0];
+    for (size_t j = 0; j < SignedLeb128Size(sleb128_tests[i].decoded); ++j) {
+      EXPECT_EQ(data_ptr[j], encoded_data_ptr[j]) << " i = " << i << " j = " << j;
+    }
+    for (size_t j = SignedLeb128Size(sleb128_tests[i].decoded); j < 5; ++j) {
+      EXPECT_EQ(data_ptr[j], 0) << " i = " << i << " j = " << j;
+    }
+    EXPECT_EQ(DecodeSignedLeb128(&encoded_data_ptr), sleb128_tests[i].decoded) << " i = " << i;
+  }
+  EXPECT_EQ(builder.GetData().size(),
+            static_cast<size_t>(encoded_data_ptr - &builder.GetData()[0]));
+}
+
+TEST_F(Leb128Test, SignedStream) {
+  // Encode a number of entries.
+  uint8_t encoded_data[5 * arraysize(sleb128_tests)];
+  uint8_t* end = encoded_data;
+  for (size_t i = 0; i < arraysize(sleb128_tests); ++i) {
+    end = EncodeSignedLeb128(end, sleb128_tests[i].decoded);
+  }
+  size_t data_size = static_cast<size_t>(end - encoded_data);
+  const uint8_t* encoded_data_ptr = encoded_data;
+  for (size_t i = 0; i < arraysize(sleb128_tests); ++i) {
+    const uint8_t* data_ptr = &sleb128_tests[i].leb128_data[0];
+    for (size_t j = 0; j < SignedLeb128Size(sleb128_tests[i].decoded); ++j) {
+      EXPECT_EQ(data_ptr[j], encoded_data_ptr[j]) << " i = " << i << " j = " << j;
+    }
+    for (size_t j = SignedLeb128Size(sleb128_tests[i].decoded); j < 5; ++j) {
+      EXPECT_EQ(data_ptr[j], 0) << " i = " << i << " j = " << j;
+    }
+    EXPECT_EQ(DecodeSignedLeb128(&encoded_data_ptr), sleb128_tests[i].decoded) << " i = " << i;
+  }
+  EXPECT_EQ(data_size, static_cast<size_t>(encoded_data_ptr - encoded_data));
 }
 
 TEST_F(Leb128Test, Speed) {
   UniquePtr<Histogram<uint64_t> > enc_hist(new Histogram<uint64_t>("Leb128EncodeSpeedTest", 5));
   UniquePtr<Histogram<uint64_t> > dec_hist(new Histogram<uint64_t>("Leb128DecodeSpeedTest", 5));
-  UnsignedLeb128EncodingVector builder;
+  Leb128EncodingVector builder;
   // Push back 1024 chunks of 1024 values measuring encoding speed.
   uint64_t last_time = NanoTime();
   for (size_t i = 0; i < 1024; i++) {
     for (size_t j = 0; j < 1024; j++) {
-      builder.PushBack((i * 1024) + j);
+      builder.PushBackUnsigned((i * 1024) + j);
     }
     uint64_t cur_time = NanoTime();
     enc_hist->AddValue(cur_time - last_time);
diff --git a/compiler/utils/arm/assembler_arm.cc b/compiler/utils/arm/assembler_arm.cc
index f0d11d8..828dffa 100644
--- a/compiler/utils/arm/assembler_arm.cc
+++ b/compiler/utils/arm/assembler_arm.cc
@@ -1742,17 +1742,8 @@
 void ArmAssembler::MemoryBarrier(ManagedRegister mscratch) {
   CHECK_EQ(mscratch.AsArm().AsCoreRegister(), R12);
 #if ANDROID_SMP != 0
-#if defined(__ARM_HAVE_DMB)
   int32_t encoding = 0xf57ff05f;  // dmb
   Emit(encoding);
-#elif  defined(__ARM_HAVE_LDREX_STREX)
-  LoadImmediate(R12, 0);
-  int32_t encoding = 0xee07cfba;  // mcr p15, 0, r12, c7, c10, 5
-  Emit(encoding);
-#else
-  LoadImmediate(R12, 0xffff0fa0);  // kuser_memory_barrier
-  blx(R12);
-#endif
 #endif
 }
 
diff --git a/dex2oat/dex2oat.cc b/dex2oat/dex2oat.cc
index 8b232700..28d6649 100644
--- a/dex2oat/dex2oat.cc
+++ b/dex2oat/dex2oat.cc
@@ -213,7 +213,7 @@
     if (zip_archive.get() == NULL) {
       return NULL;
     }
-    UniquePtr<ZipEntry> zip_entry(zip_archive->Find(image_classes_filename));
+    UniquePtr<ZipEntry> zip_entry(zip_archive->Find(image_classes_filename, error_msg));
     if (zip_entry.get() == NULL) {
       *error_msg = StringPrintf("Failed to find '%s' within '%s': %s", image_classes_filename,
                                 zip_filename, error_msg->c_str());
diff --git a/disassembler/disassembler_x86.cc b/disassembler/disassembler_x86.cc
index 9ed65cd..1d53ca8 100644
--- a/disassembler/disassembler_x86.cc
+++ b/disassembler/disassembler_x86.cc
@@ -208,7 +208,9 @@
     reg_in_opcode = true;
     break;
   case 0x68: opcode << "push"; immediate_bytes = 4; break;
+  case 0x69: opcode << "imul"; load = true; has_modrm = true; immediate_bytes = 4; break;
   case 0x6A: opcode << "push"; immediate_bytes = 1; break;
+  case 0x6B: opcode << "imul"; load = true; has_modrm = true; immediate_bytes = 1; break;
   case 0x70: case 0x71: case 0x72: case 0x73: case 0x74: case 0x75: case 0x76: case 0x77:
   case 0x78: case 0x79: case 0x7A: case 0x7B: case 0x7C: case 0x7D: case 0x7E: case 0x7F:
     static const char* condition_codes[] =
@@ -515,11 +517,19 @@
           no_ops = true;
         }
         break;
+      case 0xAF: opcode << "imul"; has_modrm = true; load = true; break;
       case 0xB1: opcode << "cmpxchg"; has_modrm = true; store = true; break;
       case 0xB6: opcode << "movzxb"; has_modrm = true; load = true; break;
       case 0xB7: opcode << "movzxw"; has_modrm = true; load = true; break;
       case 0xBE: opcode << "movsxb"; has_modrm = true; load = true; break;
       case 0xBF: opcode << "movsxw"; has_modrm = true; load = true; break;
+      case 0xC7:
+        static const char* x0FxC7_opcodes[] = { "unknown-0f-c7", "cmpxchg8b", "unknown-0f-c7", "unknown-0f-c7", "unknown-0f-c7", "unknown-0f-c7", "unknown-0f-c7", "unknown-0f-c7" };
+        modrm_opcodes = x0FxC7_opcodes;
+        has_modrm = true;
+        reg_is_opcode = true;
+        store = true;
+        break;
       case 0xC8: case 0xC9: case 0xCA: case 0xCB: case 0xCC: case 0xCD: case 0xCE: case 0xCF:
         opcode << "bswap";
         reg_in_opcode = true;
@@ -587,6 +597,20 @@
     reg_is_opcode = true;
     break;
   case 0xCC: opcode << "int 3"; break;
+  case 0xD9:
+    static const char* d9_opcodes[] = {"flds", "unknown-d9", "fsts", "fstps", "fldenv", "fldcw", "fnstenv", "fnstcw"};
+    modrm_opcodes = d9_opcodes;
+    store = true;
+    has_modrm = true;
+    reg_is_opcode = true;
+    break;
+  case 0xDD:
+    static const char* dd_opcodes[] = {"fldl", "fisttp", "fstl", "fstpl", "frstor", "unknown-dd", "fnsave", "fnstsw"};
+    modrm_opcodes = dd_opcodes;
+    store = true;
+    has_modrm = true;
+    reg_is_opcode = true;
+    break;
   case 0xE8: opcode << "call"; branch_bytes = 4; break;
   case 0xE9: opcode << "jmp"; branch_bytes = 4; break;
   case 0xEB: opcode << "jmp"; branch_bytes = 1; break;
diff --git a/runtime/Android.mk b/runtime/Android.mk
index b471d84..a602c83 100644
--- a/runtime/Android.mk
+++ b/runtime/Android.mk
@@ -355,10 +355,10 @@
   LOCAL_SHARED_LIBRARIES += liblog libnativehelper
   LOCAL_SHARED_LIBRARIES += libbacktrace # native stack trace support
   ifeq ($$(art_target_or_host),target)
-    LOCAL_SHARED_LIBRARIES += libcutils libz libdl libselinux
+    LOCAL_SHARED_LIBRARIES += libcutils libdl libselinux libutils
+    LOCAL_STATIC_LIBRARIES := libziparchive libz
   else # host
-    LOCAL_STATIC_LIBRARIES += libcutils
-    LOCAL_SHARED_LIBRARIES += libz-host
+    LOCAL_STATIC_LIBRARIES += libcutils libziparchive-host libz libutils
     LOCAL_LDLIBS += -ldl -lpthread
     ifeq ($(HOST_OS),linux)
       LOCAL_LDLIBS += -lrt
diff --git a/runtime/base/macros.h b/runtime/base/macros.h
index 00a530a..cf7029a 100644
--- a/runtime/base/macros.h
+++ b/runtime/base/macros.h
@@ -140,6 +140,13 @@
 #define ALWAYS_INLINE  __attribute__ ((always_inline))
 #endif
 
+#ifdef __clang__
+/* clang doesn't like attributes on lambda functions */
+#define ALWAYS_INLINE_LAMBDA
+#else
+#define ALWAYS_INLINE_LAMBDA ALWAYS_INLINE
+#endif
+
 #if defined (__APPLE__)
 #define HOT_ATTR
 #define COLD_ATTR
diff --git a/runtime/base/timing_logger.cc b/runtime/base/timing_logger.cc
index c8dee6d..fe18f66 100644
--- a/runtime/base/timing_logger.cc
+++ b/runtime/base/timing_logger.cc
@@ -31,6 +31,8 @@
 
 namespace art {
 
+constexpr size_t CumulativeLogger::kLowMemoryBucketCount;
+constexpr size_t CumulativeLogger::kDefaultBucketCount;
 CumulativeLogger::CumulativeLogger(const std::string& name)
     : name_(name),
       lock_name_("CumulativeLoggerLock" + name),
@@ -43,6 +45,7 @@
 }
 
 void CumulativeLogger::SetName(const std::string& name) {
+  MutexLock mu(Thread::Current(), lock_);
   name_.assign(name);
 }
 
@@ -61,6 +64,7 @@
 }
 
 uint64_t CumulativeLogger::GetTotalNs() const {
+  MutexLock mu(Thread::Current(), lock_);
   return GetTotalTime() * kAdjust;
 }
 
diff --git a/runtime/base/timing_logger.h b/runtime/base/timing_logger.h
index c1ff0a3..b0bcf10 100644
--- a/runtime/base/timing_logger.h
+++ b/runtime/base/timing_logger.h
@@ -31,16 +31,15 @@
 class CumulativeLogger {
  public:
   explicit CumulativeLogger(const std::string& name);
-  void prepare_stats();
   ~CumulativeLogger();
   void Start();
-  void End();
-  void Reset();
+  void End() LOCKS_EXCLUDED(lock_);
+  void Reset() LOCKS_EXCLUDED(lock_);
   void Dump(std::ostream& os) LOCKS_EXCLUDED(lock_);
   uint64_t GetTotalNs() const;
   // Allow the name to be modified, particularly when the cumulative logger is a field within a
   // parent class that is unable to determine the "name" of a sub-class.
-  void SetName(const std::string& name);
+  void SetName(const std::string& name) LOCKS_EXCLUDED(lock_);
   void AddLogger(const TimingLogger& logger) LOCKS_EXCLUDED(lock_);
   size_t GetIterations() const;
 
diff --git a/runtime/class_linker.cc b/runtime/class_linker.cc
index 500cb59..643c183 100644
--- a/runtime/class_linker.cc
+++ b/runtime/class_linker.cc
@@ -530,7 +530,8 @@
   for (size_t i = 0; i < ClassLinker::kClassRootsMax; ++i) {
     mirror::Class* c = GetClassRoot(ClassRoot(i));
     if (!c->IsArrayClass() && !c->IsPrimitive()) {
-      EnsureInitialized(GetClassRoot(ClassRoot(i)), true, true);
+      SirtRef<mirror::Class> sirt_class(self, GetClassRoot(ClassRoot(i)));
+      EnsureInitialized(sirt_class, true, true);
       self->AssertNoPendingException();
     }
   }
@@ -673,18 +674,19 @@
 }
 
 const OatFile* ClassLinker::FindOpenedOatFileForDexFile(const DexFile& dex_file) {
-  return FindOpenedOatFileFromDexLocation(dex_file.GetLocation().c_str(),
-                                          dex_file.GetLocationChecksum());
+  const char* dex_location = dex_file.GetLocation().c_str();
+  uint32_t dex_location_checksum = dex_file.GetLocationChecksum();
+  return FindOpenedOatFileFromDexLocation(dex_location, &dex_location_checksum);
 }
 
 const OatFile* ClassLinker::FindOpenedOatFileFromDexLocation(const char* dex_location,
-                                                             uint32_t dex_location_checksum) {
+                                                             const uint32_t* const dex_location_checksum) {
   ReaderMutexLock mu(Thread::Current(), dex_lock_);
   for (size_t i = 0; i < oat_files_.size(); i++) {
     const OatFile* oat_file = oat_files_[i];
     DCHECK(oat_file != NULL);
     const OatFile::OatDexFile* oat_dex_file = oat_file->GetOatDexFile(dex_location,
-                                                                      &dex_location_checksum,
+                                                                      dex_location_checksum,
                                                                       false);
     if (oat_dex_file != NULL) {
       return oat_file;
@@ -943,13 +945,13 @@
 }
 
 const DexFile* ClassLinker::FindDexFileInOatFileFromDexLocation(const char* dex_location,
-                                                                uint32_t dex_location_checksum,
+                                                                const uint32_t* const dex_location_checksum,
                                                                 std::string* error_msg) {
   const OatFile* open_oat_file = FindOpenedOatFileFromDexLocation(dex_location,
                                                                   dex_location_checksum);
   if (open_oat_file != nullptr) {
     const OatFile::OatDexFile* oat_dex_file = open_oat_file->GetOatDexFile(dex_location,
-                                                                           &dex_location_checksum);
+                                                                           dex_location_checksum);
     return oat_dex_file->OpenDexFile(error_msg);
   }
 
@@ -962,6 +964,12 @@
   if (dex_file != nullptr) {
     return dex_file;
   }
+  if (dex_location_checksum == nullptr) {
+    *error_msg = StringPrintf("Failed to open oat file from %s and no classes.dex found in %s: %s",
+                              odex_filename.c_str(), dex_location, error_msg->c_str());
+    return nullptr;
+  }
+
   std::string cache_error_msg;
   std::string cache_location(GetDalvikCacheFilenameOrDie(dex_location));
   dex_file = VerifyAndOpenDexFileFromOatFile(cache_location, dex_location, &cache_error_msg,
@@ -978,7 +986,7 @@
 
   // Try to generate oat file if it wasn't found or was obsolete.
   error_msg->clear();
-  return FindOrCreateOatFileForDexLocation(dex_location, dex_location_checksum,
+  return FindOrCreateOatFileForDexLocation(dex_location, *dex_location_checksum,
                                            cache_location.c_str(), error_msg);
 }
 
@@ -1133,7 +1141,7 @@
   }
 
   {
-    ReaderMutexLock mu(self, *Locks::classlinker_classes_lock_);
+    WriterMutexLock mu(self, *Locks::classlinker_classes_lock_);
     if (!only_dirty || class_table_dirty_) {
       for (std::pair<const size_t, mirror::Class*>& it : class_table_) {
         it.second = down_cast<mirror::Class*>(visitor(it.second, arg));
@@ -1156,7 +1164,7 @@
   if (dex_cache_image_class_lookup_required_) {
     MoveImageClassesToClassTable();
   }
-  ReaderMutexLock mu(Thread::Current(), *Locks::classlinker_classes_lock_);
+  WriterMutexLock mu(Thread::Current(), *Locks::classlinker_classes_lock_);
   for (const std::pair<size_t, mirror::Class*>& it : class_table_) {
     if (!visitor(it.second, arg)) {
       return;
@@ -1249,7 +1257,10 @@
                                        size_t class_size) {
   DCHECK_GE(class_size, sizeof(mirror::Class));
   gc::Heap* heap = Runtime::Current()->GetHeap();
-  mirror::Object* k = heap->AllocNonMovableObject<true>(self, java_lang_Class, class_size);
+  mirror::Object* k =
+      kMovingClasses ?
+          heap->AllocObject<true>(self, java_lang_Class, class_size) :
+          heap->AllocNonMovableObject<true>(self, java_lang_Class, class_size);
   if (UNLIKELY(k == NULL)) {
     CHECK(self->IsExceptionPending());  // OOME.
     return NULL;
@@ -1287,21 +1298,23 @@
   DCHECK(klass != NULL);
   // Wait for the class if it has not already been linked.
   if (!klass->IsResolved() && !klass->IsErroneous()) {
-    ObjectLock lock(self, klass);
+    SirtRef<mirror::Class> sirt_class(self, klass);
+    ObjectLock<mirror::Class> lock(self, &sirt_class);
     // Check for circular dependencies between classes.
-    if (!klass->IsResolved() && klass->GetClinitThreadId() == self->GetTid()) {
-      ThrowClassCircularityError(klass);
-      klass->SetStatus(mirror::Class::kStatusError, self);
-      return NULL;
+    if (!sirt_class->IsResolved() && sirt_class->GetClinitThreadId() == self->GetTid()) {
+      ThrowClassCircularityError(sirt_class.get());
+      sirt_class->SetStatus(mirror::Class::kStatusError, self);
+      return nullptr;
     }
     // Wait for the pending initialization to complete.
-    while (!klass->IsResolved() && !klass->IsErroneous()) {
+    while (!sirt_class->IsResolved() && !sirt_class->IsErroneous()) {
       lock.WaitIgnoringInterrupts();
     }
+    klass = sirt_class.get();
   }
   if (klass->IsErroneous()) {
     ThrowEarlierClassFailure(klass);
-    return NULL;
+    return nullptr;
   }
   // Return the loaded class.  No exceptions should be pending.
   CHECK(klass->IsResolved()) << PrettyClass(klass);
@@ -1320,7 +1333,7 @@
 }
 
 mirror::Class* ClassLinker::FindClass(const char* descriptor,
-                                      SirtRef<mirror::ClassLoader>& class_loader) {
+                                      const SirtRef<mirror::ClassLoader>& class_loader) {
   DCHECK_NE(*descriptor, '\0') << "descriptor is empty string";
   Thread* self = Thread::Current();
   DCHECK(self != NULL);
@@ -1403,7 +1416,7 @@
 }
 
 mirror::Class* ClassLinker::DefineClass(const char* descriptor,
-                                        SirtRef<mirror::ClassLoader>& class_loader,
+                                        const SirtRef<mirror::ClassLoader>& class_loader,
                                         const DexFile& dex_file,
                                         const DexFile::ClassDef& dex_class_def) {
   Thread* self = Thread::Current();
@@ -1440,7 +1453,7 @@
     klass->SetStatus(mirror::Class::kStatusError, self);
     return NULL;
   }
-  ObjectLock lock(self, klass.get());
+  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));
@@ -1695,7 +1708,7 @@
   // Ignore virtual methods on the iterator.
 }
 
-static void LinkCode(SirtRef<mirror::ArtMethod>& method, const OatFile::OatClass* oat_class,
+static void LinkCode(const SirtRef<mirror::ArtMethod>& method, const OatFile::OatClass* oat_class,
                      uint32_t method_index)
     SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
   // Method shouldn't have already been linked.
@@ -1741,7 +1754,7 @@
 
 void ClassLinker::LoadClass(const DexFile& dex_file,
                             const DexFile::ClassDef& dex_class_def,
-                            SirtRef<mirror::Class>& klass,
+                            const SirtRef<mirror::Class>& klass,
                             mirror::ClassLoader* class_loader) {
   CHECK(klass.get() != NULL);
   CHECK(klass->GetDexCache() != NULL);
@@ -1861,7 +1874,8 @@
 }
 
 void ClassLinker::LoadField(const DexFile& /*dex_file*/, const ClassDataItemIterator& it,
-                            SirtRef<mirror::Class>& klass, SirtRef<mirror::ArtField>& dst) {
+                            const SirtRef<mirror::Class>& klass,
+                            const SirtRef<mirror::ArtField>& dst) {
   uint32_t field_idx = it.GetMemberIndex();
   dst->SetDexFieldIndex(field_idx);
   dst->SetDeclaringClass(klass.get());
@@ -1870,7 +1884,7 @@
 
 mirror::ArtMethod* ClassLinker::LoadMethod(Thread* self, const DexFile& dex_file,
                                            const ClassDataItemIterator& it,
-                                           SirtRef<mirror::Class>& klass) {
+                                           const SirtRef<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_);
@@ -1941,7 +1955,8 @@
   AppendToBootClassPath(dex_file, dex_cache);
 }
 
-void ClassLinker::AppendToBootClassPath(const DexFile& dex_file, SirtRef<mirror::DexCache>& dex_cache) {
+void ClassLinker::AppendToBootClassPath(const DexFile& dex_file,
+                                        const SirtRef<mirror::DexCache>& dex_cache) {
   CHECK(dex_cache.get() != NULL) << dex_file.GetLocation();
   boot_class_path_.push_back(&dex_file);
   RegisterDexFile(dex_file, dex_cache);
@@ -1962,7 +1977,8 @@
   return IsDexFileRegisteredLocked(dex_file);
 }
 
-void ClassLinker::RegisterDexFileLocked(const DexFile& dex_file, SirtRef<mirror::DexCache>& dex_cache) {
+void ClassLinker::RegisterDexFileLocked(const DexFile& dex_file,
+                                        const SirtRef<mirror::DexCache>& dex_cache) {
   dex_lock_.AssertExclusiveHeld(Thread::Current());
   CHECK(dex_cache.get() != NULL) << dex_file.GetLocation();
   CHECK(dex_cache->GetLocation()->Equals(dex_file.GetLocation()))
@@ -1994,7 +2010,8 @@
   }
 }
 
-void ClassLinker::RegisterDexFile(const DexFile& dex_file, SirtRef<mirror::DexCache>& dex_cache) {
+void ClassLinker::RegisterDexFile(const DexFile& dex_file,
+                                  const SirtRef<mirror::DexCache>& dex_cache) {
   WriterMutexLock mu(Thread::Current(), dex_lock_);
   RegisterDexFileLocked(dex_file, dex_cache);
 }
@@ -2040,11 +2057,13 @@
   return InitializePrimitiveClass(klass, type);
 }
 
-mirror::Class* ClassLinker::InitializePrimitiveClass(mirror::Class* primitive_class, Primitive::Type type) {
+mirror::Class* ClassLinker::InitializePrimitiveClass(mirror::Class* primitive_class,
+                                                     Primitive::Type type) {
   CHECK(primitive_class != NULL);
   // Must hold lock on object when initializing.
   Thread* self = Thread::Current();
-  ObjectLock lock(self, primitive_class);
+  SirtRef<mirror::Class> sirt_class(self, primitive_class);
+  ObjectLock<mirror::Class> lock(self, &sirt_class);
   primitive_class->SetAccessFlags(kAccPublic | kAccFinal | kAccAbstract);
   primitive_class->SetPrimitiveType(type);
   primitive_class->SetStatus(mirror::Class::kStatusInitialized, self);
@@ -2068,7 +2087,7 @@
 //
 // Returns NULL with an exception raised on failure.
 mirror::Class* ClassLinker::CreateArrayClass(const char* descriptor,
-                                             SirtRef<mirror::ClassLoader>& class_loader) {
+                                             const SirtRef<mirror::ClassLoader>& class_loader) {
   // Identify the underlying component type
   CHECK_EQ('[', descriptor[0]);
   mirror::Class* component_type = FindClass(descriptor + 1, class_loader);
@@ -2138,7 +2157,7 @@
     }
     new_class->SetComponentType(component_type);
   }
-  ObjectLock lock(self, new_class.get());  // Must hold lock on object when initializing.
+  ObjectLock<mirror::Class> lock(self, &new_class);  // Must hold lock on object when initializing.
   DCHECK(new_class->GetComponentType() != NULL);
   mirror::Class* java_lang_Object = GetClassRoot(kJavaLangObject);
   new_class->SetSuperClass(java_lang_Object);
@@ -2421,10 +2440,10 @@
   }
 }
 
-void ClassLinker::VerifyClass(mirror::Class* klass) {
+void ClassLinker::VerifyClass(const SirtRef<mirror::Class>& klass) {
   // TODO: assert that the monitor on the Class is held
   Thread* self = Thread::Current();
-  ObjectLock lock(self, klass);
+  ObjectLock<mirror::Class> lock(self, &klass);
 
   // Don't attempt to re-verify if already sufficiently verified.
   if (klass->IsVerified() ||
@@ -2435,7 +2454,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);
+    ThrowEarlierClassFailure(klass.get());
     return;
   }
 
@@ -2443,7 +2462,7 @@
     klass->SetStatus(mirror::Class::kStatusVerifying, self);
   } else {
     CHECK_EQ(klass->GetStatus(), mirror::Class::kStatusRetryVerificationAtRuntime)
-        << PrettyClass(klass);
+        << PrettyClass(klass.get());
     CHECK(!Runtime::Current()->IsCompiler());
     klass->SetStatus(mirror::Class::kStatusVerifyingAtRuntime, self);
   }
@@ -2452,24 +2471,26 @@
   SirtRef<mirror::Class> super(self, klass->GetSuperClass());
   if (super.get() != NULL) {
     // Acquire lock to prevent races on verifying the super class.
-    ObjectLock lock(self, super.get());
+    ObjectLock<mirror::Class> lock(self, &super);
 
     if (!super->IsVerified() && !super->IsErroneous()) {
-      VerifyClass(super.get());
+      VerifyClass(super);
     }
     if (!super->IsCompileTimeVerified()) {
       std::string error_msg(StringPrintf("Rejecting class %s that attempts to sub-class erroneous class %s",
-                                         PrettyDescriptor(klass).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() != NULL) {
+      if (cause.get() != nullptr) {
         self->ClearException();
       }
-      ThrowVerifyError(klass, "%s", error_msg.c_str());
-      if (cause.get() != NULL) {
-        self->GetException(NULL)->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());
+      verifier::MethodVerifier::AddRejectedClass(ref);
       klass->SetStatus(mirror::Class::kStatusError, self);
       return;
     }
@@ -2478,26 +2499,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, 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) << " in "
+        << PrettyDescriptor(klass.get()) << " in "
         << klass->GetDexCache()->GetLocation()->ToModifiedUtf8();
-    ThrowVerifyError(klass, "Rejecting class %s because it failed compile-time verification",
-                     PrettyDescriptor(klass).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,
+    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)
+      VLOG(class_linker) << "Soft verification failure in class " << PrettyDescriptor(klass.get())
           << " in " << klass->GetDexCache()->GetLocation()->ToModifiedUtf8()
           << " because: " << error_msg;
     }
@@ -2527,11 +2548,11 @@
       }
     }
   } else {
-    LOG(ERROR) << "Verification failed on class " << PrettyDescriptor(klass)
+    LOG(ERROR) << "Verification failed on class " << PrettyDescriptor(klass.get())
         << " in " << klass->GetDexCache()->GetLocation()->ToModifiedUtf8()
         << " because: " << error_msg;
     self->AssertNoPendingException();
-    ThrowVerifyError(klass, "%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) {
@@ -2625,7 +2646,8 @@
   return false;
 }
 
-void ClassLinker::ResolveClassExceptionHandlerTypes(const DexFile& dex_file, mirror::Class* klass) {
+void ClassLinker::ResolveClassExceptionHandlerTypes(const DexFile& dex_file,
+                                                    const SirtRef<mirror::Class>& klass) {
   for (size_t i = 0; i < klass->NumDirectMethods(); i++) {
     ResolveMethodExceptionHandlerTypes(dex_file, klass->GetDirectMethod(i));
   }
@@ -2763,13 +2785,13 @@
   self->AssertNoPendingException();
 
   {
-    ObjectLock lock(self, klass.get());  // Must hold lock on object when resolved.
+    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)) {
       klass->SetStatus(mirror::Class::kStatusError, self);
-      return NULL;
+      return nullptr;
     }
 
     interfaces_sfield->SetObject(klass.get(), soa.Decode<mirror::ObjectArray<mirror::Class>*>(interfaces));
@@ -2840,7 +2862,7 @@
 
 
 mirror::ArtMethod* ClassLinker::CreateProxyConstructor(Thread* self,
-                                                       SirtRef<mirror::Class>& klass,
+                                                       const SirtRef<mirror::Class>& klass,
                                                        mirror::Class* proxy_class) {
   // Create constructor for Proxy that must initialize h
   mirror::ObjectArray<mirror::ArtMethod>* proxy_direct_methods =
@@ -2870,8 +2892,9 @@
   DCHECK(constructor->IsPublic());
 }
 
-mirror::ArtMethod* ClassLinker::CreateProxyMethod(Thread* self, SirtRef<mirror::Class>& klass,
-                                                  SirtRef<mirror::ArtMethod>& prototype) {
+mirror::ArtMethod* ClassLinker::CreateProxyMethod(Thread* self,
+                                                  const SirtRef<mirror::Class>& klass,
+                                                  const SirtRef<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(),
@@ -2966,7 +2989,7 @@
   return init_done_;
 }
 
-bool ClassLinker::InitializeClass(mirror::Class* klass, bool can_init_statics,
+bool ClassLinker::InitializeClass(const SirtRef<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
 
@@ -2978,14 +3001,14 @@
   }
 
   // Fast fail if initialization requires a full runtime. Not part of the JLS.
-  if (!CanWeInitializeClass(klass, can_init_statics, can_init_parents)) {
+  if (!CanWeInitializeClass(klass.get(), can_init_statics, can_init_parents)) {
     return false;
   }
 
   Thread* self = Thread::Current();
   uint64_t t0;
   {
-    ObjectLock lock(self, klass);
+    ObjectLock<mirror::Class> lock(self, &klass);
 
     // Re-check under the lock in case another thread initialized ahead of us.
     if (klass->IsInitialized()) {
@@ -2994,11 +3017,11 @@
 
     // Was the class already found to be erroneous? Done under the lock to match the JLS.
     if (klass->IsErroneous()) {
-      ThrowEarlierClassFailure(klass);
+      ThrowEarlierClassFailure(klass.get());
       return false;
     }
 
-    CHECK(klass->IsResolved()) << PrettyClass(klass) << ": state=" << klass->GetStatus();
+    CHECK(klass->IsResolved()) << PrettyClass(klass.get()) << ": state=" << klass->GetStatus();
 
     if (!klass->IsVerified()) {
       VerifyClass(klass);
@@ -3035,7 +3058,7 @@
       return false;
     }
 
-    CHECK_EQ(klass->GetStatus(), mirror::Class::kStatusVerified) << PrettyClass(klass);
+    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.
@@ -3051,16 +3074,17 @@
     if (!super_class->IsInitialized()) {
       CHECK(!super_class->IsInterface());
       CHECK(can_init_parents);
-      bool super_initialized = InitializeClass(super_class, can_init_statics, true);
+      SirtRef<mirror::Class> sirt_super(self, super_class);
+      bool super_initialized = InitializeClass(sirt_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(super_class->IsErroneous() && self->IsExceptionPending())
-            << "Super class initialization failed for " << PrettyDescriptor(super_class)
-            << " that has unexpected status " << super_class->GetStatus()
+        CHECK(sirt_super->IsErroneous() && self->IsExceptionPending())
+            << "Super class initialization failed for " << PrettyDescriptor(sirt_super.get())
+            << " that has unexpected status " << sirt_super->GetStatus()
             << "\nPending exception:\n"
             << (self->GetException(NULL) != NULL ? self->GetException(NULL)->Dump() : "");
-        ObjectLock lock(self, klass);
+        ObjectLock<mirror::Class> lock(self, &klass);
         // Initialization failed because the super-class is erroneous.
         klass->SetStatus(mirror::Class::kStatusError, self);
         return false;
@@ -3069,7 +3093,7 @@
   }
 
   if (klass->NumStaticFields() > 0) {
-    ClassHelper kh(klass);
+    ClassHelper kh(klass.get());
     const DexFile::ClassDef* dex_class_def = kh.GetClassDef();
     CHECK(dex_class_def != NULL);
     const DexFile& dex_file = kh.GetDexFile();
@@ -3081,7 +3105,7 @@
       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, field_map);
+      ConstructFieldMap(dex_file, *dex_class_def, klass.get(), field_map);
       for (size_t i = 0; it.HasNext(); i++, it.Next()) {
         it.ReadValueToField(field_map.Get(i));
       }
@@ -3100,13 +3124,13 @@
   }
 
   // Opportunistically set static method trampolines to their destination.
-  FixupStaticTrampolines(klass);
+  FixupStaticTrampolines(klass.get());
 
   uint64_t t1 = NanoTime();
 
   bool success = true;
   {
-    ObjectLock lock(self, klass);
+    ObjectLock<mirror::Class> lock(self, &klass);
 
     if (self->IsExceptionPending()) {
       WrapExceptionInInitializer();
@@ -3122,7 +3146,7 @@
       // 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);
+        ClassHelper kh(klass.get());
         LOG(INFO) << "Initialized class " << kh.GetDescriptor() << " from " << kh.GetLocation();
       }
     }
@@ -3130,7 +3154,8 @@
   return success;
 }
 
-bool ClassLinker::WaitForInitializeClass(mirror::Class* klass, Thread* self, ObjectLock& lock)
+bool ClassLinker::WaitForInitializeClass(const SirtRef<mirror::Class>& klass, Thread* self,
+                                         ObjectLock<mirror::Class>& lock)
     SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
   while (true) {
     self->AssertNoPendingException();
@@ -3157,47 +3182,49 @@
       // 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).c_str());
+                                PrettyDescriptor(klass.get()).c_str());
       return false;
     }
     if (klass->IsInitialized()) {
       return true;
     }
-    LOG(FATAL) << "Unexpected class status. " << PrettyClass(klass) << " is " << klass->GetStatus();
+    LOG(FATAL) << "Unexpected class status. " << PrettyClass(klass.get()) << " is "
+        << klass->GetStatus();
   }
-  LOG(FATAL) << "Not Reached" << PrettyClass(klass);
+  LOG(FATAL) << "Not Reached" << PrettyClass(klass.get());
 }
 
-bool ClassLinker::ValidateSuperClassDescriptors(const mirror::Class* klass) {
+bool ClassLinker::ValidateSuperClassDescriptors(const SirtRef<mirror::Class>& klass) {
   if (klass->IsInterface()) {
     return true;
   }
+  Thread* self = Thread::Current();
   // begin with the methods local to the superclass
   if (klass->HasSuperClass() &&
       klass->GetClassLoader() != klass->GetSuperClass()->GetClassLoader()) {
-    const mirror::Class* super = klass->GetSuperClass();
+    SirtRef<mirror::Class> super(self, klass->GetSuperClass());
     for (int i = super->GetVTable()->GetLength() - 1; i >= 0; --i) {
       const mirror::ArtMethod* method = klass->GetVTable()->Get(i);
       if (method != super->GetVTable()->Get(i) &&
-          !IsSameMethodSignatureInDifferentClassContexts(method, super, klass)) {
-        ThrowLinkageError(klass, "Class %s method %s resolves differently in superclass %s",
-                          PrettyDescriptor(klass).c_str(), PrettyMethod(method).c_str(),
-                          PrettyDescriptor(super).c_str());
+          !IsSameMethodSignatureInDifferentClassContexts(method, super.get(), klass.get())) {
+        ThrowLinkageError(klass.get(), "Class %s method %s resolves differently in superclass %s",
+                          PrettyDescriptor(klass.get()).c_str(), PrettyMethod(method).c_str(),
+                          PrettyDescriptor(super.get()).c_str());
         return false;
       }
     }
   }
   for (int32_t i = 0; i < klass->GetIfTableCount(); ++i) {
-    mirror::Class* interface = klass->GetIfTable()->GetInterface(i);
+    SirtRef<mirror::Class> interface(self, klass->GetIfTable()->GetInterface(i));
     if (klass->GetClassLoader() != interface->GetClassLoader()) {
       for (size_t j = 0; j < interface->NumVirtualMethods(); ++j) {
         const mirror::ArtMethod* method = klass->GetIfTable()->GetMethodArray(i)->Get(j);
-        if (!IsSameMethodSignatureInDifferentClassContexts(method, interface,
+        if (!IsSameMethodSignatureInDifferentClassContexts(method, interface.get(),
                                                            method->GetDeclaringClass())) {
-          ThrowLinkageError(klass, "Class %s method %s resolves differently in interface %s",
+          ThrowLinkageError(klass.get(), "Class %s method %s resolves differently in interface %s",
                             PrettyDescriptor(method->GetDeclaringClass()).c_str(),
                             PrettyMethod(method).c_str(),
-                            PrettyDescriptor(interface).c_str());
+                            PrettyDescriptor(interface.get()).c_str());
           return false;
         }
       }
@@ -3214,17 +3241,22 @@
   if (klass1 == klass2) {
     return true;
   }
+  Thread* self = Thread::Current();
+  CHECK(klass1 != nullptr);
+  CHECK(klass2 != nullptr);
+  SirtRef<mirror::ClassLoader> loader1(self, klass1->GetClassLoader());
+  SirtRef<mirror::ClassLoader> loader2(self, klass2->GetClassLoader());
   const DexFile& dex_file = *method->GetDeclaringClass()->GetDexCache()->GetDexFile();
   const DexFile::ProtoId& proto_id =
       dex_file.GetMethodPrototype(dex_file.GetMethodId(method->GetDexMethodIndex()));
   for (DexFileParameterIterator it(dex_file, proto_id); it.HasNext(); it.Next()) {
     const char* descriptor = it.GetDescriptor();
-    if (descriptor == NULL) {
+    if (descriptor == nullptr) {
       break;
     }
     if (descriptor[0] == 'L' || descriptor[0] == '[') {
       // Found a non-primitive type.
-      if (!IsSameDescriptorInDifferentClassContexts(descriptor, klass1, klass2)) {
+      if (!IsSameDescriptorInDifferentClassContexts(descriptor, loader1, loader2)) {
         return false;
       }
     }
@@ -3232,47 +3264,42 @@
   // Check the return type
   const char* descriptor = dex_file.GetReturnTypeDescriptor(proto_id);
   if (descriptor[0] == 'L' || descriptor[0] == '[') {
-    if (!IsSameDescriptorInDifferentClassContexts(descriptor, klass1, klass2)) {
+    if (!IsSameDescriptorInDifferentClassContexts(descriptor, loader1, loader2)) {
       return false;
     }
   }
   return true;
 }
 
-// Returns true if the descriptor resolves to the same class in the context of klass1 and klass2.
+// Returns true if the descriptor resolves to the same class in the context of loader1 and loader2.
 bool ClassLinker::IsSameDescriptorInDifferentClassContexts(const char* descriptor,
-                                                           const mirror::Class* klass1,
-                                                           const mirror::Class* klass2) {
-  CHECK(descriptor != NULL);
-  CHECK(klass1 != NULL);
-  CHECK(klass2 != NULL);
-  if (klass1 == klass2) {
-    return true;
-  }
+                                                           SirtRef<mirror::ClassLoader>& loader1,
+                                                           SirtRef<mirror::ClassLoader>& loader2) {
+  CHECK(descriptor != nullptr);
   Thread* self = Thread::Current();
-  SirtRef<mirror::ClassLoader> class_loader1(self, klass1->GetClassLoader());
-  mirror::Class* found1 = FindClass(descriptor, class_loader1);
-  if (found1 == NULL) {
-    Thread::Current()->ClearException();
+  SirtRef<mirror::Class> found1(self, FindClass(descriptor, loader1));
+  if (found1.get() == nullptr) {
+    self->ClearException();
   }
-  SirtRef<mirror::ClassLoader> class_loader2(self, klass2->GetClassLoader());
-  mirror::Class* found2 = FindClass(descriptor, class_loader2);
-  if (found2 == NULL) {
-    Thread::Current()->ClearException();
+  mirror::Class* found2 = FindClass(descriptor, loader2);
+  if (found2 == nullptr) {
+    self->ClearException();
   }
-  return found1 == found2;
+  return found1.get() == found2;
 }
 
-bool ClassLinker::EnsureInitialized(mirror::Class* c, bool can_init_fields, bool can_init_parents) {
-  DCHECK(c != NULL);
+bool ClassLinker::EnsureInitialized(const SirtRef<mirror::Class>& c, bool can_init_fields,
+                                    bool can_init_parents) {
+  DCHECK(c.get() != NULL);
   if (c->IsInitialized()) {
     return true;
   }
 
   bool success = InitializeClass(c, can_init_fields, can_init_parents);
   if (!success) {
-    Thread* self = Thread::Current();
-    CHECK(self->IsExceptionPending() || !can_init_fields || !can_init_parents) << PrettyClass(c);
+    if (can_init_fields && can_init_parents) {
+      CHECK(Thread::Current()->IsExceptionPending()) << PrettyClass(c.get());
+    }
   }
   return success;
 }
@@ -3285,13 +3312,14 @@
   Thread* self = Thread::Current();
   SirtRef<mirror::DexCache> dex_cache(self, c->GetDexCache());
   SirtRef<mirror::ClassLoader> class_loader(self, 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, SirtRef<mirror::Class>& klass,
-                            SirtRef<mirror::ObjectArray<mirror::Class> >& interfaces) {
+bool ClassLinker::LinkClass(Thread* self, const SirtRef<mirror::Class>& klass,
+                            const SirtRef<mirror::ObjectArray<mirror::Class> >& interfaces) {
   CHECK_EQ(mirror::Class::kStatusLoaded, klass->GetStatus());
   if (!LinkSuperClass(klass)) {
     return false;
@@ -3312,7 +3340,8 @@
   return true;
 }
 
-bool ClassLinker::LoadSuperAndInterfaces(SirtRef<mirror::Class>& klass, const DexFile& dex_file) {
+bool ClassLinker::LoadSuperAndInterfaces(const SirtRef<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_;
@@ -3355,7 +3384,7 @@
   return true;
 }
 
-bool ClassLinker::LinkSuperClass(SirtRef<mirror::Class>& klass) {
+bool ClassLinker::LinkSuperClass(const SirtRef<mirror::Class>& klass) {
   CHECK(!klass->IsPrimitive());
   mirror::Class* super = klass->GetSuperClass();
   if (klass.get() == GetClassRoot(kJavaLangObject)) {
@@ -3414,8 +3443,8 @@
 }
 
 // Populate the class vtable and itable. Compute return type indices.
-bool ClassLinker::LinkMethods(SirtRef<mirror::Class>& klass,
-                              SirtRef<mirror::ObjectArray<mirror::Class> >& interfaces) {
+bool ClassLinker::LinkMethods(const SirtRef<mirror::Class>& klass,
+                              const SirtRef<mirror::ObjectArray<mirror::Class> >& interfaces) {
   if (klass->IsInterface()) {
     // No vtable.
     size_t count = klass->NumVirtualMethods();
@@ -3435,7 +3464,7 @@
   return true;
 }
 
-bool ClassLinker::LinkVirtualMethods(SirtRef<mirror::Class>& klass) {
+bool ClassLinker::LinkVirtualMethods(const SirtRef<mirror::Class>& klass) {
   Thread* self = Thread::Current();
   if (klass->HasSuperClass()) {
     uint32_t max_count = klass->NumVirtualMethods() + klass->GetSuperClass()->GetVTable()->GetLength();
@@ -3518,8 +3547,8 @@
   return true;
 }
 
-bool ClassLinker::LinkInterfaceMethods(SirtRef<mirror::Class>& klass,
-                                       SirtRef<mirror::ObjectArray<mirror::Class> >& interfaces) {
+bool ClassLinker::LinkInterfaceMethods(const SirtRef<mirror::Class>& klass,
+                                       const SirtRef<mirror::ObjectArray<mirror::Class> >& interfaces) {
   // Set the imt table to be all conflicts by default.
   klass->SetImTable(Runtime::Current()->GetDefaultImt());
   size_t super_ifcount;
@@ -3529,14 +3558,17 @@
     super_ifcount = 0;
   }
   size_t ifcount = super_ifcount;
-  ClassHelper kh(klass.get());
-  uint32_t num_interfaces =
-      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);
-    ifcount += interface->GetIfTableCount();
+  uint32_t num_interfaces;
+  {
+    ClassHelper kh(klass.get());
+    num_interfaces =
+        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);
+      ifcount += interface->GetIfTableCount();
+    }
   }
   if (ifcount == 0) {
     // Class implements no interfaces.
@@ -3576,6 +3608,7 @@
   // Flatten the interface inheritance hierarchy.
   size_t idx = super_ifcount;
   for (size_t i = 0; i < num_interfaces; i++) {
+    ClassHelper kh(klass.get());
     mirror::Class* interface =
         interfaces.get() == nullptr ? kh.GetDirectInterface(i) : interfaces->Get(i);
     DCHECK(interface != NULL);
@@ -3640,11 +3673,8 @@
     return false;
   }
   std::vector<mirror::ArtMethod*> miranda_list;
-  MethodHelper vtable_mh(NULL);
-  MethodHelper interface_mh(NULL);
   for (size_t i = 0; i < ifcount; ++i) {
-    mirror::Class* interface = iftable->GetInterface(i);
-    size_t num_methods = interface->NumVirtualMethods();
+    size_t num_methods = iftable->GetInterface(i)->NumVirtualMethods();
     if (num_methods > 0) {
       SirtRef<mirror::ObjectArray<mirror::ArtMethod> >
           method_array(self, AllocArtMethodArray(self, num_methods));
@@ -3656,8 +3686,8 @@
       SirtRef<mirror::ObjectArray<mirror::ArtMethod> > vtable(self,
                                                               klass->GetVTableDuringLinking());
       for (size_t j = 0; j < num_methods; ++j) {
-        mirror::ArtMethod* interface_method = interface->GetVirtualMethod(j);
-        interface_mh.ChangeMethod(interface_method);
+        mirror::ArtMethod* interface_method = iftable->GetInterface(i)->GetVirtualMethod(j);
+        MethodHelper interface_mh(interface_method);
         int32_t k;
         // For each method listed in the interface's method list, find the
         // matching method in our class's method list.  We want to favor the
@@ -3669,7 +3699,7 @@
         // matter which direction we go.  We walk it backward anyway.)
         for (k = vtable->GetLength() - 1; k >= 0; --k) {
           mirror::ArtMethod* vtable_method = vtable->Get(k);
-          vtable_mh.ChangeMethod(vtable_method);
+          MethodHelper vtable_mh(vtable_method);
           if (interface_mh.HasSameNameAndSignature(&vtable_mh)) {
             if (!vtable_method->IsAbstract() && !vtable_method->IsPublic()) {
               ThrowIllegalAccessError(klass.get(),
@@ -3694,7 +3724,7 @@
           SirtRef<mirror::ArtMethod> miranda_method(self, NULL);
           for (size_t mir = 0; mir < miranda_list.size(); mir++) {
             mirror::ArtMethod* mir_method = miranda_list[mir];
-            vtable_mh.ChangeMethod(mir_method);
+            MethodHelper vtable_mh(mir_method);
             if (interface_mh.HasSameNameAndSignature(&vtable_mh)) {
               miranda_method.reset(miranda_list[mir]);
               break;
@@ -3772,12 +3802,12 @@
   return true;
 }
 
-bool ClassLinker::LinkInstanceFields(SirtRef<mirror::Class>& klass) {
+bool ClassLinker::LinkInstanceFields(const SirtRef<mirror::Class>& klass) {
   CHECK(klass.get() != NULL);
   return LinkFields(klass, false);
 }
 
-bool ClassLinker::LinkStaticFields(SirtRef<mirror::Class>& klass) {
+bool ClassLinker::LinkStaticFields(const SirtRef<mirror::Class>& klass) {
   CHECK(klass.get() != NULL);
   size_t allocated_class_size = klass->GetClassSize();
   bool success = LinkFields(klass, true);
@@ -3813,7 +3843,7 @@
   }
 };
 
-bool ClassLinker::LinkFields(SirtRef<mirror::Class>& klass, bool is_static) {
+bool ClassLinker::LinkFields(const SirtRef<mirror::Class>& klass, bool is_static) {
   size_t num_fields =
       is_static ? klass->NumStaticFields() : klass->NumInstanceFields();
 
@@ -3972,7 +4002,7 @@
 
 //  Set the bitmap of reference offsets, refOffsets, from the ifields
 //  list.
-void ClassLinker::CreateReferenceInstanceOffsets(SirtRef<mirror::Class>& klass) {
+void ClassLinker::CreateReferenceInstanceOffsets(const SirtRef<mirror::Class>& klass) {
   uint32_t reference_offsets = 0;
   mirror::Class* super_class = klass->GetSuperClass();
   if (super_class != NULL) {
@@ -3986,11 +4016,11 @@
   CreateReferenceOffsets(klass, false, reference_offsets);
 }
 
-void ClassLinker::CreateReferenceStaticOffsets(SirtRef<mirror::Class>& klass) {
+void ClassLinker::CreateReferenceStaticOffsets(const SirtRef<mirror::Class>& klass) {
   CreateReferenceOffsets(klass, true, 0);
 }
 
-void ClassLinker::CreateReferenceOffsets(SirtRef<mirror::Class>& klass, bool is_static,
+void ClassLinker::CreateReferenceOffsets(const SirtRef<mirror::Class>& klass, bool is_static,
                                          uint32_t reference_offsets) {
   size_t num_reference_fields =
       is_static ? klass->NumReferenceStaticFieldsDuringLinking()
@@ -4023,7 +4053,7 @@
 }
 
 mirror::String* ClassLinker::ResolveString(const DexFile& dex_file, uint32_t string_idx,
-                                           SirtRef<mirror::DexCache>& dex_cache) {
+                                           const SirtRef<mirror::DexCache>& dex_cache) {
   DCHECK(dex_cache.get() != nullptr);
   mirror::String* resolved = dex_cache->GetResolvedString(string_idx);
   if (resolved != NULL) {
@@ -4045,8 +4075,8 @@
 }
 
 mirror::Class* ClassLinker::ResolveType(const DexFile& dex_file, uint16_t type_idx,
-                                        SirtRef<mirror::DexCache>& dex_cache,
-                                        SirtRef<mirror::ClassLoader>& class_loader) {
+                                        const SirtRef<mirror::DexCache>& dex_cache,
+                                        const SirtRef<mirror::ClassLoader>& class_loader) {
   DCHECK(dex_cache.get() != NULL);
   mirror::Class* resolved = dex_cache->GetResolvedType(type_idx);
   if (resolved == NULL) {
@@ -4064,9 +4094,11 @@
       // Convert a ClassNotFoundException to a NoClassDefFoundError.
       SirtRef<mirror::Throwable> cause(self, self->GetException(NULL));
       if (cause->InstanceOf(GetClassRoot(kJavaLangClassNotFoundException))) {
+        SirtRef<mirror::Class> sirt_resolved(self, resolved);
         Thread::Current()->ClearException();
         ThrowNoClassDefFoundError("Failed resolution of: %s", descriptor);
         self->GetException(NULL)->SetCause(cause.get());
+        resolved = sirt_resolved.get();
       }
     }
   }
@@ -4077,8 +4109,8 @@
 
 mirror::ArtMethod* ClassLinker::ResolveMethod(const DexFile& dex_file,
                                               uint32_t method_idx,
-                                              SirtRef<mirror::DexCache>& dex_cache,
-                                              SirtRef<mirror::ClassLoader>& class_loader,
+                                              const SirtRef<mirror::DexCache>& dex_cache,
+                                              const SirtRef<mirror::ClassLoader>& class_loader,
                                               const mirror::ArtMethod* referrer,
                                               InvokeType type) {
   DCHECK(dex_cache.get() != NULL);
@@ -4223,8 +4255,8 @@
 }
 
 mirror::ArtField* ClassLinker::ResolveField(const DexFile& dex_file, uint32_t field_idx,
-                                            SirtRef<mirror::DexCache>& dex_cache,
-                                            SirtRef<mirror::ClassLoader>& class_loader,
+                                            const SirtRef<mirror::DexCache>& dex_cache,
+                                            const SirtRef<mirror::ClassLoader>& class_loader,
                                             bool is_static) {
   DCHECK(dex_cache.get() != nullptr);
   mirror::ArtField* resolved = dex_cache->GetResolvedField(field_idx);
@@ -4263,8 +4295,8 @@
 
 mirror::ArtField* ClassLinker::ResolveFieldJLS(const DexFile& dex_file,
                                                uint32_t field_idx,
-                                               SirtRef<mirror::DexCache>& dex_cache,
-                                               SirtRef<mirror::ClassLoader>& class_loader) {
+                                               const SirtRef<mirror::DexCache>& dex_cache,
+                                               const SirtRef<mirror::ClassLoader>& class_loader) {
   DCHECK(dex_cache.get() != nullptr);
   mirror::ArtField* resolved = dex_cache->GetResolvedField(field_idx);
   if (resolved != NULL) {
diff --git a/runtime/class_linker.h b/runtime/class_linker.h
index 4e2cc06..d468e1e 100644
--- a/runtime/class_linker.h
+++ b/runtime/class_linker.h
@@ -45,7 +45,7 @@
 }  // namespace mirror
 
 class InternTable;
-class ObjectLock;
+template<class T> class ObjectLock;
 class ScopedObjectAccess;
 template<class T> class SirtRef;
 
@@ -72,7 +72,7 @@
 
   // Finds a class by its descriptor, loading it if necessary.
   // If class_loader is null, searches boot_class_path_.
-  mirror::Class* FindClass(const char* descriptor, SirtRef<mirror::ClassLoader>& class_loader)
+  mirror::Class* FindClass(const char* descriptor, const SirtRef<mirror::ClassLoader>& class_loader)
       SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
 
   mirror::Class* FindSystemClass(const char* descriptor)
@@ -82,7 +82,8 @@
   bool IsInitialized() const;
 
   // Define a new a class based on a ClassDef from a DexFile
-  mirror::Class* DefineClass(const char* descriptor, SirtRef<mirror::ClassLoader>& class_loader,
+  mirror::Class* DefineClass(const char* descriptor,
+                             const SirtRef<mirror::ClassLoader>& class_loader,
                              const DexFile& dex_file, const DexFile::ClassDef& dex_class_def)
       SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
 
@@ -126,7 +127,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,
-                                SirtRef<mirror::DexCache>& dex_cache)
+                                const SirtRef<mirror::DexCache>& dex_cache)
       SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
 
   // Resolve a Type with the given index from the DexFile, storing the
@@ -150,8 +151,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,
-                             SirtRef<mirror::DexCache>& dex_cache,
-                             SirtRef<mirror::ClassLoader>& class_loader)
+                             const SirtRef<mirror::DexCache>& dex_cache,
+                             const SirtRef<mirror::ClassLoader>& class_loader)
       SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
 
   // Resolve a method with a given ID from the DexFile, storing the
@@ -161,8 +162,8 @@
   // virtual method.
   mirror::ArtMethod* ResolveMethod(const DexFile& dex_file,
                                    uint32_t method_idx,
-                                   SirtRef<mirror::DexCache>& dex_cache,
-                                   SirtRef<mirror::ClassLoader>& class_loader,
+                                   const SirtRef<mirror::DexCache>& dex_cache,
+                                   const SirtRef<mirror::ClassLoader>& class_loader,
                                    const mirror::ArtMethod* referrer,
                                    InvokeType type)
       SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
@@ -182,8 +183,8 @@
   // field.
   mirror::ArtField* ResolveField(const DexFile& dex_file,
                                  uint32_t field_idx,
-                                 SirtRef<mirror::DexCache>& dex_cache,
-                                 SirtRef<mirror::ClassLoader>& class_loader,
+                                 const SirtRef<mirror::DexCache>& dex_cache,
+                                 const SirtRef<mirror::ClassLoader>& class_loader,
                                  bool is_static)
       SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
 
@@ -193,8 +194,8 @@
   // field resolution semantics are followed.
   mirror::ArtField* ResolveFieldJLS(const DexFile& dex_file,
                                     uint32_t field_idx,
-                                    SirtRef<mirror::DexCache>& dex_cache,
-                                    SirtRef<mirror::ClassLoader>& class_loader)
+                                    const SirtRef<mirror::DexCache>& dex_cache,
+                                    const SirtRef<mirror::ClassLoader>& class_loader)
       SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
 
   // Get shorty from method index without resolution. Used to do handlerization.
@@ -204,7 +205,8 @@
   // 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(mirror::Class* c, bool can_run_clinit, bool can_init_fields)
+  bool EnsureInitialized(const SirtRef<mirror::Class>& c,
+                         bool can_init_fields, bool can_init_parents)
       SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
 
   // Initializes classes that have instances in the image but that have
@@ -214,7 +216,7 @@
   void RegisterDexFile(const DexFile& dex_file)
       LOCKS_EXCLUDED(dex_lock_)
       SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
-  void RegisterDexFile(const DexFile& dex_file, SirtRef<mirror::DexCache>& dex_cache)
+  void RegisterDexFile(const DexFile& dex_file, const SirtRef<mirror::DexCache>& dex_cache)
       LOCKS_EXCLUDED(dex_lock_)
       SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
 
@@ -268,7 +270,7 @@
   // that this returns null if the location checksum of the DexFile
   // does not match the OatFile.
   const DexFile* FindDexFileInOatFileFromDexLocation(const char* location,
-                                                     uint32_t location_checksum,
+                                                     const uint32_t* const location_checksum,
                                                      std::string* error_msg)
       LOCKS_EXCLUDED(dex_lock_, Locks::mutator_lock_);
 
@@ -303,11 +305,12 @@
                                                                               size_t length)
       SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
 
-  void VerifyClass(mirror::Class* klass) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
+  void VerifyClass(const SirtRef<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, mirror::Class* klass)
+  void ResolveClassExceptionHandlerTypes(const DexFile& dex_file,
+                                         const SirtRef<mirror::Class>& klass)
       SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
   void ResolveMethodExceptionHandlerTypes(const DexFile& dex_file, mirror::ArtMethod* klass)
       SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
@@ -380,7 +383,8 @@
   // Alloc* convenience functions to avoid needing to pass in mirror::Class*
   // values that are known to the ClassLinker such as
   // kObjectArrayClass and kJavaLangString etc.
-  mirror::Class* AllocClass(Thread* self, size_t class_size) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
+  mirror::Class* AllocClass(Thread* self, size_t class_size)
+      SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
   mirror::DexCache* AllocDexCache(Thread* self, const DexFile& dex_file)
       SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
   mirror::ArtField* AllocArtField(Thread* self) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
@@ -392,12 +396,12 @@
 
 
   mirror::Class* CreateArrayClass(const char* descriptor,
-                                  SirtRef<mirror::ClassLoader>& class_loader)
+                                  const SirtRef<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, SirtRef<mirror::DexCache>& dex_cache)
+  void AppendToBootClassPath(const DexFile& dex_file, const SirtRef<mirror::DexCache>& dex_cache)
       SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
 
   void ConstructFieldMap(const DexFile& dex_file, const DexFile::ClassDef& dex_class_def,
@@ -409,17 +413,17 @@
 
   void LoadClass(const DexFile& dex_file,
                  const DexFile::ClassDef& dex_class_def,
-                 SirtRef<mirror::Class>& klass,
+                 const SirtRef<mirror::Class>& klass,
                  mirror::ClassLoader* class_loader)
       SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
 
   void LoadField(const DexFile& dex_file, const ClassDataItemIterator& it,
-                 SirtRef<mirror::Class>& klass, SirtRef<mirror::ArtField>& dst)
+                 const SirtRef<mirror::Class>& klass, const SirtRef<mirror::ArtField>& dst)
       SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
 
   mirror::ArtMethod* LoadMethod(Thread* self, const DexFile& dex_file,
                                 const ClassDataItemIterator& dex_method,
-                                SirtRef<mirror::Class>& klass)
+                                const SirtRef<mirror::Class>& klass)
       SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
 
   void FixupStaticTrampolines(mirror::Class* klass) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
@@ -428,20 +432,22 @@
   const OatFile::OatClass* GetOatClass(const DexFile& dex_file, uint16_t class_def_idx)
       SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
 
-  void RegisterDexFileLocked(const DexFile& dex_file, SirtRef<mirror::DexCache>& dex_cache)
+  void RegisterDexFileLocked(const DexFile& dex_file, const SirtRef<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_);
 
-  bool InitializeClass(mirror::Class* klass, bool can_run_clinit, bool can_init_parents)
+  bool InitializeClass(const SirtRef<mirror::Class>& klass, bool can_run_clinit,
+                       bool can_init_parents)
       SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
-  bool WaitForInitializeClass(mirror::Class* klass, Thread* self, ObjectLock& lock);
-  bool ValidateSuperClassDescriptors(const mirror::Class* klass)
+  bool WaitForInitializeClass(const SirtRef<mirror::Class>& klass, Thread* self,
+                              ObjectLock<mirror::Class>& lock);
+  bool ValidateSuperClassDescriptors(const SirtRef<mirror::Class>& klass)
       SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
 
   bool IsSameDescriptorInDifferentClassContexts(const char* descriptor,
-                                                const mirror::Class* klass1,
-                                                const mirror::Class* klass2)
+                                                SirtRef<mirror::ClassLoader>& class_loader1,
+                                                SirtRef<mirror::ClassLoader>& class_loader2)
       SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
 
   bool IsSameMethodSignatureInDifferentClassContexts(const mirror::ArtMethod* method,
@@ -449,40 +455,40 @@
                                                      const mirror::Class* klass2)
       SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
 
-  bool LinkClass(Thread* self, SirtRef<mirror::Class>& klass,
-                 SirtRef<mirror::ObjectArray<mirror::Class> >& interfaces)
+  bool LinkClass(Thread* self, const SirtRef<mirror::Class>& klass,
+                 const SirtRef<mirror::ObjectArray<mirror::Class> >& interfaces)
       SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
 
-  bool LinkSuperClass(SirtRef<mirror::Class>& klass)
+  bool LinkSuperClass(const SirtRef<mirror::Class>& klass)
       SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
 
-  bool LoadSuperAndInterfaces(SirtRef<mirror::Class>& klass, const DexFile& dex_file)
+  bool LoadSuperAndInterfaces(const SirtRef<mirror::Class>& klass, const DexFile& dex_file)
       SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
 
-  bool LinkMethods(SirtRef<mirror::Class>& klass,
-                   SirtRef<mirror::ObjectArray<mirror::Class> >& interfaces)
+  bool LinkMethods(const SirtRef<mirror::Class>& klass,
+                   const SirtRef<mirror::ObjectArray<mirror::Class> >& interfaces)
       SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
 
-  bool LinkVirtualMethods(SirtRef<mirror::Class>& klass)
+  bool LinkVirtualMethods(const SirtRef<mirror::Class>& klass)
       SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
 
-  bool LinkInterfaceMethods(SirtRef<mirror::Class>& klass,
-                            SirtRef<mirror::ObjectArray<mirror::Class> >& interfaces)
+  bool LinkInterfaceMethods(const SirtRef<mirror::Class>& klass,
+                            const SirtRef<mirror::ObjectArray<mirror::Class> >& interfaces)
       SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
 
-  bool LinkStaticFields(SirtRef<mirror::Class>& klass)
+  bool LinkStaticFields(const SirtRef<mirror::Class>& klass)
       SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
-  bool LinkInstanceFields(SirtRef<mirror::Class>& klass)
+  bool LinkInstanceFields(const SirtRef<mirror::Class>& klass)
       SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
-  bool LinkFields(SirtRef<mirror::Class>& klass, bool is_static)
+  bool LinkFields(const SirtRef<mirror::Class>& klass, bool is_static)
       SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
 
 
-  void CreateReferenceInstanceOffsets(SirtRef<mirror::Class>& klass)
+  void CreateReferenceInstanceOffsets(const SirtRef<mirror::Class>& klass)
       SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
-  void CreateReferenceStaticOffsets(SirtRef<mirror::Class>& klass)
+  void CreateReferenceStaticOffsets(const SirtRef<mirror::Class>& klass)
       SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
-  void CreateReferenceOffsets(SirtRef<mirror::Class>& klass, bool is_static,
+  void CreateReferenceOffsets(const SirtRef<mirror::Class>& klass, bool is_static,
                               uint32_t reference_offsets)
       SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
 
@@ -495,7 +501,7 @@
       LOCKS_EXCLUDED(dex_lock_)
       SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
   const OatFile* FindOpenedOatFileFromDexLocation(const char* dex_location,
-                                                  uint32_t dex_location_checksum)
+                                                  const uint32_t* const dex_location_checksum)
       LOCKS_EXCLUDED(dex_lock);
   const OatFile* FindOpenedOatFileFromOatLocation(const std::string& oat_location)
       LOCKS_EXCLUDED(dex_lock_);
@@ -511,11 +517,11 @@
                                                  bool* open_failed)
       LOCKS_EXCLUDED(dex_lock_);
 
-  mirror::ArtMethod* CreateProxyConstructor(Thread* self, SirtRef<mirror::Class>& klass,
+  mirror::ArtMethod* CreateProxyConstructor(Thread* self, const SirtRef<mirror::Class>& klass,
                                             mirror::Class* proxy_class)
       SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
-  mirror::ArtMethod* CreateProxyMethod(Thread* self, SirtRef<mirror::Class>& klass,
-                                       SirtRef<mirror::ArtMethod>& prototype)
+  mirror::ArtMethod* CreateProxyMethod(Thread* self, const SirtRef<mirror::Class>& klass,
+                                       const SirtRef<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 b8bc474..34134fa 100644
--- a/runtime/class_linker_test.cc
+++ b/runtime/class_linker_test.cc
@@ -95,8 +95,10 @@
                         const std::string& component_type,
                         mirror::ClassLoader* class_loader)
       SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
-    SirtRef<mirror::ClassLoader> loader(Thread::Current(), class_loader);
-    mirror::Class* array = class_linker_->FindClass(array_descriptor.c_str(), loader);
+    Thread* self = Thread::Current();
+    SirtRef<mirror::ClassLoader> loader(self, class_loader);
+    SirtRef<mirror::Class> array(self,
+                                 class_linker_->FindClass(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());
@@ -104,10 +106,10 @@
     AssertArrayClass(array_descriptor, array);
   }
 
-  void AssertArrayClass(const std::string& array_descriptor, mirror::Class* array)
+  void AssertArrayClass(const std::string& array_descriptor, const SirtRef<mirror::Class>& array)
       SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
-    ClassHelper kh(array);
-    ASSERT_TRUE(array != 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);
@@ -135,15 +137,14 @@
     EXPECT_EQ(0U, array->NumVirtualMethods());
     EXPECT_EQ(0U, array->NumInstanceFields());
     EXPECT_EQ(0U, array->NumStaticFields());
-    kh.ChangeClass(array);
+    kh.ChangeClass(array.get());
     EXPECT_EQ(2U, kh.NumDirectInterfaces());
     EXPECT_TRUE(array->GetVTable() != NULL);
     EXPECT_EQ(2, array->GetIfTableCount());
-    mirror::IfTable* iftable = array->GetIfTable();
-    ASSERT_TRUE(iftable != NULL);
+    ASSERT_TRUE(array->GetIfTable() != NULL);
     kh.ChangeClass(kh.GetDirectInterface(0));
     EXPECT_STREQ(kh.GetDescriptor(), "Ljava/lang/Cloneable;");
-    kh.ChangeClass(array);
+    kh.ChangeClass(array.get());
     kh.ChangeClass(kh.GetDirectInterface(1));
     EXPECT_STREQ(kh.GetDescriptor(), "Ljava/io/Serializable;");
   }
@@ -179,9 +180,9 @@
     EXPECT_TRUE(fh.GetType() != NULL);
   }
 
-  void AssertClass(const std::string& descriptor, mirror::Class* klass)
+  void AssertClass(const std::string& descriptor, const SirtRef<mirror::Class>& klass)
       SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
-    ClassHelper kh(klass);
+    ClassHelper kh(klass.get());
     EXPECT_STREQ(descriptor.c_str(), kh.GetDescriptor());
     if (descriptor == "Ljava/lang/Object;") {
       EXPECT_FALSE(klass->HasSuperClass());
@@ -197,7 +198,7 @@
     EXPECT_FALSE(klass->IsErroneous());
     EXPECT_FALSE(klass->IsArrayClass());
     EXPECT_TRUE(klass->GetComponentType() == NULL);
-    EXPECT_TRUE(klass->IsInSamePackage(klass));
+    EXPECT_TRUE(klass->IsInSamePackage(klass.get()));
     EXPECT_TRUE(mirror::Class::IsInSamePackage(kh.GetDescriptor(), kh.GetDescriptor()));
     if (klass->IsInterface()) {
       EXPECT_TRUE(klass->IsAbstract());
@@ -239,31 +240,31 @@
     }
 
     EXPECT_FALSE(klass->IsPrimitive());
-    EXPECT_TRUE(klass->CanAccess(klass));
+    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, 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));
+      EXPECT_TRUE(method->GetDeclaringClass()->IsAssignableFrom(klass.get()));
     }
 
     for (size_t i = 0; i < klass->NumInstanceFields(); i++) {
       mirror::ArtField* field = klass->GetInstanceField(i);
-      AssertField(klass, 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, field);
+      AssertField(klass.get(), field);
       EXPECT_TRUE(field->IsStatic());
     }
 
@@ -291,24 +292,24 @@
     }
 
     size_t total_num_reference_instance_fields = 0;
-    mirror::Class* k = klass;
+    mirror::Class* k = klass.get();
     while (k != NULL) {
       total_num_reference_instance_fields += k->NumReferenceInstanceFields();
       k = k->GetSuperClass();
     }
-    EXPECT_EQ(klass->GetReferenceInstanceOffsets() == 0,
-              total_num_reference_instance_fields == 0);
+    EXPECT_EQ(klass->GetReferenceInstanceOffsets() == 0, total_num_reference_instance_fields == 0);
   }
 
   void AssertDexFileClass(mirror::ClassLoader* class_loader, const std::string& descriptor)
       SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
     ASSERT_TRUE(descriptor != NULL);
-    mirror::Class* klass = class_linker_->FindSystemClass(descriptor.c_str());
-    ASSERT_TRUE(klass != NULL);
-    EXPECT_STREQ(descriptor.c_str(), ClassHelper(klass).GetDescriptor());
+    SirtRef<mirror::Class> klass(Thread::Current(),
+                                 class_linker_->FindSystemClass(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);
+      AssertPrimitiveClass(descriptor, klass.get());
     } else if (klass->IsArrayClass()) {
       AssertArrayClass(descriptor, klass);
     } else {
@@ -852,7 +853,7 @@
 TEST_F(ClassLinkerTest, StaticFields) {
   ScopedObjectAccess soa(Thread::Current());
   SirtRef<mirror::ClassLoader> class_loader(soa.Self(), soa.Decode<mirror::ClassLoader*>(LoadDex("Statics")));
-  mirror::Class* statics = class_linker_->FindClass("LStatics;", class_loader);
+  SirtRef<mirror::Class> statics(soa.Self(), class_linker_->FindClass("LStatics;", class_loader));
   class_linker_->EnsureInitialized(statics, true, true);
 
   // Static final primitives that are initialized by a compile-time constant
@@ -867,68 +868,68 @@
   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));
-  s0->SetBoolean(statics, false);
+  EXPECT_EQ(true, s0->GetBoolean(statics.get()));
+  s0->SetBoolean(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));
-  s1->SetByte(statics, 6);
+  EXPECT_EQ(5, s1->GetByte(statics.get()));
+  s1->SetByte(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));
-  s2->SetChar(statics, 'b');
+  EXPECT_EQ('a', s2->GetChar(statics.get()));
+  s2->SetChar(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));
-  s3->SetShort(statics, -535);
+  EXPECT_EQ(-536, s3->GetShort(statics.get()));
+  s3->SetShort(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));
-  s4->SetInt(statics, 2000000001);
+  EXPECT_EQ(2000000000, s4->GetInt(statics.get()));
+  s4->SetInt(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));
-  s5->SetLong(statics, 0x34567890abcdef12LL);
+  EXPECT_EQ(0x1234567890abcdefLL, s5->GetLong(statics.get()));
+  s5->SetLong(statics.get(), 0x34567890abcdef12LL);
 
   mirror::ArtField* s6 = statics->FindStaticField("s6", "F");
   fh.ChangeField(s6);
   EXPECT_TRUE(fh.GetTypeAsPrimitiveType() == Primitive::kPrimFloat);
-  EXPECT_EQ(0.5, s6->GetFloat(statics));
-  s6->SetFloat(statics, 0.75);
+  EXPECT_EQ(0.5, s6->GetFloat(statics.get()));
+  s6->SetFloat(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));
-  s7->SetDouble(statics, 16777219);
+  EXPECT_EQ(16777217, s7->GetDouble(statics.get()));
+  s7->SetDouble(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)->AsString()->Equals("android"));
+  EXPECT_TRUE(s8->GetObject(statics.get())->AsString()->Equals("android"));
   s8->SetObject(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));
-  EXPECT_EQ(6, s1->GetByte(statics));
-  EXPECT_EQ('b', s2->GetChar(statics));
-  EXPECT_EQ(-535, s3->GetShort(statics));
-  EXPECT_EQ(2000000001, s4->GetInt(statics));
-  EXPECT_EQ(0x34567890abcdef12LL, s5->GetLong(statics));
-  EXPECT_EQ(0.75, s6->GetFloat(statics));
-  EXPECT_EQ(16777219, s7->GetDouble(statics));
-  EXPECT_TRUE(s8->GetObject(statics)->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(0x34567890abcdef12LL, 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) {
diff --git a/runtime/debugger.cc b/runtime/debugger.cc
index 52a2141..bcf7267 100644
--- a/runtime/debugger.cc
+++ b/runtime/debugger.cc
@@ -452,6 +452,7 @@
 
 void Dbg::StopJdwp() {
   delete gJdwpState;
+  gJdwpState = NULL;
   delete gRegistry;
   gRegistry = NULL;
 }
@@ -795,18 +796,37 @@
 
 JDWP::JdwpError Dbg::DisableCollection(JDWP::ObjectId object_id)
     SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
+  mirror::Object* o = gRegistry->Get<mirror::Object*>(object_id);
+  if (o == NULL || o == ObjectRegistry::kInvalidObject) {
+    return JDWP::ERR_INVALID_OBJECT;
+  }
   gRegistry->DisableCollection(object_id);
   return JDWP::ERR_NONE;
 }
 
 JDWP::JdwpError Dbg::EnableCollection(JDWP::ObjectId object_id)
     SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
+  mirror::Object* o = gRegistry->Get<mirror::Object*>(object_id);
+  // Unlike DisableCollection, JDWP specs do not state an invalid object causes an error. The RI
+  // also ignores these cases and never return an error. However it's not obvious why this command
+  // should behave differently from DisableCollection and IsCollected commands. So let's be more
+  // strict and return an error if this happens.
+  if (o == NULL || o == ObjectRegistry::kInvalidObject) {
+    return JDWP::ERR_INVALID_OBJECT;
+  }
   gRegistry->EnableCollection(object_id);
   return JDWP::ERR_NONE;
 }
 
 JDWP::JdwpError Dbg::IsCollected(JDWP::ObjectId object_id, bool& is_collected)
     SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
+  mirror::Object* o = gRegistry->Get<mirror::Object*>(object_id);
+  // JDWP specs state an INVALID_OBJECT error is returned if the object ID is not valid. However
+  // the RI seems to ignore this and does not return any error in this case. Let's comply with
+  // JDWP specs here.
+  if (o == NULL || o == ObjectRegistry::kInvalidObject) {
+    return JDWP::ERR_INVALID_OBJECT;
+  }
   is_collected = gRegistry->IsCollected(object_id);
   return JDWP::ERR_NONE;
 }
@@ -1113,7 +1133,7 @@
   CHECK(c1 != NULL);
   mirror::Class* c2 = DecodeClass(class_id, status);
   CHECK(c2 != NULL);
-  return c1->IsAssignableFrom(c2);
+  return c2->IsAssignableFrom(c1);
 }
 
 static JDWP::FieldId ToFieldId(const mirror::ArtField* f)
@@ -2712,7 +2732,7 @@
         if (argument == ObjectRegistry::kInvalidObject) {
           return JDWP::ERR_INVALID_OBJECT;
         }
-        if (!argument->InstanceOf(parameter_type)) {
+        if (argument != NULL && !argument->InstanceOf(parameter_type)) {
           return JDWP::ERR_ILLEGAL_ARGUMENT;
         }
 
@@ -2816,30 +2836,30 @@
   }
 
   // Translate the method through the vtable, unless the debugger wants to suppress it.
-  mirror::ArtMethod* m = pReq->method;
+  SirtRef<mirror::ArtMethod> m(soa.Self(), pReq->method);
   if ((pReq->options & JDWP::INVOKE_NONVIRTUAL) == 0 && pReq->receiver != NULL) {
     mirror::ArtMethod* actual_method = pReq->klass->FindVirtualMethodForVirtualOrInterface(pReq->method);
-    if (actual_method != m) {
-      VLOG(jdwp) << "ExecuteMethod translated " << PrettyMethod(m) << " to " << PrettyMethod(actual_method);
-      m = actual_method;
+    if (actual_method != m.get()) {
+      VLOG(jdwp) << "ExecuteMethod translated " << PrettyMethod(m.get()) << " to " << PrettyMethod(actual_method);
+      m.reset(actual_method);
     }
   }
-  VLOG(jdwp) << "ExecuteMethod " << PrettyMethod(m)
+  VLOG(jdwp) << "ExecuteMethod " << PrettyMethod(m.get())
              << " receiver=" << pReq->receiver
              << " arg_count=" << pReq->arg_count;
-  CHECK(m != NULL);
+  CHECK(m.get() != nullptr);
 
   CHECK_EQ(sizeof(jvalue), sizeof(uint64_t));
 
-  MethodHelper mh(m);
+  MethodHelper mh(m.get());
   ArgArray arg_array(mh.GetShorty(), mh.GetShortyLength());
   arg_array.BuildArgArray(soa, pReq->receiver, reinterpret_cast<jvalue*>(pReq->arg_values));
-  InvokeWithArgArray(soa, m, &arg_array, &pReq->result_value, mh.GetShorty()[0]);
+  InvokeWithArgArray(soa, m.get(), &arg_array, &pReq->result_value, mh.GetShorty()[0]);
 
   mirror::Throwable* exception = soa.Self()->GetException(NULL);
   soa.Self()->ClearException();
   pReq->exception = gRegistry->Add(exception);
-  pReq->result_tag = BasicTagFromDescriptor(MethodHelper(m).GetShorty());
+  pReq->result_tag = BasicTagFromDescriptor(MethodHelper(m.get()).GetShorty());
   if (pReq->exception != 0) {
     VLOG(jdwp) << "  JDWP invocation returning with exception=" << exception
         << " " << exception->Dump();
diff --git a/runtime/dex_file.cc b/runtime/dex_file.cc
index 517f96c..429c516 100644
--- a/runtime/dex_file.cc
+++ b/runtime/dex_file.cc
@@ -98,9 +98,10 @@
       *error_msg = StringPrintf("Failed to open zip archive '%s'", filename);
       return false;
     }
-    UniquePtr<ZipEntry> zip_entry(zip_archive->Find(kClassesDex));
+    UniquePtr<ZipEntry> zip_entry(zip_archive->Find(kClassesDex, error_msg));
     if (zip_entry.get() == NULL) {
-      *error_msg = StringPrintf("Zip archive '%s' doesn\'t contain %s", filename, kClassesDex);
+      *error_msg = StringPrintf("Zip archive '%s' doesn't contain %s (error msg: %s)", filename,
+                                kClassesDex, error_msg->c_str());
       return false;
     }
     *checksum = zip_entry->GetCrc32();
@@ -176,7 +177,7 @@
     struct stat sbuf;
     memset(&sbuf, 0, sizeof(sbuf));
     if (fstat(fd, &sbuf) == -1) {
-      *error_msg = StringPrintf("DexFile: fstat \'%s\' failed: %s", location, strerror(errno));
+      *error_msg = StringPrintf("DexFile: fstat '%s' failed: %s", location, strerror(errno));
       return nullptr;
     }
     if (S_ISDIR(sbuf.st_mode)) {
@@ -193,7 +194,7 @@
 
   if (map->Size() < sizeof(DexFile::Header)) {
     *error_msg = StringPrintf(
-        "DexFile: failed to open dex file \'%s\' that is too short to have a header", location);
+        "DexFile: failed to open dex file '%s' that is too short to have a header", location);
     return nullptr;
   }
 
@@ -240,9 +241,8 @@
 const DexFile* DexFile::Open(const ZipArchive& zip_archive, const std::string& location,
                              std::string* error_msg) {
   CHECK(!location.empty());
-  UniquePtr<ZipEntry> zip_entry(zip_archive.Find(kClassesDex));
+  UniquePtr<ZipEntry> zip_entry(zip_archive.Find(kClassesDex, error_msg));
   if (zip_entry.get() == NULL) {
-    *error_msg = StringPrintf("Failed to find classes.dex within '%s'", location.c_str());
     return nullptr;
   }
   UniquePtr<MemMap> map(zip_entry->ExtractToMemMap(kClassesDex, error_msg));
diff --git a/runtime/dex_file_verifier.cc b/runtime/dex_file_verifier.cc
index 56bf21d..dc9d337 100644
--- a/runtime/dex_file_verifier.cc
+++ b/runtime/dex_file_verifier.cc
@@ -16,6 +16,8 @@
 
 #include "dex_file_verifier.h"
 
+#include <zlib.h>
+
 #include "base/stringprintf.h"
 #include "dex_file-inl.h"
 #include "leb128.h"
@@ -23,7 +25,6 @@
 #include "UniquePtr.h"
 #include "utf-inl.h"
 #include "utils.h"
-#include "zip_archive.h"
 
 namespace art {
 
diff --git a/runtime/dex_method_iterator_test.cc b/runtime/dex_method_iterator_test.cc
index 9961df9..2941db6 100644
--- a/runtime/dex_method_iterator_test.cc
+++ b/runtime/dex_method_iterator_test.cc
@@ -36,7 +36,7 @@
 TEST_F(DexMethodIteratorTest, Basic) {
   ScopedObjectAccess soa(Thread::Current());
   std::vector<const DexFile*> dex_files;
-  dex_files.push_back(OpenDexFile("core"));
+  dex_files.push_back(OpenDexFile("core-libart"));
   dex_files.push_back(OpenDexFile("conscrypt"));
   dex_files.push_back(OpenDexFile("okhttp"));
   dex_files.push_back(OpenDexFile("core-junit"));
diff --git a/runtime/entrypoints/entrypoint_utils.cc b/runtime/entrypoints/entrypoint_utils.cc
index 2806f94..3ab8888 100644
--- a/runtime/entrypoints/entrypoint_utils.cc
+++ b/runtime/entrypoints/entrypoint_utils.cc
@@ -57,7 +57,7 @@
       ThrowLocation throw_location = self->GetCurrentLocationForThrow();
       DCHECK(throw_location.GetMethod() == referrer);
       self->ThrowNewExceptionF(throw_location, "Ljava/lang/InternalError;",
-                               "Found type %s; filled-new-array not implemented for anything but \'int\'",
+                               "Found type %s; filled-new-array not implemented for anything but 'int'",
                                PrettyDescriptor(klass).c_str());
     }
     return nullptr;  // Failure
diff --git a/runtime/entrypoints/entrypoint_utils.h b/runtime/entrypoints/entrypoint_utils.h
index 747dd56..a60446c 100644
--- a/runtime/entrypoints/entrypoint_utils.h
+++ b/runtime/entrypoints/entrypoint_utils.h
@@ -72,7 +72,7 @@
   if (UNLIKELY(!klass->IsInitialized())) {
     SirtRef<mirror::Class> sirt_klass(self, klass);
     // The class initializer might cause a GC.
-    if (!Runtime::Current()->GetClassLinker()->EnsureInitialized(klass, true, true)) {
+    if (!Runtime::Current()->GetClassLinker()->EnsureInitialized(sirt_klass, true, true)) {
       DCHECK(self->IsExceptionPending());
       return nullptr;  // Failure
     }
@@ -246,12 +246,15 @@
     // If the class is initialized we're done.
     if (LIKELY(fields_class->IsInitialized())) {
       return resolved_field;
-    } else if (LIKELY(class_linker->EnsureInitialized(fields_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
+      SirtRef<mirror::Class> sirt_class(self, fields_class);
+      if (LIKELY(class_linker->EnsureInitialized(sirt_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
+      }
     }
   }
 }
@@ -259,9 +262,9 @@
 // Explicit template declarations of FindFieldFromCode for all field access types.
 #define EXPLICIT_FIND_FIELD_FROM_CODE_TEMPLATE_DECL(_type, _access_check) \
 template SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) ALWAYS_INLINE \
-static mirror::ArtField* FindFieldFromCode<_type, _access_check>(uint32_t field_idx, \
-                                                                 const mirror::ArtMethod* referrer, \
-                                                                 Thread* self, size_t expected_size) \
+mirror::ArtField* FindFieldFromCode<_type, _access_check>(uint32_t field_idx, \
+                                                          const mirror::ArtMethod* referrer, \
+                                                          Thread* self, size_t expected_size) \
 
 #define EXPLICIT_FIND_FIELD_FROM_CODE_TYPED_TEMPLATE_DECL(_type) \
     EXPLICIT_FIND_FIELD_FROM_CODE_TEMPLATE_DECL(_type, false); \
@@ -390,12 +393,12 @@
 }
 
 // Explicit template declarations of FindMethodFromCode for all invoke types.
-#define EXPLICIT_FIND_METHOD_FROM_CODE_TEMPLATE_DECL(_type, _access_check)                        \
-  template SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) ALWAYS_INLINE                              \
-  static mirror::ArtMethod* FindMethodFromCode<_type, _access_check>(uint32_t method_idx,         \
-                                                                     mirror::Object* this_object, \
-                                                                     mirror::ArtMethod* referrer, \
-                                                                     Thread* self)
+#define EXPLICIT_FIND_METHOD_FROM_CODE_TEMPLATE_DECL(_type, _access_check)                 \
+  template SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) ALWAYS_INLINE                       \
+  mirror::ArtMethod* FindMethodFromCode<_type, _access_check>(uint32_t method_idx,         \
+                                                              mirror::Object* this_object, \
+                                                              mirror::ArtMethod* referrer, \
+                                                              Thread* self)
 #define EXPLICIT_FIND_METHOD_FROM_CODE_TYPED_TEMPLATE_DECL(_type) \
     EXPLICIT_FIND_METHOD_FROM_CODE_TEMPLATE_DECL(_type, false);   \
     EXPLICIT_FIND_METHOD_FROM_CODE_TEMPLATE_DECL(_type, true)
@@ -535,12 +538,13 @@
   if (klass == referring_class && referrer->IsConstructor() && referrer->IsStatic()) {
     return klass;
   }
-  if (!class_linker->EnsureInitialized(klass, true, true)) {
+  SirtRef<mirror::Class> sirt_class(self, klass);
+  if (!class_linker->EnsureInitialized(sirt_class, true, true)) {
     CHECK(self->IsExceptionPending());
     return NULL;  // Failure - Indicate to caller to deliver exception
   }
-  referrer->GetDexCacheInitializedStaticStorage()->Set(type_idx, klass);
-  return klass;
+  referrer->GetDexCacheInitializedStaticStorage()->Set(type_idx, sirt_class.get());
+  return sirt_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 05c02f2..0df00c2 100644
--- a/runtime/entrypoints/interpreter/interpreter_entrypoints.cc
+++ b/runtime/entrypoints/interpreter/interpreter_entrypoints.cc
@@ -33,12 +33,15 @@
   if (method->IsStatic()) {
     mirror::Class* declaringClass = method->GetDeclaringClass();
     if (UNLIKELY(!declaringClass->IsInitializing())) {
-      if (UNLIKELY(!Runtime::Current()->GetClassLinker()->EnsureInitialized(declaringClass,
-                                                                            true, true))) {
-        DCHECK(Thread::Current()->IsExceptionPending());
+      self->PushShadowFrame(shadow_frame);
+      SirtRef<mirror::Class> sirt_c(self, declaringClass);
+      if (UNLIKELY(!Runtime::Current()->GetClassLinker()->EnsureInitialized(sirt_c, true, true))) {
+        self->PopShadowFrame();
+        DCHECK(self->IsExceptionPending());
         return;
       }
-      CHECK(declaringClass->IsInitializing());
+      self->PopShadowFrame();
+      CHECK(sirt_c->IsInitializing());
     }
   }
   uint16_t arg_offset = (code_item == NULL) ? 0 : code_item->registers_size_ - code_item->ins_size_;
diff --git a/runtime/entrypoints/jni/jni_entrypoints.cc b/runtime/entrypoints/jni/jni_entrypoints.cc
index 16364fc..4d1e531 100644
--- a/runtime/entrypoints/jni/jni_entrypoints.cc
+++ b/runtime/entrypoints/jni/jni_entrypoints.cc
@@ -50,7 +50,7 @@
   intptr_t value = *arg_ptr;
   mirror::Object** value_as_jni_rep = reinterpret_cast<mirror::Object**>(value);
   mirror::Object* value_as_work_around_rep = value_as_jni_rep != NULL ? *value_as_jni_rep : NULL;
-  CHECK(Runtime::Current()->GetHeap()->IsHeapAddress(value_as_work_around_rep))
+  CHECK(Runtime::Current()->GetHeap()->IsValidObjectAddress(value_as_work_around_rep))
       << value_as_work_around_rep;
   *arg_ptr = reinterpret_cast<intptr_t>(value_as_work_around_rep);
 }
diff --git a/runtime/entrypoints/portable/portable_invoke_entrypoints.cc b/runtime/entrypoints/portable/portable_invoke_entrypoints.cc
index e2a0cc2..47ccbb1 100644
--- a/runtime/entrypoints/portable/portable_invoke_entrypoints.cc
+++ b/runtime/entrypoints/portable/portable_invoke_entrypoints.cc
@@ -22,8 +22,8 @@
 namespace art {
 
 template<InvokeType type, bool access_check>
-static mirror::ArtMethod* FindMethodHelper(uint32_t method_idx, mirror::Object* this_object,
-                                           mirror::ArtMethod* caller_method, Thread* thread) {
+mirror::ArtMethod* FindMethodHelper(uint32_t method_idx, mirror::Object* this_object,
+                                    mirror::ArtMethod* caller_method, Thread* thread) {
   mirror::ArtMethod* method = FindMethodFast(method_idx, this_object, caller_method,
                                              access_check, type);
   if (UNLIKELY(method == NULL)) {
@@ -46,12 +46,12 @@
 }
 
 // Explicit template declarations of FindMethodHelper for all invoke types.
-#define EXPLICIT_FIND_METHOD_HELPER_TEMPLATE_DECL(_type, _access_check)                               \
-  template SHARED_LOCKS_REQUIRED(Locks::mutator_lock_)                                                \
-  static mirror::ArtMethod* FindMethodHelper<_type, _access_check>(uint32_t method_idx,               \
-                                                                   mirror::Object* this_object,       \
-                                                                   mirror::ArtMethod* caller_method,  \
-                                                                   Thread* thread)
+#define EXPLICIT_FIND_METHOD_HELPER_TEMPLATE_DECL(_type, _access_check)                        \
+  template SHARED_LOCKS_REQUIRED(Locks::mutator_lock_)                                         \
+  mirror::ArtMethod* FindMethodHelper<_type, _access_check>(uint32_t method_idx,               \
+                                                            mirror::Object* this_object,       \
+                                                            mirror::ArtMethod* caller_method,  \
+                                                            Thread* thread)
 #define EXPLICIT_FIND_METHOD_HELPER_TYPED_TEMPLATE_DECL(_type) \
     EXPLICIT_FIND_METHOD_HELPER_TEMPLATE_DECL(_type, false);   \
     EXPLICIT_FIND_METHOD_HELPER_TEMPLATE_DECL(_type, true)
diff --git a/runtime/entrypoints/portable/portable_thread_entrypoints.cc b/runtime/entrypoints/portable/portable_thread_entrypoints.cc
index 8a2c899..4f19964 100644
--- a/runtime/entrypoints/portable/portable_thread_entrypoints.cc
+++ b/runtime/entrypoints/portable/portable_thread_entrypoints.cc
@@ -36,11 +36,7 @@
       ShadowFrame* new_frame = ShadowFrame::Create(num_regs, NULL, method, dex_pc);
 
       const uint8_t* gc_map = method->GetNativeGcMap();
-      uint32_t gc_map_length = static_cast<uint32_t>((gc_map[0] << 24) |
-                                                     (gc_map[1] << 16) |
-                                                     (gc_map[2] << 8) |
-                                                     (gc_map[3] << 0));
-      verifier::DexPcToReferenceMap dex_gc_map(gc_map + 4, gc_map_length);
+      verifier::DexPcToReferenceMap dex_gc_map(gc_map);
       const uint8_t* reg_bitmap = dex_gc_map.FindBitMap(dex_pc);
       for (size_t reg = 0; reg < num_regs; ++reg) {
         if (TestBitmap(reg, reg_bitmap)) {
diff --git a/runtime/entrypoints/portable/portable_trampoline_entrypoints.cc b/runtime/entrypoints/portable/portable_trampoline_entrypoints.cc
index 61f7440..2162dcc 100644
--- a/runtime/entrypoints/portable/portable_trampoline_entrypoints.cc
+++ b/runtime/entrypoints/portable/portable_trampoline_entrypoints.cc
@@ -208,8 +208,8 @@
 
     if (method->IsStatic() && !method->GetDeclaringClass()->IsInitializing()) {
       // Ensure static method's class is initialized.
-      if (!Runtime::Current()->GetClassLinker()->EnsureInitialized(method->GetDeclaringClass(),
-                                                                   true, true)) {
+      SirtRef<mirror::Class> sirt_c(self, method->GetDeclaringClass());
+      if (!Runtime::Current()->GetClassLinker()->EnsureInitialized(sirt_c, true, true)) {
         DCHECK(Thread::Current()->IsExceptionPending());
         self->PopManagedStackFragment(fragment);
         return 0;
@@ -390,7 +390,7 @@
   const void* code = NULL;
   if (LIKELY(!thread->IsExceptionPending())) {
     // Ensure that the called method's class is initialized.
-    mirror::Class* called_class = called->GetDeclaringClass();
+    SirtRef<mirror::Class> called_class(thread, called->GetDeclaringClass());
     linker->EnsureInitialized(called_class, true, true);
     if (LIKELY(called_class->IsInitialized())) {
       code = called->GetEntryPointFromCompiledCode();
diff --git a/runtime/entrypoints/quick/quick_invoke_entrypoints.cc b/runtime/entrypoints/quick/quick_invoke_entrypoints.cc
index b852a32..5a1b3e8 100644
--- a/runtime/entrypoints/quick/quick_invoke_entrypoints.cc
+++ b/runtime/entrypoints/quick/quick_invoke_entrypoints.cc
@@ -142,9 +142,9 @@
 }
 
 template<InvokeType type, bool access_check>
-static uint64_t artInvokeCommon(uint32_t method_idx, mirror::Object* this_object,
-                                mirror::ArtMethod* caller_method,
-                                Thread* self, mirror::ArtMethod** sp) {
+uint64_t artInvokeCommon(uint32_t method_idx, mirror::Object* this_object,
+                         mirror::ArtMethod* caller_method,
+                         Thread* self, mirror::ArtMethod** sp) {
   mirror::ArtMethod* method = FindMethodFast(method_idx, this_object, caller_method,
                                                   access_check, type);
   if (UNLIKELY(method == NULL)) {
@@ -174,12 +174,12 @@
 }
 
 // Explicit template declarations of artInvokeCommon for all invoke types.
-#define EXPLICIT_ART_INVOKE_COMMON_TEMPLATE_DECL(_type, _access_check)                        \
-  template SHARED_LOCKS_REQUIRED(Locks::mutator_lock_)                                        \
-  static uint64_t artInvokeCommon<_type, _access_check>(uint32_t method_idx,                  \
-                                                        mirror::Object* this_object,          \
-                                                        mirror::ArtMethod* caller_method,     \
-                                                        Thread* self, mirror::ArtMethod** sp)
+#define EXPLICIT_ART_INVOKE_COMMON_TEMPLATE_DECL(_type, _access_check)                 \
+  template SHARED_LOCKS_REQUIRED(Locks::mutator_lock_)                                 \
+  uint64_t artInvokeCommon<_type, _access_check>(uint32_t method_idx,                  \
+                                                 mirror::Object* this_object,          \
+                                                 mirror::ArtMethod* caller_method,     \
+                                                 Thread* self, mirror::ArtMethod** sp)
 
 #define EXPLICIT_ART_INVOKE_COMMON_TYPED_TEMPLATE_DECL(_type) \
     EXPLICIT_ART_INVOKE_COMMON_TEMPLATE_DECL(_type, false);   \
diff --git a/runtime/entrypoints/quick/quick_trampoline_entrypoints.cc b/runtime/entrypoints/quick/quick_trampoline_entrypoints.cc
index 8ba08ee..b589384 100644
--- a/runtime/entrypoints/quick/quick_trampoline_entrypoints.cc
+++ b/runtime/entrypoints/quick/quick_trampoline_entrypoints.cc
@@ -298,8 +298,8 @@
 
     if (method->IsStatic() && !method->GetDeclaringClass()->IsInitializing()) {
       // Ensure static method's class is initialized.
-      if (!Runtime::Current()->GetClassLinker()->EnsureInitialized(method->GetDeclaringClass(),
-                                                                   true, true)) {
+      SirtRef<mirror::Class> sirt_c(self, method->GetDeclaringClass());
+      if (!Runtime::Current()->GetClassLinker()->EnsureInitialized(sirt_c, true, true)) {
         DCHECK(Thread::Current()->IsExceptionPending());
         self->PopManagedStackFragment(fragment);
         return 0;
@@ -564,7 +564,7 @@
       }
     }
     // Ensure that the called method's class is initialized.
-    mirror::Class* called_class = called->GetDeclaringClass();
+    SirtRef<mirror::Class> called_class(soa.Self(), called->GetDeclaringClass());
     linker->EnsureInitialized(called_class, true, true);
     if (LIKELY(called_class->IsInitialized())) {
       code = called->GetEntryPointFromCompiledCode();
diff --git a/runtime/exception_test.cc b/runtime/exception_test.cc
index e9a6e4f..978faeb 100644
--- a/runtime/exception_test.cc
+++ b/runtime/exception_test.cc
@@ -37,11 +37,13 @@
     CommonTest::SetUp();
 
     ScopedObjectAccess soa(Thread::Current());
-    SirtRef<mirror::ClassLoader> class_loader(soa.Self(),
-                                      soa.Decode<mirror::ClassLoader*>(LoadDex("ExceptionHandle")));
+    SirtRef<mirror::ClassLoader> class_loader(
+        soa.Self(), soa.Decode<mirror::ClassLoader*>(LoadDex("ExceptionHandle")));
     my_klass_ = class_linker_->FindClass("LExceptionHandle;", class_loader);
     ASSERT_TRUE(my_klass_ != NULL);
-    class_linker_->EnsureInitialized(my_klass_, true, true);
+    SirtRef<mirror::Class> sirt_klass(soa.Self(), my_klass_);
+    class_linker_->EnsureInitialized(sirt_klass, true, true);
+    my_klass_ = sirt_klass.get();
 
     dex_ = my_klass_->GetDexCache()->GetDexFile();
 
@@ -54,17 +56,17 @@
       fake_code_.push_back(0x70 | i);
     }
 
-    fake_mapping_data_.PushBack(4);  // first element is count
-    fake_mapping_data_.PushBack(4);  // total (non-length) elements
-    fake_mapping_data_.PushBack(2);  // count of pc to dex elements
+    fake_mapping_data_.PushBackUnsigned(4);  // first element is count
+    fake_mapping_data_.PushBackUnsigned(4);  // total (non-length) elements
+    fake_mapping_data_.PushBackUnsigned(2);  // count of pc to dex elements
                                       // ---  pc to dex table
-    fake_mapping_data_.PushBack(3);  // offset 3
-    fake_mapping_data_.PushBack(3);  // maps to dex offset 3
+    fake_mapping_data_.PushBackUnsigned(3 - 0);  // offset 3
+    fake_mapping_data_.PushBackSigned(3 - 0);    // maps to dex offset 3
                                       // ---  dex to pc table
-    fake_mapping_data_.PushBack(3);  // offset 3
-    fake_mapping_data_.PushBack(3);  // maps to dex offset 3
+    fake_mapping_data_.PushBackUnsigned(3 - 0);  // offset 3
+    fake_mapping_data_.PushBackSigned(3 - 0);    // maps to dex offset 3
 
-    fake_vmap_table_data_.PushBack(0);
+    fake_vmap_table_data_.PushBackUnsigned(0);
 
     fake_gc_map_.push_back(0);  // 0 bytes to encode references and native pc offsets.
     fake_gc_map_.push_back(0);
@@ -91,8 +93,8 @@
   const DexFile* dex_;
 
   std::vector<uint8_t> fake_code_;
-  UnsignedLeb128EncodingVector fake_mapping_data_;
-  UnsignedLeb128EncodingVector fake_vmap_table_data_;
+  Leb128EncodingVector fake_mapping_data_;
+  Leb128EncodingVector fake_vmap_table_data_;
   std::vector<uint8_t> fake_gc_map_;
 
   mirror::ArtMethod* method_f_;
diff --git a/runtime/gc/accounting/card_table.cc b/runtime/gc/accounting/card_table.cc
index 7818bc8..e099137 100644
--- a/runtime/gc/accounting/card_table.cc
+++ b/runtime/gc/accounting/card_table.cc
@@ -95,8 +95,8 @@
 }
 
 void CardTable::ClearCardTable() {
-  // TODO: clear just the range of the table that has been modified
-  memset(mem_map_->Begin(), kCardClean, mem_map_->Size());
+  COMPILE_ASSERT(kCardClean == 0, clean_card_must_be_0);
+  madvise(mem_map_->Begin(), mem_map_->Size(), MADV_DONTNEED);
 }
 
 bool CardTable::AddrIsInCardTable(const void* addr) const {
diff --git a/runtime/gc/accounting/mod_union_table.cc b/runtime/gc/accounting/mod_union_table.cc
index faa198a..b428e74 100644
--- a/runtime/gc/accounting/mod_union_table.cc
+++ b/runtime/gc/accounting/mod_union_table.cc
@@ -82,7 +82,7 @@
     if (ref != nullptr) {
       Object* new_ref = visitor_(ref, arg_);
       if (new_ref != ref) {
-        obj->SetFieldObject(offset, new_ref, true);
+        obj->SetFieldPtr(offset, new_ref, true);
       }
     }
   }
diff --git a/runtime/gc/collector/mark_sweep-inl.h b/runtime/gc/collector/mark_sweep-inl.h
index 7a51553..9c1c5dc 100644
--- a/runtime/gc/collector/mark_sweep-inl.h
+++ b/runtime/gc/collector/mark_sweep-inl.h
@@ -69,15 +69,14 @@
   DCHECK(obj->GetClass() != NULL);
   mirror::Class* klass = obj->GetClass();
   DCHECK(klass != NULL);
-  if (visit_class) {
-    visitor(obj, klass, mirror::Object::ClassOffset(), false);
-  }
   if (klass == mirror::Class::GetJavaLangClass()) {
     DCHECK_EQ(klass->GetClass(), mirror::Class::GetJavaLangClass());
     VisitClassReferences(klass, obj, visitor);
   } else {
     if (klass->IsArrayClass()) {
-      visitor(obj, klass, mirror::Object::ClassOffset(), false);
+      if (visit_class) {
+        visitor(obj, klass, mirror::Object::ClassOffset(), false);
+      }
       if (klass->IsObjectArrayClass()) {
         VisitObjectArrayReferences(obj->AsObjectArray<mirror::Object>(), visitor);
       }
diff --git a/runtime/gc/collector/mark_sweep.cc b/runtime/gc/collector/mark_sweep.cc
index 0697a65..28cc510 100644
--- a/runtime/gc/collector/mark_sweep.cc
+++ b/runtime/gc/collector/mark_sweep.cc
@@ -669,7 +669,7 @@
       MarkSweep* mark_sweep = chunk_task_->mark_sweep_;
       mark_sweep->ScanObjectVisit(obj,
           [mark_sweep, this](Object* /* obj */, Object* ref, const MemberOffset& /* offset */,
-              bool /* is_static */) ALWAYS_INLINE {
+              bool /* is_static */) ALWAYS_INLINE_LAMBDA {
         if (ref != nullptr && mark_sweep->MarkObjectParallel(ref)) {
           if (kUseFinger) {
             android_memory_barrier();
diff --git a/runtime/gc/collector/mark_sweep.h b/runtime/gc/collector/mark_sweep.h
index 53d85b0..62991bb 100644
--- a/runtime/gc/collector/mark_sweep.h
+++ b/runtime/gc/collector/mark_sweep.h
@@ -89,10 +89,12 @@
       SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
 
   void MarkNonThreadRoots()
-      EXCLUSIVE_LOCKS_REQUIRED(Locks::heap_bitmap_lock_);
+      EXCLUSIVE_LOCKS_REQUIRED(Locks::heap_bitmap_lock_)
+      SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
 
-  void MarkConcurrentRoots();
-      EXCLUSIVE_LOCKS_REQUIRED(Locks::heap_bitmap_lock_);
+  void MarkConcurrentRoots()
+      EXCLUSIVE_LOCKS_REQUIRED(Locks::heap_bitmap_lock_)
+      SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
 
   void MarkRootsCheckpoint(Thread* self)
       EXCLUSIVE_LOCKS_REQUIRED(Locks::heap_bitmap_lock_)
diff --git a/runtime/gc/collector/semi_space.cc b/runtime/gc/collector/semi_space.cc
index 3939354..923560e 100644
--- a/runtime/gc/collector/semi_space.cc
+++ b/runtime/gc/collector/semi_space.cc
@@ -78,6 +78,8 @@
 
 static constexpr bool kProtectFromSpace = true;
 static constexpr bool kResetFromSpace = true;
+// TODO: move this to a new file as a new garbage collector?
+static constexpr bool kEnableSimplePromo = false;
 
 // TODO: Unduplicate logic.
 void SemiSpace::ImmuneSpace(space::ContinuousSpace* space) {
@@ -134,7 +136,9 @@
       finalizer_reference_list_(nullptr),
       phantom_reference_list_(nullptr),
       cleared_reference_list_(nullptr),
-      self_(nullptr) {
+      self_(nullptr),
+      last_gc_to_space_end_(nullptr),
+      bytes_promoted_(0) {
 }
 
 void SemiSpace::InitializePhase() {
@@ -169,10 +173,25 @@
   // Need to do this with mutators paused so that somebody doesn't accidentally allocate into the
   // wrong space.
   heap_->SwapSemiSpaces();
+  if (kEnableSimplePromo) {
+    // If last_gc_to_space_end_ is out of the bounds of the from-space
+    // (the to-space from last GC), then point it to the beginning of
+    // the from-space. For example, the very first GC or the
+    // pre-zygote compaction.
+    if (!from_space_->HasAddress(reinterpret_cast<mirror::Object*>(last_gc_to_space_end_))) {
+      last_gc_to_space_end_ = from_space_->Begin();
+    }
+    // Reset this before the marking starts below.
+    bytes_promoted_ = 0;
+  }
   // Assume the cleared space is already empty.
   BindBitmaps();
   // Process dirty cards and add dirty cards to mod-union tables.
   heap_->ProcessCards(timings_);
+  // 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();
   // Need to do this before the checkpoint since we don't want any threads to add references to
   // the live stack during the recursive mark.
   timings_.NewSplit("SwapStacks");
@@ -268,6 +287,13 @@
   } else {
     mprotect(from_space_->Begin(), from_space_->Capacity(), PROT_READ);
   }
+
+  if (kEnableSimplePromo) {
+    // Record the end (top) of the to space so we can distinguish
+    // between objects that were allocated since the last GC and the
+    // older objects.
+    last_gc_to_space_end_ = to_space_->End();
+  }
 }
 
 void SemiSpace::ResizeMarkStack(size_t new_size) {
@@ -308,20 +334,48 @@
     if (from_space_->HasAddress(obj)) {
       mirror::Object* forward_address = GetForwardingAddressInFromSpace(obj);
       // If the object has already been moved, return the new forward address.
-      if (!to_space_->HasAddress(forward_address)) {
+      if (forward_address == nullptr) {
         // Otherwise, we need to move the object and add it to the markstack for processing.
         size_t object_size = obj->SizeOf();
         size_t dummy = 0;
-        forward_address = to_space_->Alloc(self_, object_size, &dummy);
+        if (kEnableSimplePromo && reinterpret_cast<byte*>(obj) < last_gc_to_space_end_) {
+          // If it's allocated before the last GC (older), move (pseudo-promote) it to
+          // the non-moving space (as sort of an old generation.)
+          size_t bytes_promoted;
+          space::MallocSpace* non_moving_space = GetHeap()->GetNonMovingSpace();
+          forward_address = non_moving_space->Alloc(self_, object_size, &bytes_promoted);
+          if (forward_address == nullptr) {
+            // If out of space, fall back to the to-space.
+            forward_address = to_space_->Alloc(self_, object_size, &dummy);
+          } else {
+            GetHeap()->num_bytes_allocated_.fetch_add(bytes_promoted);
+            bytes_promoted_ += bytes_promoted;
+            // Mark forward_address on the live bit map.
+            accounting::SpaceBitmap* live_bitmap = non_moving_space->GetLiveBitmap();
+            DCHECK(live_bitmap != nullptr);
+            DCHECK(!live_bitmap->Test(forward_address));
+            live_bitmap->Set(forward_address);
+            // Mark forward_address on the mark bit map.
+            accounting::SpaceBitmap* mark_bitmap = non_moving_space->GetMarkBitmap();
+            DCHECK(mark_bitmap != nullptr);
+            DCHECK(!mark_bitmap->Test(forward_address));
+            mark_bitmap->Set(forward_address);
+          }
+          DCHECK(forward_address != nullptr);
+        } else {
+          // If it's allocated after the last GC (younger), copy it to the to-space.
+          forward_address = to_space_->Alloc(self_, object_size, &dummy);
+        }
         // Copy over the object and add it to the mark stack since we still need to update it's
         // references.
         memcpy(reinterpret_cast<void*>(forward_address), obj, object_size);
         // Make sure to only update the forwarding address AFTER you copy the object so that the
         // monitor word doesn't get stomped over.
-        COMPILE_ASSERT(sizeof(uint32_t) == sizeof(mirror::Object*),
-                       monitor_size_must_be_same_as_object);
         obj->SetLockWord(LockWord::FromForwardingAddress(reinterpret_cast<size_t>(forward_address)));
         MarkStackPush(forward_address);
+      } else {
+        DCHECK(to_space_->HasAddress(forward_address) ||
+               (kEnableSimplePromo && GetHeap()->GetNonMovingSpace()->HasAddress(forward_address)));
       }
       ret = forward_address;
       // TODO: Do we need this if in the else statement?
@@ -504,11 +558,14 @@
   DCHECK(obj != NULL);
   DCHECK(!from_space_->HasAddress(obj)) << "Scanning object " << obj << " in from space";
   MarkSweep::VisitObjectReferences(obj, [this](Object* obj, Object* ref, const MemberOffset& offset,
-     bool /* is_static */) ALWAYS_INLINE NO_THREAD_SAFETY_ANALYSIS {
+     bool /* is_static */) ALWAYS_INLINE_LAMBDA NO_THREAD_SAFETY_ANALYSIS {
     mirror::Object* new_address = MarkObject(ref);
     if (new_address != ref) {
       DCHECK(new_address != nullptr);
-      obj->SetFieldObject(offset, new_address, false);
+      // Don't need to mark the card since we updating the object address and not changing the
+      // actual objects its pointing to. Using SetFieldPtr is better in this case since it does not
+      // dirty cards and use additional memory.
+      obj->SetFieldPtr(offset, new_address, false);
     }
   }, kMovingClasses);
   mirror::Class* klass = obj->GetClass();
@@ -535,7 +592,9 @@
   if (from_space_->HasAddress(obj)) {
     mirror::Object* forwarding_address = GetForwardingAddressInFromSpace(const_cast<Object*>(obj));
     // If the object is forwarded then it MUST be marked.
-    if (to_space_->HasAddress(forwarding_address)) {
+    DCHECK(forwarding_address == nullptr || to_space_->HasAddress(forwarding_address) ||
+           (kEnableSimplePromo && GetHeap()->GetNonMovingSpace()->HasAddress(forwarding_address)));
+    if (forwarding_address != nullptr) {
       return forwarding_address;
     }
     // Must not be marked, return nullptr;
diff --git a/runtime/gc/collector/semi_space.h b/runtime/gc/collector/semi_space.h
index 0f0cae1..b0724f9 100644
--- a/runtime/gc/collector/semi_space.h
+++ b/runtime/gc/collector/semi_space.h
@@ -281,6 +281,15 @@
 
   Thread* self_;
 
+  // Used for kEnableSimplePromo. The end/top of the bump pointer
+  // space at the end of the last collection.
+  byte* last_gc_to_space_end_;
+
+  // Used for kEnableSimplePromo. During a collection, keeps track of
+  // how many bytes of objects have been copied so far from the bump
+  // pointer space to the non-moving space.
+  uint64_t bytes_promoted_;
+
  private:
   DISALLOW_COPY_AND_ASSIGN(SemiSpace);
 };
diff --git a/runtime/gc/collector_type.h b/runtime/gc/collector_type.h
index ba3cad6..06395cf 100644
--- a/runtime/gc/collector_type.h
+++ b/runtime/gc/collector_type.h
@@ -24,6 +24,8 @@
 
 // Which types of collections are able to be performed.
 enum CollectorType {
+  // No collector selected.
+  kCollectorTypeNone,
   // Non concurrent mark-sweep.
   kCollectorTypeMS,
   // Concurrent mark-sweep.
diff --git a/runtime/gc/heap-inl.h b/runtime/gc/heap-inl.h
index 5eda0b9..99f084a 100644
--- a/runtime/gc/heap-inl.h
+++ b/runtime/gc/heap-inl.h
@@ -41,24 +41,20 @@
   // done in the runnable state where suspension is expected.
   DCHECK_EQ(self->GetState(), kRunnable);
   self->AssertThreadSuspensionIsAllowable();
+  // Need to check that we arent the large object allocator since the large object allocation code
+  // path this function. If we didn't check we would have an infinite loop.
+  if (allocator != kAllocatorTypeLOS && UNLIKELY(ShouldAllocLargeObject(klass, byte_count))) {
+    return AllocLargeObject<kInstrumented, PreFenceVisitor>(self, klass, byte_count,
+                                                            pre_fence_visitor);
+  }
   mirror::Object* obj;
   size_t bytes_allocated;
   AllocationTimer alloc_timer(this, &obj);
-  if (UNLIKELY(ShouldAllocLargeObject(klass, byte_count))) {
-    obj = TryToAllocate<kInstrumented>(self, kAllocatorTypeLOS, byte_count, false,
-                                       &bytes_allocated);
-    allocator = kAllocatorTypeLOS;
-  } else {
-    obj = TryToAllocate<kInstrumented>(self, allocator, byte_count, false, &bytes_allocated);
-  }
-
+  obj = TryToAllocate<kInstrumented, false>(self, allocator, byte_count, &bytes_allocated);
   if (UNLIKELY(obj == nullptr)) {
-    SirtRef<mirror::Class> sirt_c(self, klass);
-    obj = AllocateInternalWithGc(self, allocator, byte_count, &bytes_allocated);
+    obj = AllocateInternalWithGc(self, allocator, byte_count, &bytes_allocated, &klass);
     if (obj == nullptr) {
       return nullptr;
-    } else {
-      klass = sirt_c.get();
     }
   }
   obj->SetClass(klass);
@@ -93,7 +89,7 @@
   } else {
     DCHECK(!Dbg::IsAllocTrackingEnabled());
   }
-  if (AllocatorHasConcurrentGC(allocator)) {
+  if (concurrent_gc_) {
     CheckConcurrentGC(self, new_num_bytes_allocated, obj);
   }
   if (kIsDebugBuild) {
@@ -105,17 +101,28 @@
   return obj;
 }
 
-template <const bool kInstrumented>
+template <bool kInstrumented, typename PreFenceVisitor>
+inline mirror::Object* Heap::AllocLargeObject(Thread* self, mirror::Class* klass,
+                                              size_t byte_count,
+                                              const PreFenceVisitor& pre_fence_visitor) {
+  return AllocObjectWithAllocator<kInstrumented, PreFenceVisitor>(self, klass, byte_count,
+                                                                  kAllocatorTypeLOS,
+                                                                  pre_fence_visitor);
+}
+
+template <const bool kInstrumented, const bool kGrow>
 inline mirror::Object* Heap::TryToAllocate(Thread* self, AllocatorType allocator_type,
-                                           size_t alloc_size, bool grow,
-                                           size_t* bytes_allocated) {
-  if (UNLIKELY(IsOutOfMemoryOnAllocation(alloc_size, grow))) {
+                                           size_t alloc_size, size_t* bytes_allocated) {
+  if (UNLIKELY(IsOutOfMemoryOnAllocation<kGrow>(alloc_size))) {
     return nullptr;
   }
   if (kInstrumented) {
     if (UNLIKELY(running_on_valgrind_ && allocator_type == kAllocatorTypeFreeList)) {
       return non_moving_space_->Alloc(self, alloc_size, bytes_allocated);
     }
+  } else {
+    // If running on valgrind, we should be using the instrumented path.
+    DCHECK(!running_on_valgrind_);
   }
   mirror::Object* ret;
   switch (allocator_type) {
@@ -187,18 +194,21 @@
   return byte_count >= kLargeObjectThreshold && have_zygote_space_ && c->IsPrimitiveArray();
 }
 
-inline bool Heap::IsOutOfMemoryOnAllocation(size_t alloc_size, bool grow) {
+template <const bool kGrow>
+inline bool Heap::IsOutOfMemoryOnAllocation(size_t alloc_size) {
   size_t new_footprint = num_bytes_allocated_ + alloc_size;
   if (UNLIKELY(new_footprint > max_allowed_footprint_)) {
     if (UNLIKELY(new_footprint > growth_limit_)) {
       return true;
     }
     if (!concurrent_gc_) {
-      if (!grow) {
+      if (!kGrow) {
         return true;
-      } else {
-        max_allowed_footprint_ = new_footprint;
       }
+      // TODO: Grow for allocation is racy, fix it.
+      VLOG(heap) << "Growing heap from " << PrettySize(max_allowed_footprint_) << " to "
+          << PrettySize(new_footprint) << " for a " << PrettySize(alloc_size) << " allocation";
+      max_allowed_footprint_ = new_footprint;
     }
   }
   return false;
diff --git a/runtime/gc/heap.cc b/runtime/gc/heap.cc
index 5e62729..11acd33 100644
--- a/runtime/gc/heap.cc
+++ b/runtime/gc/heap.cc
@@ -75,12 +75,13 @@
 
 Heap::Heap(size_t initial_size, size_t growth_limit, size_t min_free, size_t max_free,
            double target_utilization, size_t capacity, const std::string& image_file_name,
-           CollectorType collector_type, size_t parallel_gc_threads, size_t conc_gc_threads,
-           bool low_memory_mode, size_t long_pause_log_threshold, size_t long_gc_log_threshold,
-           bool ignore_max_footprint)
+           CollectorType post_zygote_collector_type, size_t parallel_gc_threads,
+           size_t conc_gc_threads, bool low_memory_mode, size_t long_pause_log_threshold,
+           size_t long_gc_log_threshold, bool ignore_max_footprint)
     : non_moving_space_(nullptr),
-      concurrent_gc_(collector_type == gc::kCollectorTypeCMS),
-      collector_type_(collector_type),
+      concurrent_gc_(false),
+      collector_type_(kCollectorTypeNone),
+      post_zygote_collector_type_(post_zygote_collector_type),
       parallel_gc_threads_(parallel_gc_threads),
       conc_gc_threads_(conc_gc_threads),
       low_memory_mode_(low_memory_mode),
@@ -107,11 +108,9 @@
       activity_thread_(NULL),
       application_thread_(NULL),
       last_process_state_id_(NULL),
-      // Initially care about pauses in case we never get notified of process states, or if the JNI
-      // code becomes broken.
-      care_about_pause_times_(true),
-      concurrent_start_bytes_(concurrent_gc_ ? initial_size - kMinConcurrentRemainingBytes
-          :  std::numeric_limits<size_t>::max()),
+      // Initially assume we perceive jank in case the process state is never updated.
+      process_state_(kProcessStateJankPerceptible),
+      concurrent_start_bytes_(std::numeric_limits<size_t>::max()),
       total_bytes_freed_ever_(0),
       total_objects_freed_ever_(0),
       num_bytes_allocated_(0),
@@ -156,8 +155,12 @@
   // If we aren't the zygote, switch to the default non zygote allocator. This may update the
   // entrypoints.
   if (!Runtime::Current()->IsZygote()) {
-    ChangeCollector(collector_type_);
+    ChangeCollector(post_zygote_collector_type_);
+  } else {
+    // We are the zygote, use bump pointer allocation + semi space collector.
+    ChangeCollector(kCollectorTypeSS);
   }
+
   live_bitmap_.reset(new accounting::HeapBitmap(this));
   mark_bitmap_.reset(new accounting::HeapBitmap(this));
   // Requested begin for the alloc space, to follow the mapped image and oat files
@@ -263,9 +266,6 @@
     garbage_collectors_.push_back(new collector::PartialMarkSweep(this, concurrent));
     garbage_collectors_.push_back(new collector::StickyMarkSweep(this, concurrent));
   }
-  gc_plan_.push_back(collector::kGcTypeSticky);
-  gc_plan_.push_back(collector::kGcTypePartial);
-  gc_plan_.push_back(collector::kGcTypeFull);
   if (kMovingCollector) {
     // TODO: Clean this up.
     semi_space_collector_ = new collector::SemiSpace(this);
@@ -325,6 +325,10 @@
   --gc_disable_count_;
 }
 
+void Heap::UpdateProcessState(ProcessState process_state) {
+  process_state_ = process_state;
+}
+
 void Heap::CreateThreadPool() {
   const size_t num_threads = std::max(parallel_gc_threads_, conc_gc_threads_);
   if (num_threads != 0) {
@@ -373,124 +377,6 @@
   thread_pool_.reset(nullptr);
 }
 
-static bool ReadStaticInt(JNIEnvExt* env, jclass clz, const char* name, int* out_value) {
-  DCHECK(out_value != NULL);
-  jfieldID field = env->GetStaticFieldID(clz, name, "I");
-  if (field == NULL) {
-    env->ExceptionClear();
-    return false;
-  }
-  *out_value = env->GetStaticIntField(clz, field);
-  return true;
-}
-
-void Heap::ListenForProcessStateChange() {
-  VLOG(heap) << "Heap notified of process state change";
-
-  Thread* self = Thread::Current();
-  JNIEnvExt* env = self->GetJniEnv();
-
-  if (!have_zygote_space_) {
-    return;
-  }
-
-  if (activity_thread_class_ == NULL) {
-    jclass clz = env->FindClass("android/app/ActivityThread");
-    if (clz == NULL) {
-      env->ExceptionClear();
-      LOG(WARNING) << "Could not find activity thread class in process state change";
-      return;
-    }
-    activity_thread_class_ = reinterpret_cast<jclass>(env->NewGlobalRef(clz));
-  }
-
-  if (activity_thread_class_ != NULL && activity_thread_ == NULL) {
-    jmethodID current_activity_method = env->GetStaticMethodID(activity_thread_class_,
-                                                               "currentActivityThread",
-                                                               "()Landroid/app/ActivityThread;");
-    if (current_activity_method == NULL) {
-      env->ExceptionClear();
-      LOG(WARNING) << "Could not get method for currentActivityThread";
-      return;
-    }
-
-    jobject obj = env->CallStaticObjectMethod(activity_thread_class_, current_activity_method);
-    if (obj == NULL) {
-      env->ExceptionClear();
-      LOG(WARNING) << "Could not get current activity";
-      return;
-    }
-    activity_thread_ = env->NewGlobalRef(obj);
-  }
-
-  if (process_state_cares_about_pause_time_.empty()) {
-    // Just attempt to do this the first time.
-    jclass clz = env->FindClass("android/app/ActivityManager");
-    if (clz == NULL) {
-      LOG(WARNING) << "Activity manager class is null";
-      return;
-    }
-    ScopedLocalRef<jclass> activity_manager(env, clz);
-    std::vector<const char*> care_about_pauses;
-    care_about_pauses.push_back("PROCESS_STATE_TOP");
-    care_about_pauses.push_back("PROCESS_STATE_IMPORTANT_BACKGROUND");
-    // Attempt to read the constants and classify them as whether or not we care about pause times.
-    for (size_t i = 0; i < care_about_pauses.size(); ++i) {
-      int process_state = 0;
-      if (ReadStaticInt(env, activity_manager.get(), care_about_pauses[i], &process_state)) {
-        process_state_cares_about_pause_time_.insert(process_state);
-        VLOG(heap) << "Adding process state " << process_state
-                   << " to set of states which care about pause time";
-      }
-    }
-  }
-
-  if (application_thread_class_ == NULL) {
-    jclass clz = env->FindClass("android/app/ActivityThread$ApplicationThread");
-    if (clz == NULL) {
-      env->ExceptionClear();
-      LOG(WARNING) << "Could not get application thread class";
-      return;
-    }
-    application_thread_class_ = reinterpret_cast<jclass>(env->NewGlobalRef(clz));
-    last_process_state_id_ = env->GetFieldID(application_thread_class_, "mLastProcessState", "I");
-    if (last_process_state_id_ == NULL) {
-      env->ExceptionClear();
-      LOG(WARNING) << "Could not get last process state member";
-      return;
-    }
-  }
-
-  if (application_thread_class_ != NULL && application_thread_ == NULL) {
-    jmethodID get_application_thread =
-        env->GetMethodID(activity_thread_class_, "getApplicationThread",
-                         "()Landroid/app/ActivityThread$ApplicationThread;");
-    if (get_application_thread == NULL) {
-      LOG(WARNING) << "Could not get method ID for get application thread";
-      return;
-    }
-
-    jobject obj = env->CallObjectMethod(activity_thread_, get_application_thread);
-    if (obj == NULL) {
-      LOG(WARNING) << "Could not get application thread";
-      return;
-    }
-
-    application_thread_ = env->NewGlobalRef(obj);
-  }
-
-  if (application_thread_ != NULL && last_process_state_id_ != NULL) {
-    int process_state = env->GetIntField(application_thread_, last_process_state_id_);
-    env->ExceptionClear();
-
-    care_about_pause_times_ = process_state_cares_about_pause_time_.find(process_state) !=
-        process_state_cares_about_pause_time_.end();
-
-    VLOG(heap) << "New process state " << process_state
-               << " care about pauses " << care_about_pause_times_;
-  }
-}
-
 void Heap::AddSpace(space::Space* space) {
   DCHECK(space != NULL);
   WriterMutexLock mu(Thread::Current(), *Locks::heap_bitmap_lock_);
@@ -995,14 +881,17 @@
 }
 
 mirror::Object* Heap::AllocateInternalWithGc(Thread* self, AllocatorType allocator,
-                                             size_t alloc_size, size_t* bytes_allocated) {
+                                             size_t alloc_size, size_t* bytes_allocated,
+                                             mirror::Class** klass) {
   mirror::Object* ptr = nullptr;
+  DCHECK(klass != nullptr);
+  SirtRef<mirror::Class> sirt_klass(self, *klass);
   // The allocation failed. If the GC is running, block until it completes, and then retry the
   // allocation.
   collector::GcType last_gc = WaitForGcToComplete(self);
   if (last_gc != collector::kGcTypeNone) {
     // A GC was in progress and we blocked, retry allocation now that memory has been freed.
-    ptr = TryToAllocate<true>(self, allocator, alloc_size, false, bytes_allocated);
+    ptr = TryToAllocate<true, false>(self, allocator, alloc_size, bytes_allocated);
   }
 
   // Loop through our different Gc types and try to Gc until we get enough free memory.
@@ -1013,13 +902,13 @@
     // Attempt to run the collector, if we succeed, re-try the allocation.
     if (CollectGarbageInternal(gc_type, kGcCauseForAlloc, false) != collector::kGcTypeNone) {
       // Did we free sufficient memory for the allocation to succeed?
-      ptr = TryToAllocate<true>(self, allocator, alloc_size, false, bytes_allocated);
+      ptr = TryToAllocate<true, false>(self, allocator, alloc_size, bytes_allocated);
     }
   }
   // Allocations have failed after GCs;  this is an exceptional state.
   if (ptr == nullptr) {
     // Try harder, growing the heap if necessary.
-    ptr = TryToAllocate<true>(self, allocator, alloc_size, true, bytes_allocated);
+    ptr = TryToAllocate<true, true>(self, allocator, alloc_size, bytes_allocated);
   }
   if (ptr == nullptr) {
     // Most allocations should have succeeded by now, so the heap is really full, really fragmented,
@@ -1032,11 +921,12 @@
     // We don't need a WaitForGcToComplete here either.
     DCHECK(!gc_plan_.empty());
     CollectGarbageInternal(gc_plan_.back(), kGcCauseForAlloc, true);
-    ptr = TryToAllocate<true>(self, allocator, alloc_size, true, bytes_allocated);
+    ptr = TryToAllocate<true, true>(self, allocator, alloc_size, bytes_allocated);
     if (ptr == nullptr) {
       ThrowOutOfMemoryError(self, alloc_size, false);
     }
   }
+  *klass = sirt_klass.get();
   return ptr;
 }
 
@@ -1200,22 +1090,46 @@
 void Heap::CollectGarbage(bool clear_soft_references) {
   // Even if we waited for a GC we still need to do another GC since weaks allocated during the
   // last GC will not have necessarily been cleared.
-  CollectGarbageInternal(collector::kGcTypeFull, kGcCauseExplicit, clear_soft_references);
+  CollectGarbageInternal(gc_plan_.back(), kGcCauseExplicit, clear_soft_references);
 }
 
 void Heap::ChangeCollector(CollectorType collector_type) {
-  switch (collector_type) {
-    case kCollectorTypeSS: {
-      ChangeAllocator(kAllocatorTypeBumpPointer);
-      break;
+  // TODO: Only do this with all mutators suspended to avoid races.
+  if (collector_type != collector_type_) {
+    collector_type_ = collector_type;
+    gc_plan_.clear();
+    switch (collector_type_) {
+      case kCollectorTypeSS: {
+        concurrent_gc_ = false;
+        gc_plan_.push_back(collector::kGcTypeFull);
+        ChangeAllocator(kAllocatorTypeBumpPointer);
+        break;
+      }
+      case kCollectorTypeMS: {
+        concurrent_gc_ = false;
+        gc_plan_.push_back(collector::kGcTypeSticky);
+        gc_plan_.push_back(collector::kGcTypePartial);
+        gc_plan_.push_back(collector::kGcTypeFull);
+        ChangeAllocator(kAllocatorTypeFreeList);
+        break;
+      }
+      case kCollectorTypeCMS: {
+        concurrent_gc_ = true;
+        gc_plan_.push_back(collector::kGcTypeSticky);
+        gc_plan_.push_back(collector::kGcTypePartial);
+        gc_plan_.push_back(collector::kGcTypeFull);
+        ChangeAllocator(kAllocatorTypeFreeList);
+        break;
+      }
+      default: {
+        LOG(FATAL) << "Unimplemented";
+      }
     }
-    case kCollectorTypeMS:
-      // Fall-through.
-    case kCollectorTypeCMS: {
-      ChangeAllocator(kAllocatorTypeFreeList);
-      break;
-    default:
-      LOG(FATAL) << "Unimplemented";
+    if (concurrent_gc_) {
+      concurrent_start_bytes_ =
+          std::max(max_allowed_footprint_, kMinConcurrentRemainingBytes) - kMinConcurrentRemainingBytes;
+    } else {
+      concurrent_start_bytes_ = std::numeric_limits<size_t>::max();
     }
   }
 }
@@ -1234,8 +1148,8 @@
   // Trim the pages at the end of the non moving space.
   non_moving_space_->Trim();
   non_moving_space_->GetMemMap()->Protect(PROT_READ | PROT_WRITE);
-  // Change the allocator to the post zygote one.
-  ChangeCollector(collector_type_);
+  // Change the collector to the post zygote one.
+  ChangeCollector(post_zygote_collector_type_);
   // TODO: Delete bump_pointer_space_ and temp_pointer_space_?
   if (semi_space_collector_ != nullptr) {
     // Create a new bump pointer space which we will compact into.
@@ -1410,7 +1324,7 @@
   } else {
     LOG(FATAL) << "Invalid current allocator " << current_allocator_;
   }
-  CHECK(collector != NULL)
+  CHECK(collector != nullptr)
       << "Could not find garbage collector with concurrent=" << concurrent_gc_
       << " and type=" << gc_type;
 
@@ -1426,7 +1340,7 @@
   // Grow the heap so that we know when to perform the next GC.
   GrowForUtilization(gc_type, collector->GetDurationNs());
 
-  if (care_about_pause_times_) {
+  if (CareAboutPauseTimes()) {
     const size_t duration = collector->GetDurationNs();
     std::vector<uint64_t> pauses = collector->GetPauseTimes();
     // GC for alloc pauses the allocating thread, so consider it as a pause.
@@ -1991,7 +1905,7 @@
   }
   if (!ignore_max_footprint_) {
     SetIdealFootprint(target_size);
-    if (concurrent_gc_ && AllocatorHasConcurrentGC(current_allocator_)) {
+    if (concurrent_gc_) {
       // Calculate when to perform the next ConcurrentGC.
       // Calculate the estimated GC duration.
       double gc_duration_seconds = NsToMs(gc_duration) / 1000.0;
@@ -2077,7 +1991,6 @@
 void Heap::RequestConcurrentGC(Thread* self) {
   // Make sure that we can do a concurrent GC.
   Runtime* runtime = Runtime::Current();
-  DCHECK(concurrent_gc_);
   if (runtime == NULL || !runtime->IsFinishedStarting() || runtime->IsShuttingDown(self) ||
       self->IsHandlingStackOverflow()) {
     return;
@@ -2143,10 +2056,9 @@
   }
 
   last_trim_time_ms_ = ms_time;
-  ListenForProcessStateChange();
 
   // Trim only if we do not currently care about pause times.
-  if (!care_about_pause_times_) {
+  if (!CareAboutPauseTimes()) {
     JNIEnv* env = self->GetJniEnv();
     DCHECK(WellKnownClasses::java_lang_Daemons != NULL);
     DCHECK(WellKnownClasses::java_lang_Daemons_requestHeapTrim != NULL);
@@ -2212,7 +2124,7 @@
       // finalizers released native managed allocations.
       UpdateMaxNativeFootprint();
     } else if (!IsGCRequestPending()) {
-      if (concurrent_gc_ && AllocatorHasConcurrentGC(current_allocator_)) {
+      if (concurrent_gc_) {
         RequestConcurrentGC(self);
       } else {
         CollectGarbageInternal(gc_type, kGcCauseForAlloc, false);
diff --git a/runtime/gc/heap.h b/runtime/gc/heap.h
index 8c5746d..9788064 100644
--- a/runtime/gc/heap.h
+++ b/runtime/gc/heap.h
@@ -119,6 +119,13 @@
 // If true, use rosalloc/RosAllocSpace instead of dlmalloc/DlMallocSpace
 static constexpr bool kUseRosAlloc = true;
 
+// The process state passed in from the activity manager, used to determine when to do trimming
+// and compaction.
+enum ProcessState {
+  kProcessStateJankPerceptible = 0,
+  kProcessStateJankImperceptible = 1,
+};
+
 class Heap {
  public:
   // If true, measure the total allocation time.
@@ -287,6 +294,9 @@
   // waited for.
   collector::GcType WaitForGcToComplete(Thread* self) LOCKS_EXCLUDED(gc_complete_lock_);
 
+  // Update the heap's process state to a new value, may cause compaction to occur.
+  void UpdateProcessState(ProcessState process_state);
+
   const std::vector<space::ContinuousSpace*>& GetContinuousSpaces() const {
     return continuous_spaces_;
   }
@@ -451,10 +461,7 @@
 
   // Mark the specified allocation stack as live.
   void MarkAllocStackAsLive(accounting::ObjectStack* stack)
-        EXCLUSIVE_LOCKS_REQUIRED(Locks::heap_bitmap_lock_);
-
-  // Gets called when we get notified by ActivityThread that the process state has changed.
-  void ListenForProcessStateChange();
+      EXCLUSIVE_LOCKS_REQUIRED(Locks::heap_bitmap_lock_);
 
   // DEPRECATED: Should remove in "near" future when support for multiple image spaces is added.
   // Assumes there is only one image space.
@@ -475,7 +482,7 @@
 
   // Returns true if we currently care about pause times.
   bool CareAboutPauseTimes() const {
-    return care_about_pause_times_;
+    return process_state_ == kProcessStateJankPerceptible;
   }
 
   // Thread pool.
@@ -510,10 +517,16 @@
   ALWAYS_INLINE void CheckConcurrentGC(Thread* self, size_t new_num_bytes_allocated,
                                        mirror::Object* obj);
 
+  // We don't force this to be inline since it is a slow path.
+  template <bool kInstrumented, typename PreFenceVisitor>
+  mirror::Object* AllocLargeObject(Thread* self, mirror::Class* klass, size_t byte_count,
+                                   const PreFenceVisitor& pre_fence_visitor)
+      SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
+
   // Handles Allocate()'s slow allocation path with GC involved after
   // an initial allocation attempt failed.
   mirror::Object* AllocateInternalWithGc(Thread* self, AllocatorType allocator, size_t num_bytes,
-                                         size_t* bytes_allocated)
+                                         size_t* bytes_allocated, mirror::Class** klass)
       LOCKS_EXCLUDED(Locks::thread_suspend_count_lock_)
       SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
 
@@ -524,15 +537,15 @@
 
   // Try to allocate a number of bytes, this function never does any GCs. Needs to be inlined so
   // that the switch statement is constant optimized in the entrypoints.
-  template <const bool kInstrumented>
+  template <const bool kInstrumented, const bool kGrow>
   ALWAYS_INLINE mirror::Object* TryToAllocate(Thread* self, AllocatorType allocator_type,
-                                              size_t alloc_size, bool grow,
-                                              size_t* bytes_allocated)
+                                              size_t alloc_size, size_t* bytes_allocated)
       SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
 
   void ThrowOutOfMemoryError(Thread* self, size_t byte_count, bool large_object_allocation)
       SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
-  bool IsOutOfMemoryOnAllocation(size_t alloc_size, bool grow);
+  template <const bool kGrow>
+  bool IsOutOfMemoryOnAllocation(size_t alloc_size);
 
   // Pushes a list of cleared references out to the managed heap.
   void SetReferenceReferent(mirror::Object* reference, mirror::Object* referent)
@@ -632,12 +645,14 @@
   // A mod-union table remembers all of the references from the it's space to other spaces.
   SafeMap<space::Space*, accounting::ModUnionTable*> mod_union_tables_;
 
-  // What kind of concurrency behavior is the runtime after? True for concurrent mark sweep GC,
-  // false for stop-the-world mark sweep.
-  const bool concurrent_gc_;
+  // What kind of concurrency behavior is the runtime after? Currently true for concurrent mark
+  // sweep GC, false for other GC types.
+  bool concurrent_gc_;
 
   // The current collector type.
   CollectorType collector_type_;
+  // Which collector we will switch to after zygote fork.
+  CollectorType post_zygote_collector_type_;
 
   // How many GC threads we may use for paused parts of garbage collection.
   const size_t parallel_gc_threads_;
@@ -713,11 +728,8 @@
   jobject application_thread_;
   jfieldID last_process_state_id_;
 
-  // Process states which care about pause times.
-  std::set<int> process_state_cares_about_pause_time_;
-
   // Whether or not we currently care about pause times.
-  bool care_about_pause_times_;
+  ProcessState process_state_;
 
   // When num_bytes_allocated_ exceeds this amount then a concurrent GC should be requested so that
   // it completes ahead of an allocation failing.
diff --git a/runtime/gc/space/space_test.cc b/runtime/gc/space/space_test.cc
index 6b597ae..60c3b1c 100644
--- a/runtime/gc/space/space_test.cc
+++ b/runtime/gc/space/space_test.cc
@@ -31,10 +31,6 @@
 
 class SpaceTest : public CommonTest {
  public:
-  void SizeFootPrintGrowthLimitAndTrimBody(DlMallocSpace* space, intptr_t object_size,
-                                           int round, size_t growth_limit);
-  void SizeFootPrintGrowthLimitAndTrimDriver(size_t object_size);
-
   void AddSpace(ContinuousSpace* space) {
     // For RosAlloc, revoke the thread local runs before moving onto a
     // new alloc space.
@@ -55,6 +51,26 @@
     arr->SetLength(length);
     EXPECT_EQ(arr->SizeOf(), size);
   }
+
+  static MallocSpace* CreateDlMallocSpace(const std::string& name, size_t initial_size, size_t growth_limit,
+                                          size_t capacity, byte* requested_begin) {
+    return DlMallocSpace::Create(name, initial_size, growth_limit, capacity, requested_begin);
+  }
+  static MallocSpace* CreateRosAllocSpace(const std::string& name, size_t initial_size, size_t growth_limit,
+                                          size_t capacity, byte* requested_begin) {
+    return RosAllocSpace::Create(name, initial_size, growth_limit, capacity, requested_begin);
+  }
+
+  typedef MallocSpace* (*CreateSpaceFn)(const std::string& name, size_t initial_size, size_t growth_limit,
+                                        size_t capacity, byte* requested_begin);
+  void InitTestBody(CreateSpaceFn create_space);
+  void ZygoteSpaceTestBody(CreateSpaceFn create_space);
+  void AllocAndFreeTestBody(CreateSpaceFn create_space);
+  void AllocAndFreeListTestBody(CreateSpaceFn create_space);
+
+  void SizeFootPrintGrowthLimitAndTrimBody(MallocSpace* space, intptr_t object_size,
+                                           int round, size_t growth_limit);
+  void SizeFootPrintGrowthLimitAndTrimDriver(size_t object_size, CreateSpaceFn create_space);
 };
 
 static size_t test_rand(size_t* seed) {
@@ -62,128 +78,143 @@
   return *seed;
 }
 
-TEST_F(SpaceTest, Init) {
+void SpaceTest::InitTestBody(CreateSpaceFn create_space) {
   {
     // Init < max == growth
-    UniquePtr<Space> space(DlMallocSpace::Create("test", 16 * MB, 32 * MB, 32 * MB, NULL));
+    UniquePtr<Space> space(create_space("test", 16 * MB, 32 * MB, 32 * MB, NULL));
     EXPECT_TRUE(space.get() != NULL);
   }
   {
     // Init == max == growth
-    UniquePtr<Space> space(DlMallocSpace::Create("test", 16 * MB, 16 * MB, 16 * MB, NULL));
+    UniquePtr<Space> space(create_space("test", 16 * MB, 16 * MB, 16 * MB, NULL));
     EXPECT_TRUE(space.get() != NULL);
   }
   {
     // Init > max == growth
-    UniquePtr<Space> space(DlMallocSpace::Create("test", 32 * MB, 16 * MB, 16 * MB, NULL));
+    UniquePtr<Space> space(create_space("test", 32 * MB, 16 * MB, 16 * MB, NULL));
     EXPECT_TRUE(space.get() == NULL);
   }
   {
     // Growth == init < max
-    UniquePtr<Space> space(DlMallocSpace::Create("test", 16 * MB, 16 * MB, 32 * MB, NULL));
+    UniquePtr<Space> space(create_space("test", 16 * MB, 16 * MB, 32 * MB, NULL));
     EXPECT_TRUE(space.get() != NULL);
   }
   {
     // Growth < init < max
-    UniquePtr<Space> space(DlMallocSpace::Create("test", 16 * MB, 8 * MB, 32 * MB, NULL));
+    UniquePtr<Space> space(create_space("test", 16 * MB, 8 * MB, 32 * MB, NULL));
     EXPECT_TRUE(space.get() == NULL);
   }
   {
     // Init < growth < max
-    UniquePtr<Space> space(DlMallocSpace::Create("test", 8 * MB, 16 * MB, 32 * MB, NULL));
+    UniquePtr<Space> space(create_space("test", 8 * MB, 16 * MB, 32 * MB, NULL));
     EXPECT_TRUE(space.get() != NULL);
   }
   {
     // Init < max < growth
-    UniquePtr<Space> space(DlMallocSpace::Create("test", 8 * MB, 32 * MB, 16 * MB, NULL));
+    UniquePtr<Space> space(create_space("test", 8 * MB, 32 * MB, 16 * MB, NULL));
     EXPECT_TRUE(space.get() == NULL);
   }
 }
 
+TEST_F(SpaceTest, Init_DlMallocSpace) {
+  InitTestBody(SpaceTest::CreateDlMallocSpace);
+}
+TEST_F(SpaceTest, Init_RosAllocSpace) {
+  InitTestBody(SpaceTest::CreateRosAllocSpace);
+}
+
 // TODO: This test is not very good, we should improve it.
 // The test should do more allocations before the creation of the ZygoteSpace, and then do
 // allocations after the ZygoteSpace is created. The test should also do some GCs to ensure that
 // the GC works with the ZygoteSpace.
-TEST_F(SpaceTest, ZygoteSpace) {
-    size_t dummy = 0;
-    MallocSpace* space(DlMallocSpace::Create("test", 4 * MB, 16 * MB, 16 * MB, NULL));
-    ASSERT_TRUE(space != NULL);
+void SpaceTest::ZygoteSpaceTestBody(CreateSpaceFn create_space) {
+  size_t dummy = 0;
+  MallocSpace* space(create_space("test", 4 * MB, 16 * MB, 16 * MB, NULL));
+  ASSERT_TRUE(space != NULL);
 
-    // Make space findable to the heap, will also delete space when runtime is cleaned up
-    AddSpace(space);
-    Thread* self = Thread::Current();
+  // Make space findable to the heap, will also delete space when runtime is cleaned up
+  AddSpace(space);
+  Thread* self = Thread::Current();
 
-    // Succeeds, fits without adjusting the footprint limit.
-    mirror::Object* ptr1 = space->Alloc(self, 1 * MB, &dummy);
-    EXPECT_TRUE(ptr1 != NULL);
-    InstallClass(ptr1, 1 * MB);
+  // Succeeds, fits without adjusting the footprint limit.
+  mirror::Object* ptr1 = space->Alloc(self, 1 * MB, &dummy);
+  EXPECT_TRUE(ptr1 != NULL);
+  InstallClass(ptr1, 1 * MB);
 
-    // Fails, requires a higher footprint limit.
-    mirror::Object* ptr2 = space->Alloc(self, 8 * MB, &dummy);
-    EXPECT_TRUE(ptr2 == NULL);
+  // Fails, requires a higher footprint limit.
+  mirror::Object* ptr2 = space->Alloc(self, 8 * MB, &dummy);
+  EXPECT_TRUE(ptr2 == NULL);
 
-    // Succeeds, adjusts the footprint.
-    size_t ptr3_bytes_allocated;
-    mirror::Object* ptr3 = space->AllocWithGrowth(self, 8 * MB, &ptr3_bytes_allocated);
-    EXPECT_TRUE(ptr3 != NULL);
-    EXPECT_LE(8U * MB, ptr3_bytes_allocated);
-    InstallClass(ptr3, 8 * MB);
+  // Succeeds, adjusts the footprint.
+  size_t ptr3_bytes_allocated;
+  mirror::Object* ptr3 = space->AllocWithGrowth(self, 8 * MB, &ptr3_bytes_allocated);
+  EXPECT_TRUE(ptr3 != NULL);
+  EXPECT_LE(8U * MB, ptr3_bytes_allocated);
+  InstallClass(ptr3, 8 * MB);
 
-    // Fails, requires a higher footprint limit.
-    mirror::Object* ptr4 = space->Alloc(self, 8 * MB, &dummy);
-    EXPECT_TRUE(ptr4 == NULL);
+  // Fails, requires a higher footprint limit.
+  mirror::Object* ptr4 = space->Alloc(self, 8 * MB, &dummy);
+  EXPECT_TRUE(ptr4 == NULL);
 
-    // Also fails, requires a higher allowed footprint.
-    mirror::Object* ptr5 = space->AllocWithGrowth(self, 8 * MB, &dummy);
-    EXPECT_TRUE(ptr5 == NULL);
+  // Also fails, requires a higher allowed footprint.
+  mirror::Object* ptr5 = space->AllocWithGrowth(self, 8 * MB, &dummy);
+  EXPECT_TRUE(ptr5 == NULL);
 
-    // Release some memory.
-    size_t free3 = space->AllocationSize(ptr3);
-    EXPECT_EQ(free3, ptr3_bytes_allocated);
-    EXPECT_EQ(free3, space->Free(self, ptr3));
-    EXPECT_LE(8U * MB, free3);
+  // Release some memory.
+  size_t free3 = space->AllocationSize(ptr3);
+  EXPECT_EQ(free3, ptr3_bytes_allocated);
+  EXPECT_EQ(free3, space->Free(self, ptr3));
+  EXPECT_LE(8U * MB, free3);
 
-    // Succeeds, now that memory has been freed.
-    mirror::Object* ptr6 = space->AllocWithGrowth(self, 9 * MB, &dummy);
-    EXPECT_TRUE(ptr6 != NULL);
-    InstallClass(ptr6, 9 * MB);
+  // Succeeds, now that memory has been freed.
+  mirror::Object* ptr6 = space->AllocWithGrowth(self, 9 * MB, &dummy);
+  EXPECT_TRUE(ptr6 != NULL);
+  InstallClass(ptr6, 9 * MB);
 
-    // Final clean up.
-    size_t free1 = space->AllocationSize(ptr1);
-    space->Free(self, ptr1);
-    EXPECT_LE(1U * MB, free1);
+  // Final clean up.
+  size_t free1 = space->AllocationSize(ptr1);
+  space->Free(self, ptr1);
+  EXPECT_LE(1U * MB, free1);
 
-    // Make sure that the zygote space isn't directly at the start of the space.
-    space->Alloc(self, 1U * MB, &dummy);
-    space = space->CreateZygoteSpace("alloc space");
+  // Make sure that the zygote space isn't directly at the start of the space.
+  space->Alloc(self, 1U * MB, &dummy);
+  space = space->CreateZygoteSpace("alloc space");
 
-    // Make space findable to the heap, will also delete space when runtime is cleaned up
-    AddSpace(space);
+  // Make space findable to the heap, will also delete space when runtime is cleaned up
+  AddSpace(space);
 
-    // Succeeds, fits without adjusting the footprint limit.
-    ptr1 = space->Alloc(self, 1 * MB, &dummy);
-    EXPECT_TRUE(ptr1 != NULL);
-    InstallClass(ptr1, 1 * MB);
+  // Succeeds, fits without adjusting the footprint limit.
+  ptr1 = space->Alloc(self, 1 * MB, &dummy);
+  EXPECT_TRUE(ptr1 != NULL);
+  InstallClass(ptr1, 1 * MB);
 
-    // Fails, requires a higher footprint limit.
-    ptr2 = space->Alloc(self, 8 * MB, &dummy);
-    EXPECT_TRUE(ptr2 == NULL);
+  // Fails, requires a higher footprint limit.
+  ptr2 = space->Alloc(self, 8 * MB, &dummy);
+  EXPECT_TRUE(ptr2 == NULL);
 
-    // Succeeds, adjusts the footprint.
-    ptr3 = space->AllocWithGrowth(self, 2 * MB, &dummy);
-    EXPECT_TRUE(ptr3 != NULL);
-    InstallClass(ptr3, 2 * MB);
-    space->Free(self, ptr3);
+  // Succeeds, adjusts the footprint.
+  ptr3 = space->AllocWithGrowth(self, 2 * MB, &dummy);
+  EXPECT_TRUE(ptr3 != NULL);
+  InstallClass(ptr3, 2 * MB);
+  space->Free(self, ptr3);
 
-    // Final clean up.
-    free1 = space->AllocationSize(ptr1);
-    space->Free(self, ptr1);
-    EXPECT_LE(1U * MB, free1);
+  // Final clean up.
+  free1 = space->AllocationSize(ptr1);
+  space->Free(self, ptr1);
+  EXPECT_LE(1U * MB, free1);
 }
 
-TEST_F(SpaceTest, AllocAndFree) {
+TEST_F(SpaceTest, ZygoteSpace_DlMallocSpace) {
+  ZygoteSpaceTestBody(SpaceTest::CreateDlMallocSpace);
+}
+
+TEST_F(SpaceTest, ZygoteSpace_RosAllocSpace) {
+  ZygoteSpaceTestBody(SpaceTest::CreateRosAllocSpace);
+}
+
+void SpaceTest::AllocAndFreeTestBody(CreateSpaceFn create_space) {
   size_t dummy = 0;
-  DlMallocSpace* space(DlMallocSpace::Create("test", 4 * MB, 16 * MB, 16 * MB, NULL));
+  MallocSpace* space(create_space("test", 4 * MB, 16 * MB, 16 * MB, NULL));
   ASSERT_TRUE(space != NULL);
   Thread* self = Thread::Current();
 
@@ -231,6 +262,13 @@
   EXPECT_LE(1U * MB, free1);
 }
 
+TEST_F(SpaceTest, AllocAndFree_DlMallocSpace) {
+  AllocAndFreeTestBody(SpaceTest::CreateDlMallocSpace);
+}
+TEST_F(SpaceTest, AllocAndFree_RosAllocSpace) {
+  AllocAndFreeTestBody(SpaceTest::CreateRosAllocSpace);
+}
+
 TEST_F(SpaceTest, LargeObjectTest) {
   size_t rand_seed = 0;
   for (size_t i = 0; i < 2; ++i) {
@@ -292,8 +330,8 @@
   }
 }
 
-TEST_F(SpaceTest, AllocAndFreeList) {
-  DlMallocSpace* space(DlMallocSpace::Create("test", 4 * MB, 16 * MB, 16 * MB, NULL));
+void SpaceTest::AllocAndFreeListTestBody(CreateSpaceFn create_space) {
+  MallocSpace* space(create_space("test", 4 * MB, 16 * MB, 16 * MB, NULL));
   ASSERT_TRUE(space != NULL);
 
   // Make space findable to the heap, will also delete space when runtime is cleaned up
@@ -332,7 +370,14 @@
   }
 }
 
-void SpaceTest::SizeFootPrintGrowthLimitAndTrimBody(DlMallocSpace* space, intptr_t object_size,
+TEST_F(SpaceTest, AllocAndFreeList_DlMallocSpace) {
+  AllocAndFreeListTestBody(SpaceTest::CreateDlMallocSpace);
+}
+TEST_F(SpaceTest, AllocAndFreeList_RosAllocSpace) {
+  AllocAndFreeListTestBody(SpaceTest::CreateRosAllocSpace);
+}
+
+void SpaceTest::SizeFootPrintGrowthLimitAndTrimBody(MallocSpace* space, intptr_t object_size,
                                                     int round, size_t growth_limit) {
   if (((object_size > 0 && object_size >= static_cast<intptr_t>(growth_limit))) ||
       ((object_size < 0 && -object_size >= static_cast<intptr_t>(growth_limit)))) {
@@ -493,11 +538,11 @@
   EXPECT_LE(space->Size(), growth_limit);
 }
 
-void SpaceTest::SizeFootPrintGrowthLimitAndTrimDriver(size_t object_size) {
+void SpaceTest::SizeFootPrintGrowthLimitAndTrimDriver(size_t object_size, CreateSpaceFn create_space) {
   size_t initial_size = 4 * MB;
   size_t growth_limit = 8 * MB;
   size_t capacity = 16 * MB;
-  DlMallocSpace* space(DlMallocSpace::Create("test", initial_size, growth_limit, capacity, NULL));
+  MallocSpace* space(create_space("test", initial_size, growth_limit, capacity, NULL));
   ASSERT_TRUE(space != NULL);
 
   // Basic sanity
@@ -518,16 +563,25 @@
 }
 
 #define TEST_SizeFootPrintGrowthLimitAndTrim(name, size) \
-  TEST_F(SpaceTest, SizeFootPrintGrowthLimitAndTrim_AllocationsOf_##name) { \
-    SizeFootPrintGrowthLimitAndTrimDriver(size); \
+  TEST_F(SpaceTest, SizeFootPrintGrowthLimitAndTrim_AllocationsOf_##name##_DlMallocSpace) { \
+    SizeFootPrintGrowthLimitAndTrimDriver(size, SpaceTest::CreateDlMallocSpace); \
   } \
-  TEST_F(SpaceTest, SizeFootPrintGrowthLimitAndTrim_RandomAllocationsWithMax_##name) { \
-    SizeFootPrintGrowthLimitAndTrimDriver(-size); \
+  TEST_F(SpaceTest, SizeFootPrintGrowthLimitAndTrim_RandomAllocationsWithMax_##name##_DlMallocSpace) { \
+    SizeFootPrintGrowthLimitAndTrimDriver(-size, SpaceTest::CreateDlMallocSpace); \
+  } \
+  TEST_F(SpaceTest, SizeFootPrintGrowthLimitAndTrim_AllocationsOf_##name##_RosAllocSpace) { \
+    SizeFootPrintGrowthLimitAndTrimDriver(size, SpaceTest::CreateRosAllocSpace); \
+  } \
+  TEST_F(SpaceTest, SizeFootPrintGrowthLimitAndTrim_RandomAllocationsWithMax_##name##_RosAllocSpace) { \
+    SizeFootPrintGrowthLimitAndTrimDriver(-size, SpaceTest::CreateRosAllocSpace); \
   }
 
 // Each size test is its own test so that we get a fresh heap each time
-TEST_F(SpaceTest, SizeFootPrintGrowthLimitAndTrim_AllocationsOf_12B) {
-  SizeFootPrintGrowthLimitAndTrimDriver(12);
+TEST_F(SpaceTest, SizeFootPrintGrowthLimitAndTrim_AllocationsOf_12B_DlMallocSpace) {
+  SizeFootPrintGrowthLimitAndTrimDriver(12, SpaceTest::CreateDlMallocSpace);
+}
+TEST_F(SpaceTest, SizeFootPrintGrowthLimitAndTrim_AllocationsOf_12B_RosAllocSpace) {
+  SizeFootPrintGrowthLimitAndTrimDriver(12, SpaceTest::CreateRosAllocSpace);
 }
 TEST_SizeFootPrintGrowthLimitAndTrim(16B, 16)
 TEST_SizeFootPrintGrowthLimitAndTrim(24B, 24)
diff --git a/runtime/globals.h b/runtime/globals.h
index c2fe67e..a0d7e48 100644
--- a/runtime/globals.h
+++ b/runtime/globals.h
@@ -82,7 +82,7 @@
 // Garbage collector constants.
 static constexpr bool kMovingCollector = true && !kUsePortableCompiler;
 // True if we allow moving classes.
-static constexpr bool kMovingClasses = false;
+static constexpr bool kMovingClasses = true;
 // True if we allow moving fields.
 static constexpr bool kMovingFields = false;
 // True if we allow moving methods.
diff --git a/runtime/interpreter/interpreter.cc b/runtime/interpreter/interpreter.cc
index 9938478..f574a0f 100644
--- a/runtime/interpreter/interpreter.cc
+++ b/runtime/interpreter/interpreter.cc
@@ -90,8 +90,8 @@
   ScopedObjectAccessUnchecked soa(self);
   if (method->IsStatic()) {
     if (shorty == "L") {
-      typedef jobject (fnptr)(JNIEnv*, jclass);
-      const fnptr* fn = reinterpret_cast<const fnptr*>(method->GetNativeMethod());
+      typedef jobject (fntype)(JNIEnv*, jclass);
+      fntype* const fn = reinterpret_cast<fntype*>(const_cast<void*>(method->GetNativeMethod()));
       ScopedLocalRef<jclass> klass(soa.Env(),
                                    soa.AddLocalReference<jclass>(method->GetDeclaringClass()));
       jobject jresult;
@@ -101,36 +101,36 @@
       }
       result->SetL(soa.Decode<Object*>(jresult));
     } else if (shorty == "V") {
-      typedef void (fnptr)(JNIEnv*, jclass);
-      const fnptr* fn = reinterpret_cast<const fnptr*>(method->GetNativeMethod());
+      typedef void (fntype)(JNIEnv*, jclass);
+      fntype* const fn = reinterpret_cast<fntype*>(const_cast<void*>(method->GetNativeMethod()));
       ScopedLocalRef<jclass> klass(soa.Env(),
                                    soa.AddLocalReference<jclass>(method->GetDeclaringClass()));
       ScopedThreadStateChange tsc(self, kNative);
       fn(soa.Env(), klass.get());
     } else if (shorty == "Z") {
-      typedef jboolean (fnptr)(JNIEnv*, jclass);
-      const fnptr* fn = reinterpret_cast<const fnptr*>(method->GetNativeMethod());
+      typedef jboolean (fntype)(JNIEnv*, jclass);
+      fntype* const fn = reinterpret_cast<fntype*>(const_cast<void*>(method->GetNativeMethod()));
       ScopedLocalRef<jclass> klass(soa.Env(),
                                    soa.AddLocalReference<jclass>(method->GetDeclaringClass()));
       ScopedThreadStateChange tsc(self, kNative);
       result->SetZ(fn(soa.Env(), klass.get()));
     } else if (shorty == "BI") {
-      typedef jbyte (fnptr)(JNIEnv*, jclass, jint);
-      const fnptr* fn = reinterpret_cast<const fnptr*>(method->GetNativeMethod());
+      typedef jbyte (fntype)(JNIEnv*, jclass, jint);
+      fntype* const fn = reinterpret_cast<fntype*>(const_cast<void*>(method->GetNativeMethod()));
       ScopedLocalRef<jclass> klass(soa.Env(),
                                    soa.AddLocalReference<jclass>(method->GetDeclaringClass()));
       ScopedThreadStateChange tsc(self, kNative);
       result->SetB(fn(soa.Env(), klass.get(), args[0]));
     } else if (shorty == "II") {
-      typedef jint (fnptr)(JNIEnv*, jclass, jint);
-      const fnptr* fn = reinterpret_cast<const fnptr*>(method->GetNativeMethod());
+      typedef jint (fntype)(JNIEnv*, jclass, jint);
+      fntype* const fn = reinterpret_cast<fntype*>(const_cast<void*>(method->GetNativeMethod()));
       ScopedLocalRef<jclass> klass(soa.Env(),
                                    soa.AddLocalReference<jclass>(method->GetDeclaringClass()));
       ScopedThreadStateChange tsc(self, kNative);
       result->SetI(fn(soa.Env(), klass.get(), args[0]));
     } else if (shorty == "LL") {
-      typedef jobject (fnptr)(JNIEnv*, jclass, jobject);
-      const fnptr* fn = reinterpret_cast<const fnptr*>(method->GetNativeMethod());
+      typedef jobject (fntype)(JNIEnv*, jclass, jobject);
+      fntype* const fn = reinterpret_cast<fntype*>(const_cast<void*>(method->GetNativeMethod()));
       ScopedLocalRef<jclass> klass(soa.Env(),
                                    soa.AddLocalReference<jclass>(method->GetDeclaringClass()));
       ScopedLocalRef<jobject> arg0(soa.Env(),
@@ -142,15 +142,15 @@
       }
       result->SetL(soa.Decode<Object*>(jresult));
     } else if (shorty == "IIZ") {
-      typedef jint (fnptr)(JNIEnv*, jclass, jint, jboolean);
-      const fnptr* fn = reinterpret_cast<const fnptr*>(method->GetNativeMethod());
+      typedef jint (fntype)(JNIEnv*, jclass, jint, jboolean);
+      fntype* const fn = reinterpret_cast<fntype*>(const_cast<void*>(method->GetNativeMethod()));
       ScopedLocalRef<jclass> klass(soa.Env(),
                                    soa.AddLocalReference<jclass>(method->GetDeclaringClass()));
       ScopedThreadStateChange tsc(self, kNative);
       result->SetI(fn(soa.Env(), klass.get(), args[0], args[1]));
     } else if (shorty == "ILI") {
-      typedef jint (fnptr)(JNIEnv*, jclass, jobject, jint);
-      const fnptr* fn = reinterpret_cast<const fnptr*>(method->GetNativeMethod());
+      typedef jint (fntype)(JNIEnv*, jclass, jobject, jint);
+      fntype* const fn = reinterpret_cast<fntype*>(const_cast<void*>(method->GetNativeMethod()));
       ScopedLocalRef<jclass> klass(soa.Env(),
                                    soa.AddLocalReference<jclass>(method->GetDeclaringClass()));
       ScopedLocalRef<jobject> arg0(soa.Env(),
@@ -158,22 +158,22 @@
       ScopedThreadStateChange tsc(self, kNative);
       result->SetI(fn(soa.Env(), klass.get(), arg0.get(), args[1]));
     } else if (shorty == "SIZ") {
-      typedef jshort (fnptr)(JNIEnv*, jclass, jint, jboolean);
-      const fnptr* fn = reinterpret_cast<const fnptr*>(method->GetNativeMethod());
+      typedef jshort (fntype)(JNIEnv*, jclass, jint, jboolean);
+      fntype* const fn = reinterpret_cast<fntype*>(const_cast<void*>(method->GetNativeMethod()));
       ScopedLocalRef<jclass> klass(soa.Env(),
                                    soa.AddLocalReference<jclass>(method->GetDeclaringClass()));
       ScopedThreadStateChange tsc(self, kNative);
       result->SetS(fn(soa.Env(), klass.get(), args[0], args[1]));
     } else if (shorty == "VIZ") {
-      typedef void (fnptr)(JNIEnv*, jclass, jint, jboolean);
-      const fnptr* fn = reinterpret_cast<const fnptr*>(method->GetNativeMethod());
+      typedef void (fntype)(JNIEnv*, jclass, jint, jboolean);
+      fntype* const fn = reinterpret_cast<fntype*>(const_cast<void*>(method->GetNativeMethod()));
       ScopedLocalRef<jclass> klass(soa.Env(),
                                    soa.AddLocalReference<jclass>(method->GetDeclaringClass()));
       ScopedThreadStateChange tsc(self, kNative);
       fn(soa.Env(), klass.get(), args[0], args[1]);
     } else if (shorty == "ZLL") {
-      typedef jboolean (fnptr)(JNIEnv*, jclass, jobject, jobject);
-      const fnptr* fn = reinterpret_cast<const fnptr*>(method->GetNativeMethod());
+      typedef jboolean (fntype)(JNIEnv*, jclass, jobject, jobject);
+      fntype* const fn = reinterpret_cast<fntype*>(const_cast<void*>(method->GetNativeMethod()));
       ScopedLocalRef<jclass> klass(soa.Env(),
                                    soa.AddLocalReference<jclass>(method->GetDeclaringClass()));
       ScopedLocalRef<jobject> arg0(soa.Env(),
@@ -183,8 +183,8 @@
       ScopedThreadStateChange tsc(self, kNative);
       result->SetZ(fn(soa.Env(), klass.get(), arg0.get(), arg1.get()));
     } else if (shorty == "ZILL") {
-      typedef jboolean (fnptr)(JNIEnv*, jclass, jint, jobject, jobject);
-      const fnptr* fn = reinterpret_cast<const fnptr*>(method->GetNativeMethod());
+      typedef jboolean (fntype)(JNIEnv*, jclass, jint, jobject, jobject);
+      fntype* const fn = reinterpret_cast<fntype*>(const_cast<void*>(method->GetNativeMethod()));
       ScopedLocalRef<jclass> klass(soa.Env(),
                                    soa.AddLocalReference<jclass>(method->GetDeclaringClass()));
       ScopedLocalRef<jobject> arg1(soa.Env(),
@@ -194,8 +194,8 @@
       ScopedThreadStateChange tsc(self, kNative);
       result->SetZ(fn(soa.Env(), klass.get(), args[0], arg1.get(), arg2.get()));
     } else if (shorty == "VILII") {
-      typedef void (fnptr)(JNIEnv*, jclass, jint, jobject, jint, jint);
-      const fnptr* fn = reinterpret_cast<const fnptr*>(method->GetNativeMethod());
+      typedef void (fntype)(JNIEnv*, jclass, jint, jobject, jint, jint);
+      fntype* const fn = reinterpret_cast<fntype*>(const_cast<void*>(method->GetNativeMethod()));
       ScopedLocalRef<jclass> klass(soa.Env(),
                                    soa.AddLocalReference<jclass>(method->GetDeclaringClass()));
       ScopedLocalRef<jobject> arg1(soa.Env(),
@@ -203,8 +203,8 @@
       ScopedThreadStateChange tsc(self, kNative);
       fn(soa.Env(), klass.get(), args[0], arg1.get(), args[2], args[3]);
     } else if (shorty == "VLILII") {
-      typedef void (fnptr)(JNIEnv*, jclass, jobject, jint, jobject, jint, jint);
-      const fnptr* fn = reinterpret_cast<const fnptr*>(method->GetNativeMethod());
+      typedef void (fntype)(JNIEnv*, jclass, jobject, jint, jobject, jint, jint);
+      fntype* const fn = reinterpret_cast<fntype*>(const_cast<void*>(method->GetNativeMethod()));
       ScopedLocalRef<jclass> klass(soa.Env(),
                                    soa.AddLocalReference<jclass>(method->GetDeclaringClass()));
       ScopedLocalRef<jobject> arg0(soa.Env(),
@@ -219,8 +219,8 @@
     }
   } else {
     if (shorty == "L") {
-      typedef jobject (fnptr)(JNIEnv*, jobject);
-      const fnptr* fn = reinterpret_cast<const fnptr*>(method->GetNativeMethod());
+      typedef jobject (fntype)(JNIEnv*, jobject);
+      fntype* const fn = reinterpret_cast<fntype*>(const_cast<void*>(method->GetNativeMethod()));
       ScopedLocalRef<jobject> rcvr(soa.Env(),
                                    soa.AddLocalReference<jobject>(receiver));
       jobject jresult;
@@ -230,15 +230,15 @@
       }
       result->SetL(soa.Decode<Object*>(jresult));
     } else if (shorty == "V") {
-      typedef void (fnptr)(JNIEnv*, jobject);
-      const fnptr* fn = reinterpret_cast<const fnptr*>(method->GetNativeMethod());
+      typedef void (fntype)(JNIEnv*, jobject);
+      fntype* const fn = reinterpret_cast<fntype*>(const_cast<void*>(method->GetNativeMethod()));
       ScopedLocalRef<jobject> rcvr(soa.Env(),
                                    soa.AddLocalReference<jobject>(receiver));
       ScopedThreadStateChange tsc(self, kNative);
       fn(soa.Env(), rcvr.get());
     } else if (shorty == "LL") {
-      typedef jobject (fnptr)(JNIEnv*, jobject, jobject);
-      const fnptr* fn = reinterpret_cast<const fnptr*>(method->GetNativeMethod());
+      typedef jobject (fntype)(JNIEnv*, jobject, jobject);
+      fntype* const fn = reinterpret_cast<fntype*>(const_cast<void*>(method->GetNativeMethod()));
       ScopedLocalRef<jobject> rcvr(soa.Env(),
                                    soa.AddLocalReference<jobject>(receiver));
       ScopedLocalRef<jobject> arg0(soa.Env(),
@@ -251,8 +251,8 @@
       result->SetL(soa.Decode<Object*>(jresult));
       ScopedThreadStateChange tsc(self, kNative);
     } else if (shorty == "III") {
-      typedef jint (fnptr)(JNIEnv*, jobject, jint, jint);
-      const fnptr* fn = reinterpret_cast<const fnptr*>(method->GetNativeMethod());
+      typedef jint (fntype)(JNIEnv*, jobject, jint, jint);
+      fntype* const fn = reinterpret_cast<fntype*>(const_cast<void*>(method->GetNativeMethod()));
       ScopedLocalRef<jobject> rcvr(soa.Env(),
                                    soa.AddLocalReference<jobject>(receiver));
       ScopedThreadStateChange tsc(self, kNative);
@@ -343,12 +343,13 @@
     ++cur_reg;
   } else if (UNLIKELY(!method->GetDeclaringClass()->IsInitializing())) {
     ClassLinker* class_linker = Runtime::Current()->GetClassLinker();
-    if (UNLIKELY(!class_linker->EnsureInitialized(method->GetDeclaringClass(), true, true))) {
+    SirtRef<mirror::Class> sirt_c(self, method->GetDeclaringClass());
+    if (UNLIKELY(!class_linker->EnsureInitialized(sirt_c, true, true))) {
       CHECK(self->IsExceptionPending());
       self->PopShadowFrame();
       return;
     }
-    CHECK(method->GetDeclaringClass()->IsInitializing());
+    CHECK(sirt_c->IsInitializing());
   }
   const char* shorty = mh.GetShorty();
   for (size_t shorty_pos = 0, arg_pos = 0; cur_reg < num_regs; ++shorty_pos, ++arg_pos, cur_reg++) {
@@ -428,7 +429,7 @@
   ArtMethod* method = shadow_frame->GetMethod();
   // Ensure static methods are initialized.
   if (method->IsStatic()) {
-    Class* declaringClass = method->GetDeclaringClass();
+    SirtRef<Class> declaringClass(self, 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 c9756ac..5b9e55f 100644
--- a/runtime/interpreter/interpreter_common.cc
+++ b/runtime/interpreter/interpreter_common.cc
@@ -188,7 +188,7 @@
     } else {
       self->ThrowNewExceptionF(shadow_frame.GetCurrentLocationForThrow(),
                                "Ljava/lang/InternalError;",
-                               "Found type %s; filled-new-array not implemented for anything but \'int\'",
+                               "Found type %s; filled-new-array not implemented for anything but 'int'",
                                PrettyDescriptor(componentClass).c_str());
     }
     return false;
@@ -231,7 +231,10 @@
   // In a runtime that's not started we intercept certain methods to avoid complicated dependency
   // problems in core libraries.
   std::string name(PrettyMethod(shadow_frame->GetMethod()));
-  if (name == "java.lang.Class java.lang.Class.forName(java.lang.String)") {
+  if (name == "java.lang.Class java.lang.Class.forName(java.lang.String)"
+      || name == "java.lang.Class java.lang.VMClassLoader.loadClass(java.lang.String, boolean)") {
+    // TODO Class#forName should actually call Class::EnsureInitialized always. Support for the
+    // 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();
@@ -240,6 +243,13 @@
     CHECK(found != NULL) << "Class.forName failed in un-started runtime for class: "
         << PrettyDescriptor(descriptor);
     result->SetL(found);
+  } 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)));
+    std::string descriptor(DotToDescriptor(shadow_frame->GetVRegReference(arg_offset + 1)->AsString()->ToModifiedUtf8().c_str()));
+
+    Class* found = Runtime::Current()->GetClassLinker()->FindClass(descriptor.c_str(),
+                                                                   class_loader);
+    result->SetL(found);
   } else if (name == "java.lang.Object java.lang.Class.newInstance()") {
     Class* klass = shadow_frame->GetVRegReference(arg_offset)->AsClass();
     ArtMethod* c = klass->FindDeclaredDirectMethod("<init>", "()V");
diff --git a/runtime/interpreter/interpreter_common.h b/runtime/interpreter/interpreter_common.h
index 0bc834c..a9b8909 100644
--- a/runtime/interpreter/interpreter_common.h
+++ b/runtime/interpreter/interpreter_common.h
@@ -334,13 +334,14 @@
 // java.lang.String class is initialized.
 static inline String* ResolveString(Thread* self, MethodHelper& mh, uint32_t string_idx)
     SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
+  CHECK(!kMovingMethods);
   Class* java_lang_string_class = String::GetJavaLangString();
   if (UNLIKELY(!java_lang_string_class->IsInitialized())) {
     ClassLinker* class_linker = Runtime::Current()->GetClassLinker();
-    if (UNLIKELY(!class_linker->EnsureInitialized(java_lang_string_class,
-                                                  true, true))) {
+    SirtRef<mirror::Class> sirt_class(self, java_lang_string_class);
+    if (UNLIKELY(!class_linker->EnsureInitialized(sirt_class, true, true))) {
       DCHECK(self->IsExceptionPending());
-      return NULL;
+      return nullptr;
     }
   }
   return mh.ResolveString(string_idx);
@@ -556,11 +557,11 @@
 }
 
 // Explicitly instantiate all DoInvoke functions.
-#define EXPLICIT_DO_INVOKE_TEMPLATE_DECL(_type, _is_range, _do_check)                             \
-  template SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) ALWAYS_INLINE                              \
-  static bool DoInvoke<_type, _is_range, _do_check>(Thread* self, ShadowFrame& shadow_frame,      \
-                                                    const Instruction* inst, uint16_t inst_data,  \
-                                                    JValue* result)
+#define EXPLICIT_DO_INVOKE_TEMPLATE_DECL(_type, _is_range, _do_check)                      \
+  template SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) ALWAYS_INLINE                       \
+  bool DoInvoke<_type, _is_range, _do_check>(Thread* self, ShadowFrame& shadow_frame,      \
+                                             const Instruction* inst, uint16_t inst_data,  \
+                                             JValue* result)
 
 #define EXPLICIT_DO_INVOKE_ALL_TEMPLATE_DECL(_type)       \
   EXPLICIT_DO_INVOKE_TEMPLATE_DECL(_type, false, false);  \
@@ -577,10 +578,10 @@
 #undef EXPLICIT_DO_INVOKE_TEMPLATE_DECL
 
 // Explicitly instantiate all DoFieldGet functions.
-#define EXPLICIT_DO_FIELD_GET_TEMPLATE_DECL(_find_type, _field_type, _do_check)                       \
-  template SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) ALWAYS_INLINE                                  \
-  static bool DoFieldGet<_find_type, _field_type, _do_check>(Thread* self, ShadowFrame& shadow_frame, \
-                                                             const Instruction* inst, uint16_t inst_data)
+#define EXPLICIT_DO_FIELD_GET_TEMPLATE_DECL(_find_type, _field_type, _do_check)                \
+  template SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) ALWAYS_INLINE                           \
+  bool DoFieldGet<_find_type, _field_type, _do_check>(Thread* self, ShadowFrame& shadow_frame, \
+                                                      const Instruction* inst, uint16_t inst_data)
 
 #define EXPLICIT_DO_FIELD_GET_ALL_TEMPLATE_DECL(_find_type, _field_type)  \
     EXPLICIT_DO_FIELD_GET_TEMPLATE_DECL(_find_type, _field_type, false);  \
@@ -608,10 +609,10 @@
 #undef EXPLICIT_DO_FIELD_GET_TEMPLATE_DECL
 
 // Explicitly instantiate all DoFieldPut functions.
-#define EXPLICIT_DO_FIELD_PUT_TEMPLATE_DECL(_find_type, _field_type, _do_check)                             \
-  template SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) ALWAYS_INLINE                                        \
-  static bool DoFieldPut<_find_type, _field_type, _do_check>(Thread* self, const ShadowFrame& shadow_frame, \
-                                                             const Instruction* inst, uint16_t inst_data)
+#define EXPLICIT_DO_FIELD_PUT_TEMPLATE_DECL(_find_type, _field_type, _do_check)                      \
+  template SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) ALWAYS_INLINE                                 \
+  bool DoFieldPut<_find_type, _field_type, _do_check>(Thread* self, const ShadowFrame& shadow_frame, \
+                                                      const Instruction* inst, uint16_t inst_data)
 
 #define EXPLICIT_DO_FIELD_PUT_ALL_TEMPLATE_DECL(_find_type, _field_type)  \
     EXPLICIT_DO_FIELD_PUT_TEMPLATE_DECL(_find_type, _field_type, false);  \
@@ -639,21 +640,21 @@
 #undef EXPLICIT_DO_FIELD_PUT_TEMPLATE_DECL
 
 // Explicitly instantiate all DoInvokeVirtualQuick functions.
-#define EXPLICIT_DO_INVOKE_VIRTUAL_QUICK_TEMPLATE_DECL(_is_range)                       \
-  template SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) ALWAYS_INLINE                    \
-  static bool DoInvokeVirtualQuick<_is_range>(Thread* self, ShadowFrame& shadow_frame,  \
-                                          const Instruction* inst, uint16_t inst_data,  \
-                                          JValue* result)
+#define EXPLICIT_DO_INVOKE_VIRTUAL_QUICK_TEMPLATE_DECL(_is_range)                    \
+  template SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) ALWAYS_INLINE                 \
+  bool DoInvokeVirtualQuick<_is_range>(Thread* self, ShadowFrame& shadow_frame,      \
+                                       const Instruction* inst, uint16_t inst_data,  \
+                                       JValue* result)
 
 EXPLICIT_DO_INVOKE_VIRTUAL_QUICK_TEMPLATE_DECL(false);  // invoke-virtual-quick.
 EXPLICIT_DO_INVOKE_VIRTUAL_QUICK_TEMPLATE_DECL(true);   // invoke-virtual-quick-range.
 #undef EXPLICIT_INSTANTIATION_DO_INVOKE_VIRTUAL_QUICK
 
 // Explicitly instantiate all DoIGetQuick functions.
-#define EXPLICIT_DO_IGET_QUICK_TEMPLATE_DECL(_field_type)                                   \
-  template SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) ALWAYS_INLINE                        \
-  static bool DoIGetQuick<_field_type>(ShadowFrame& shadow_frame, const Instruction* inst,  \
-                                       uint16_t inst_data)
+#define EXPLICIT_DO_IGET_QUICK_TEMPLATE_DECL(_field_type)                            \
+  template SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) ALWAYS_INLINE                 \
+  bool DoIGetQuick<_field_type>(ShadowFrame& shadow_frame, const Instruction* inst,  \
+                                uint16_t inst_data)
 
 EXPLICIT_DO_IGET_QUICK_TEMPLATE_DECL(Primitive::kPrimInt);    // iget-quick.
 EXPLICIT_DO_IGET_QUICK_TEMPLATE_DECL(Primitive::kPrimLong);   // iget-wide-quick.
@@ -661,10 +662,10 @@
 #undef EXPLICIT_DO_IGET_QUICK_TEMPLATE_DECL
 
 // Explicitly instantiate all DoIPutQuick functions.
-#define EXPLICIT_DO_IPUT_QUICK_TEMPLATE_DECL(_field_type)                                         \
-  template SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) ALWAYS_INLINE                              \
-  static bool DoIPutQuick<_field_type>(const ShadowFrame& shadow_frame, const Instruction* inst,  \
-                                       uint16_t inst_data)
+#define EXPLICIT_DO_IPUT_QUICK_TEMPLATE_DECL(_field_type)                                  \
+  template SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) ALWAYS_INLINE                       \
+  bool DoIPutQuick<_field_type>(const ShadowFrame& shadow_frame, const Instruction* inst,  \
+                                uint16_t inst_data)
 
 EXPLICIT_DO_IPUT_QUICK_TEMPLATE_DECL(Primitive::kPrimInt);    // iget-quick.
 EXPLICIT_DO_IPUT_QUICK_TEMPLATE_DECL(Primitive::kPrimLong);   // iget-wide-quick.
diff --git a/runtime/jdwp/object_registry.cc b/runtime/jdwp/object_registry.cc
index be2219c..369eddd 100644
--- a/runtime/jdwp/object_registry.cc
+++ b/runtime/jdwp/object_registry.cc
@@ -118,6 +118,9 @@
 }
 
 jobject ObjectRegistry::GetJObject(JDWP::ObjectId id) {
+  if (id == 0) {
+    return NULL;
+  }
   Thread* self = Thread::Current();
   MutexLock mu(self, lock_);
   id_iterator it = id_to_entry_.find(id);
@@ -130,9 +133,7 @@
   Thread* self = Thread::Current();
   MutexLock mu(self, lock_);
   id_iterator it = id_to_entry_.find(id);
-  if (it == id_to_entry_.end()) {
-    return;
-  }
+  CHECK(it != id_to_entry_.end());
   Promote(*(it->second));
 }
 
@@ -140,9 +141,7 @@
   Thread* self = Thread::Current();
   MutexLock mu(self, lock_);
   id_iterator it = id_to_entry_.find(id);
-  if (it == id_to_entry_.end()) {
-    return;
-  }
+  CHECK(it != id_to_entry_.end());
   Demote(*(it->second));
 }
 
@@ -172,9 +171,7 @@
   Thread* self = Thread::Current();
   MutexLock mu(self, lock_);
   id_iterator it = id_to_entry_.find(id);
-  if (it == id_to_entry_.end()) {
-    return true;  // TODO: can we report that this was an invalid id?
-  }
+  CHECK(it != id_to_entry_.end());
 
   ObjectRegistryEntry& entry = *(it->second);
   if (entry.jni_reference_type == JNIWeakGlobalRefType) {
diff --git a/runtime/jni_internal.cc b/runtime/jni_internal.cc
index 466edeb..6690519 100644
--- a/runtime/jni_internal.cc
+++ b/runtime/jni_internal.cc
@@ -225,13 +225,24 @@
                                  kind, ClassHelper(c).GetDescriptor(), name, sig);
 }
 
+static mirror::Class* EnsureInitialized(Thread* self, mirror::Class* klass)
+    SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
+  if (LIKELY(klass->IsInitialized())) {
+    return klass;
+  }
+  SirtRef<mirror::Class> sirt_klass(self, klass);
+  if (!Runtime::Current()->GetClassLinker()->EnsureInitialized(sirt_klass, true, true)) {
+    return nullptr;
+  }
+  return sirt_klass.get();
+}
+
 static jmethodID FindMethodID(ScopedObjectAccess& soa, jclass jni_class,
                               const char* name, const char* sig, bool is_static)
     SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
-  Class* c = soa.Decode<Class*>(jni_class);
-  DCHECK(c != nullptr);
-  if (!Runtime::Current()->GetClassLinker()->EnsureInitialized(c, true, true)) {
-    return NULL;
+  Class* c = EnsureInitialized(soa.Self(), soa.Decode<Class*>(jni_class));
+  if (c == nullptr) {
+    return nullptr;
   }
 
   ArtMethod* method = NULL;
@@ -284,16 +295,16 @@
 static jfieldID FindFieldID(const ScopedObjectAccess& soa, jclass jni_class, const char* name,
                             const char* sig, bool is_static)
     SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
-  Class* c = soa.Decode<Class*>(jni_class);
-  if (!Runtime::Current()->GetClassLinker()->EnsureInitialized(c, true, true)) {
-    return NULL;
+  Class* c = EnsureInitialized(soa.Self(), soa.Decode<Class*>(jni_class));
+  if (c == nullptr) {
+    return nullptr;
   }
 
   ArtField* field = NULL;
   Class* field_type;
   ClassLinker* class_linker = Runtime::Current()->GetClassLinker();
   if (sig[1] != '\0') {
-    SirtRef<mirror::ClassLoader> class_loader(soa.Self(), GetClassLoader(soa));
+    SirtRef<mirror::ClassLoader> class_loader(soa.Self(), c->GetClassLoader());
     field_type = class_linker->FindClass(sig, class_loader);
   } else {
     field_type = class_linker->FindPrimitiveClass(*sig);
@@ -910,9 +921,9 @@
   static jobject AllocObject(JNIEnv* env, jclass java_class) {
     CHECK_NON_NULL_ARGUMENT(AllocObject, java_class);
     ScopedObjectAccess soa(env);
-    Class* c = soa.Decode<Class*>(java_class);
-    if (!Runtime::Current()->GetClassLinker()->EnsureInitialized(c, true, true)) {
-      return NULL;
+    Class* c = EnsureInitialized(soa.Self(), soa.Decode<Class*>(java_class));
+    if (c == nullptr) {
+      return nullptr;
     }
     return soa.AddLocalReference<jobject>(c->AllocObject(soa.Self()));
   }
@@ -931,20 +942,20 @@
     CHECK_NON_NULL_ARGUMENT(NewObjectV, java_class);
     CHECK_NON_NULL_ARGUMENT(NewObjectV, mid);
     ScopedObjectAccess soa(env);
-    Class* c = soa.Decode<Class*>(java_class);
-    if (!Runtime::Current()->GetClassLinker()->EnsureInitialized(c, true, true)) {
-      return NULL;
+    Class* c = EnsureInitialized(soa.Self(), soa.Decode<Class*>(java_class));
+    if (c == nullptr) {
+      return nullptr;
     }
     Object* result = c->AllocObject(soa.Self());
-    if (result == NULL) {
-      return NULL;
+    if (result == nullptr) {
+      return nullptr;
     }
     jobject local_result = soa.AddLocalReference<jobject>(result);
     CallNonvirtualVoidMethodV(env, local_result, java_class, mid, args);
     if (!soa.Self()->IsExceptionPending()) {
       return local_result;
     } else {
-      return NULL;
+      return nullptr;
     }
   }
 
@@ -952,9 +963,9 @@
     CHECK_NON_NULL_ARGUMENT(NewObjectA, java_class);
     CHECK_NON_NULL_ARGUMENT(NewObjectA, mid);
     ScopedObjectAccess soa(env);
-    Class* c = soa.Decode<Class*>(java_class);
-    if (!Runtime::Current()->GetClassLinker()->EnsureInitialized(c, true, true)) {
-      return NULL;
+    Class* c = EnsureInitialized(soa.Self(), soa.Decode<Class*>(java_class));
+    if (c == nullptr) {
+      return nullptr;
     }
     Object* result = c->AllocObject(soa.Self());
     if (result == NULL) {
@@ -3303,8 +3314,9 @@
   // If this is a static method, it could be called before the class
   // has been initialized.
   if (m->IsStatic()) {
-    if (!Runtime::Current()->GetClassLinker()->EnsureInitialized(c, true, true)) {
-      return NULL;
+    c = EnsureInitialized(Thread::Current(), c);
+    if (c == nullptr) {
+      return nullptr;
     }
   } else {
     CHECK(c->IsInitializing()) << c->GetStatus() << " " << PrettyMethod(m);
diff --git a/runtime/leb128.h b/runtime/leb128.h
index 6041f8c..7a7d38d 100644
--- a/runtime/leb128.h
+++ b/runtime/leb128.h
@@ -18,6 +18,7 @@
 #define ART_RUNTIME_LEB128_H_
 
 #include "globals.h"
+#include "utils.h"
 
 namespace art {
 
@@ -95,12 +96,20 @@
 
 // Returns the number of bytes needed to encode the value in unsigned LEB128.
 static inline uint32_t UnsignedLeb128Size(uint32_t data) {
-  uint32_t count = 0;
-  do {
-    data >>= 7;
-    count++;
-  } while (data != 0);
-  return count;
+  // bits_to_encode = (data != 0) ? 32 - CLZ(x) : 1  // 32 - CLZ(data | 1)
+  // bytes = ceil(bits_to_encode / 7.0);             // (6 + bits_to_encode) / 7
+  uint32_t x = 6 + 32 - CLZ(data | 1);
+  // Division by 7 is done by (x * 37) >> 8 where 37 = ceil(256 / 7).
+  // This works for 0 <= x < 256 / (7 * 37 - 256), i.e. 0 <= x <= 85.
+  return (x * 37) >> 8;
+}
+
+// Returns the number of bytes needed to encode the value in unsigned LEB128.
+static inline uint32_t SignedLeb128Size(int32_t data) {
+  // Like UnsignedLeb128Size(), but we need one bit beyond the highest bit that differs from sign.
+  data = data ^ (data >> 31);
+  uint32_t x = 1 /* we need to encode the sign bit */ + 6 + 32 - CLZ(data | 1);
+  return (x * 37) >> 8;
 }
 
 }  // namespace art
diff --git a/runtime/mapping_table.h b/runtime/mapping_table.h
index c468c1e..a82bc1c 100644
--- a/runtime/mapping_table.h
+++ b/runtime/mapping_table.h
@@ -72,7 +72,8 @@
         if (end_ > 0) {
           encoded_table_ptr_ = table_->FirstDexToPcPtr();
           native_pc_offset_ = DecodeUnsignedLeb128(&encoded_table_ptr_);
-          dex_pc_ = DecodeUnsignedLeb128(&encoded_table_ptr_);
+          // First delta is always positive.
+          dex_pc_ = static_cast<uint32_t>(DecodeSignedLeb128(&encoded_table_ptr_));
         }
       } else {  // An iterator wanted from the end.
         DCHECK_EQ(table_->DexToPcSize(), element);
@@ -87,8 +88,9 @@
     void operator++() {
       ++element_;
       if (element_ != end_) {  // Avoid reading beyond the end of the table.
-        native_pc_offset_ = DecodeUnsignedLeb128(&encoded_table_ptr_);
-        dex_pc_ = DecodeUnsignedLeb128(&encoded_table_ptr_);
+        native_pc_offset_ += DecodeUnsignedLeb128(&encoded_table_ptr_);
+        // For negative delta, unsigned overflow after static_cast does exactly what we need.
+        dex_pc_ += static_cast<uint32_t>(DecodeSignedLeb128(&encoded_table_ptr_));
       }
     }
     bool operator==(const DexToPcIterator& rhs) const {
@@ -147,7 +149,8 @@
         if (end_ > 0) {
           encoded_table_ptr_ = table_->FirstPcToDexPtr();
           native_pc_offset_ = DecodeUnsignedLeb128(&encoded_table_ptr_);
-          dex_pc_ = DecodeUnsignedLeb128(&encoded_table_ptr_);
+          // First delta is always positive.
+          dex_pc_ = static_cast<uint32_t>(DecodeSignedLeb128(&encoded_table_ptr_));
         }
       } else {  // An iterator wanted from the end.
         DCHECK_EQ(table_->PcToDexSize(), element);
@@ -162,8 +165,9 @@
     void operator++() {
       ++element_;
       if (element_ != end_) {  // Avoid reading beyond the end of the table.
-        native_pc_offset_ = DecodeUnsignedLeb128(&encoded_table_ptr_);
-        dex_pc_ = DecodeUnsignedLeb128(&encoded_table_ptr_);
+        native_pc_offset_ += DecodeUnsignedLeb128(&encoded_table_ptr_);
+        // For negative delta, unsigned overflow after static_cast does exactly what we need.
+        dex_pc_ += static_cast<uint32_t>(DecodeSignedLeb128(&encoded_table_ptr_));
       }
     }
     bool operator==(const PcToDexIterator& rhs) const {
diff --git a/runtime/mirror/array-inl.h b/runtime/mirror/array-inl.h
index a754b69..cf4b48c 100644
--- a/runtime/mirror/array-inl.h
+++ b/runtime/mirror/array-inl.h
@@ -108,6 +108,13 @@
                Runtime::Current()->GetHeap()->GetCurrentAllocator());
 }
 
+template<class T>
+inline void PrimitiveArray<T>::VisitRoots(RootVisitor* visitor, void* arg) {
+  if (array_class_ != nullptr) {
+    array_class_ = down_cast<Class*>(visitor(array_class_, arg));
+  }
+}
+
 }  // namespace mirror
 }  // namespace art
 
diff --git a/runtime/mirror/array.h b/runtime/mirror/array.h
index a332f97..5265946 100644
--- a/runtime/mirror/array.h
+++ b/runtime/mirror/array.h
@@ -149,6 +149,9 @@
     array_class_ = NULL;
   }
 
+  static void VisitRoots(RootVisitor* visitor, void* arg)
+      SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
+
  private:
   static Class* array_class_;
 
diff --git a/runtime/mirror/art_field.cc b/runtime/mirror/art_field.cc
index a8bbe4b..c3a4efb 100644
--- a/runtime/mirror/art_field.cc
+++ b/runtime/mirror/art_field.cc
@@ -52,5 +52,12 @@
   SetField32(OFFSET_OF_OBJECT_MEMBER(ArtField, offset_), num_bytes.Uint32Value(), false);
 }
 
+void ArtField::VisitRoots(RootVisitor* visitor, void* arg) {
+  if (java_lang_reflect_ArtField_ != nullptr) {
+    java_lang_reflect_ArtField_ = down_cast<mirror::Class*>(
+        visitor(java_lang_reflect_ArtField_, arg));
+  }
+}
+
 }  // namespace mirror
 }  // namespace art
diff --git a/runtime/mirror/art_field.h b/runtime/mirror/art_field.h
index ae34cb1..62bcf06 100644
--- a/runtime/mirror/art_field.h
+++ b/runtime/mirror/art_field.h
@@ -130,6 +130,8 @@
 
   static void SetClass(Class* java_lang_reflect_ArtField);
   static void ResetClass();
+  static void VisitRoots(RootVisitor* visitor, void* arg)
+      SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
 
   bool IsVolatile() const {
     return (GetAccessFlags() & kAccVolatile) != 0;
diff --git a/runtime/mirror/art_method.cc b/runtime/mirror/art_method.cc
index f5c0e9f..a4f6b3b 100644
--- a/runtime/mirror/art_method.cc
+++ b/runtime/mirror/art_method.cc
@@ -40,6 +40,13 @@
 // TODO: get global references for these
 Class* ArtMethod::java_lang_reflect_ArtMethod_ = NULL;
 
+void ArtMethod::VisitRoots(RootVisitor* visitor, void* arg) {
+  if (java_lang_reflect_ArtMethod_ != nullptr) {
+    java_lang_reflect_ArtMethod_ = down_cast<mirror::Class*>(
+        visitor(java_lang_reflect_ArtMethod_, arg));
+  }
+}
+
 InvokeType ArtMethod::GetInvokeType() const {
   // TODO: kSuper?
   if (GetDeclaringClass()->IsInterface()) {
diff --git a/runtime/mirror/art_method.h b/runtime/mirror/art_method.h
index f396fbe..d5524ec 100644
--- a/runtime/mirror/art_method.h
+++ b/runtime/mirror/art_method.h
@@ -23,6 +23,7 @@
 #include "locks.h"
 #include "modifiers.h"
 #include "object.h"
+#include "root_visitor.h"
 
 namespace art {
 
@@ -381,6 +382,9 @@
 
   static void ResetClass();
 
+  static void VisitRoots(RootVisitor* visitor, void* arg)
+      SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
+
  protected:
   // Field order required by test "ValidateFieldOrderOfJavaCppUnionClasses".
   // The class we are a part of
diff --git a/runtime/mirror/class.cc b/runtime/mirror/class.cc
index cdc5ab2..2746e1e 100644
--- a/runtime/mirror/class.cc
+++ b/runtime/mirror/class.cc
@@ -50,6 +50,12 @@
   java_lang_Class_ = NULL;
 }
 
+void Class::VisitRoots(RootVisitor* visitor, void* arg) {
+  if (java_lang_Class_ != nullptr) {
+    java_lang_Class_ = down_cast<Class*>(visitor(java_lang_Class_, arg));
+  }
+}
+
 void Class::SetStatus(Status new_status, Thread* self) {
   Status old_status = GetStatus();
   ClassLinker* class_linker = Runtime::Current()->GetClassLinker();
diff --git a/runtime/mirror/class.h b/runtime/mirror/class.h
index 5f64bb4..50ede66 100644
--- a/runtime/mirror/class.h
+++ b/runtime/mirror/class.h
@@ -787,6 +787,8 @@
   // Can't call this SetClass or else gets called instead of Object::SetClass in places.
   static void SetClassClass(Class* java_lang_Class);
   static void ResetClass();
+  static void VisitRoots(RootVisitor* visitor, void* arg)
+      SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
 
   // When class is verified, set the kAccPreverified flag on each method.
   void SetPreverifiedFlagOnAllMethods() SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
diff --git a/runtime/mirror/object.h b/runtime/mirror/object.h
index 0fb2039..fe89b7e 100644
--- a/runtime/mirror/object.h
+++ b/runtime/mirror/object.h
@@ -225,6 +225,11 @@
 
   void SetField64(MemberOffset field_offset, uint64_t new_value, bool is_volatile);
 
+  template<typename T>
+  void SetFieldPtr(MemberOffset field_offset, T new_value, bool is_volatile, bool this_is_valid = true) {
+    SetField32(field_offset, reinterpret_cast<uint32_t>(new_value), is_volatile, this_is_valid);
+  }
+
  protected:
   // Accessors for non-Java type fields
   template<class T>
@@ -232,11 +237,6 @@
     return reinterpret_cast<T>(GetField32(field_offset, is_volatile));
   }
 
-  template<typename T>
-  void SetFieldPtr(MemberOffset field_offset, T new_value, bool is_volatile, bool this_is_valid = true) {
-    SetField32(field_offset, reinterpret_cast<uint32_t>(new_value), is_volatile, this_is_valid);
-  }
-
  private:
   static void VerifyObject(const Object* obj) ALWAYS_INLINE;
   // Verify the type correctness of stores to fields.
diff --git a/runtime/mirror/object_test.cc b/runtime/mirror/object_test.cc
index 8272ff8..3637181 100644
--- a/runtime/mirror/object_test.cc
+++ b/runtime/mirror/object_test.cc
@@ -221,8 +221,8 @@
       java_lang_dex_file_->GetIndexForStringId(*string_id));
   ASSERT_TRUE(type_id != NULL);
   uint32_t type_idx = java_lang_dex_file_->GetIndexForTypeId(*type_id);
-  Object* array = CheckAndAllocArrayFromCode(type_idx, sort, 3, Thread::Current(), false,
-                                             Runtime::Current()->GetHeap()->GetCurrentAllocator());
+  Object* array = CheckAndAllocArrayFromCodeInstrumented(type_idx, sort, 3, Thread::Current(), false,
+                                                         Runtime::Current()->GetHeap()->GetCurrentAllocator());
   EXPECT_TRUE(array->IsArrayInstance());
   EXPECT_EQ(3, array->AsArray()->GetLength());
   EXPECT_TRUE(array->GetClass()->IsArrayClass());
diff --git a/runtime/mirror/stack_trace_element.cc b/runtime/mirror/stack_trace_element.cc
index 32a50fe..a7ebe07 100644
--- a/runtime/mirror/stack_trace_element.cc
+++ b/runtime/mirror/stack_trace_element.cc
@@ -58,5 +58,12 @@
   return trace;
 }
 
+void StackTraceElement::VisitRoots(RootVisitor* visitor, void* arg) {
+  if (java_lang_StackTraceElement_ != nullptr) {
+    java_lang_StackTraceElement_ = down_cast<Class*>(visitor(java_lang_StackTraceElement_, arg));
+  }
+}
+
+
 }  // namespace mirror
 }  // namespace art
diff --git a/runtime/mirror/stack_trace_element.h b/runtime/mirror/stack_trace_element.h
index 2af5128..d1be4dc 100644
--- a/runtime/mirror/stack_trace_element.h
+++ b/runtime/mirror/stack_trace_element.h
@@ -57,8 +57,9 @@
       SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
 
   static void SetClass(Class* java_lang_StackTraceElement);
-
   static void ResetClass();
+  static void VisitRoots(RootVisitor* visitor, void* arg)
+      SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
 
  private:
   // Field order required by test "ValidateFieldOrderOfJavaCppUnionClasses".
diff --git a/runtime/mirror/string.cc b/runtime/mirror/string.cc
index b372fe7..d6e509d 100644
--- a/runtime/mirror/string.cc
+++ b/runtime/mirror/string.cc
@@ -122,7 +122,7 @@
                                const uint16_t* utf16_data_in,
                                int32_t hash_code) {
   CHECK(utf16_data_in != NULL || utf16_length == 0);
-  String* string = Alloc(self, GetJavaLangString(), utf16_length);
+  String* string = Alloc(self, utf16_length);
   if (UNLIKELY(string == nullptr)) {
     return nullptr;
   }
@@ -152,7 +152,7 @@
 
 String* String::AllocFromModifiedUtf8(Thread* self, int32_t utf16_length,
                                       const char* utf8_data_in) {
-  String* string = Alloc(self, GetJavaLangString(), utf16_length);
+  String* string = Alloc(self, utf16_length);
   if (UNLIKELY(string == nullptr)) {
     return nullptr;
   }
@@ -163,21 +163,20 @@
   return string;
 }
 
-String* String::Alloc(Thread* self, Class* java_lang_String, int32_t utf16_length) {
-  CharArray* array = CharArray::Alloc(self, utf16_length);
-  if (UNLIKELY(array == nullptr)) {
+String* String::Alloc(Thread* self, int32_t utf16_length) {
+  SirtRef<CharArray> array(self, CharArray::Alloc(self, utf16_length));
+  if (UNLIKELY(array.get() == nullptr)) {
     return nullptr;
   }
-  return Alloc(self, java_lang_String, array);
+  return Alloc(self, array);
 }
 
-String* String::Alloc(Thread* self, Class* java_lang_String, CharArray* array) {
+String* String::Alloc(Thread* self, const SirtRef<CharArray>& array) {
   // Hold reference in case AllocObject causes GC.
-  SirtRef<CharArray> array_ref(self, array);
-  String* string = down_cast<String*>(java_lang_String->AllocObject(self));
+  String* string = down_cast<String*>(GetJavaLangString()->AllocObject(self));
   if (LIKELY(string != nullptr)) {
-    string->SetArray(array_ref.get());
-    string->SetCount(array_ref->GetLength());
+    string->SetArray(array.get());
+    string->SetCount(array->GetLength());
   }
   return string;
 }
@@ -287,5 +286,11 @@
   return countDiff;
 }
 
+void String::VisitRoots(RootVisitor* visitor, void* arg) {
+  if (java_lang_String_ != nullptr) {
+    java_lang_String_ = down_cast<Class*>(visitor(java_lang_String_, arg));
+  }
+}
+
 }  // namespace mirror
 }  // namespace art
diff --git a/runtime/mirror/string.h b/runtime/mirror/string.h
index 7520c4d..4bbcb9c 100644
--- a/runtime/mirror/string.h
+++ b/runtime/mirror/string.h
@@ -19,6 +19,7 @@
 
 #include "class.h"
 #include "gtest/gtest.h"
+#include "root_visitor.h"
 
 namespace art {
 
@@ -77,12 +78,6 @@
                                        const char* utf8_data_in)
       SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
 
-  static String* Alloc(Thread* self, Class* java_lang_String, int32_t utf16_length)
-      SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
-
-  static String* Alloc(Thread* self, Class* java_lang_String, CharArray* array)
-      SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
-
   bool Equals(const char* modified_utf8) const
       SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
 
@@ -114,6 +109,8 @@
 
   static void SetClass(Class* java_lang_String);
   static void ResetClass();
+  static void VisitRoots(RootVisitor* visitor, void* arg)
+      SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
 
  private:
   void SetHashCode(int32_t new_hash_code) {
@@ -132,6 +129,12 @@
     SetField32(OFFSET_OF_OBJECT_MEMBER(String, offset_), new_offset, false);
   }
 
+  static String* Alloc(Thread* self, int32_t utf16_length)
+      SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
+
+  static String* Alloc(Thread* self, const SirtRef<CharArray>& array)
+      SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
+
   void SetArray(CharArray* new_array) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
 
   // Field order required by test "ValidateFieldOrderOfJavaCppUnionClasses".
diff --git a/runtime/mirror/throwable.cc b/runtime/mirror/throwable.cc
index 961f6de..b55db72 100644
--- a/runtime/mirror/throwable.cc
+++ b/runtime/mirror/throwable.cc
@@ -93,5 +93,11 @@
   java_lang_Throwable_ = NULL;
 }
 
+void Throwable::VisitRoots(RootVisitor* visitor, void* arg) {
+  if (java_lang_Throwable_ != nullptr) {
+    java_lang_Throwable_ = down_cast<Class*>(visitor(java_lang_Throwable_, arg));
+  }
+}
+
 }  // namespace mirror
 }  // namespace art
diff --git a/runtime/mirror/throwable.h b/runtime/mirror/throwable.h
index 27f6e12..5a90599 100644
--- a/runtime/mirror/throwable.h
+++ b/runtime/mirror/throwable.h
@@ -18,6 +18,7 @@
 #define ART_RUNTIME_MIRROR_THROWABLE_H_
 
 #include "object.h"
+#include "root_visitor.h"
 #include "string.h"
 
 namespace art {
@@ -50,6 +51,8 @@
 
   static void SetClass(Class* java_lang_Throwable);
   static void ResetClass();
+  static void VisitRoots(RootVisitor* visitor, void* arg)
+      SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
 
  private:
   Object* GetStackState() const {
diff --git a/runtime/monitor.cc b/runtime/monitor.cc
index af93a56..ef9a9ce 100644
--- a/runtime/monitor.cc
+++ b/runtime/monitor.cc
@@ -633,8 +633,7 @@
     ScopedThreadStateChange tsc(self, kBlocked);
     if (lock_word == obj->GetLockWord()) {  // If lock word hasn't changed.
       bool timed_out;
-      Thread* owner = thread_list->SuspendThreadByThreadId(lock_word.ThinLockOwner(), false,
-                                                           &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();
diff --git a/runtime/native/dalvik_system_DexFile.cc b/runtime/native/dalvik_system_DexFile.cc
index c9e0e83..600045f 100644
--- a/runtime/native/dalvik_system_DexFile.cc
+++ b/runtime/native/dalvik_system_DexFile.cc
@@ -95,20 +95,27 @@
   }
 
   uint32_t dex_location_checksum;
+  uint32_t* dex_location_checksum_pointer = &dex_location_checksum;
   std::string error_msg;
-  if (!DexFile::GetChecksum(sourceName.c_str(), &dex_location_checksum, &error_msg)) {
-    ScopedObjectAccess soa(env);
-    DCHECK(!error_msg.empty());
-    ThrowIOException("%s", error_msg.c_str());
-    return 0;
+  if (!DexFile::GetChecksum(sourceName.c_str(), dex_location_checksum_pointer, &error_msg)) {
+    dex_location_checksum_pointer = NULL;
   }
 
   ClassLinker* linker = Runtime::Current()->GetClassLinker();
   const DexFile* dex_file;
   if (outputName.c_str() == nullptr) {
+    // FindOrCreateOatFileForDexLocation can tolerate a missing dex_location_checksum
+    error_msg.clear();
     dex_file = linker->FindDexFileInOatFileFromDexLocation(sourceName.c_str(),
-                                                           dex_location_checksum, &error_msg);
+                                                           dex_location_checksum_pointer, &error_msg);
   } else {
+    // FindOrCreateOatFileForDexLocation requires the dex_location_checksum
+    if (dex_location_checksum_pointer == NULL) {
+      ScopedObjectAccess soa(env);
+      DCHECK(!error_msg.empty());
+      ThrowIOException("%s", error_msg.c_str());
+      return 0;
+    }
     dex_file = linker->FindOrCreateOatFileForDexLocation(sourceName.c_str(), dex_location_checksum,
                                                          outputName.c_str(), &error_msg);
   }
diff --git a/runtime/native/dalvik_system_VMRuntime.cc b/runtime/native/dalvik_system_VMRuntime.cc
index fd3d91e..726a8f1 100644
--- a/runtime/native/dalvik_system_VMRuntime.cc
+++ b/runtime/native/dalvik_system_VMRuntime.cc
@@ -166,6 +166,10 @@
   Runtime::Current()->GetHeap()->RegisterNativeFree(env, bytes);
 }
 
+static void VMRuntime_updateProcessState(JNIEnv* env, jobject, jint process_state) {
+  Runtime::Current()->GetHeap()->UpdateProcessState(static_cast<gc::ProcessState>(process_state));
+}
+
 static void VMRuntime_trimHeap(JNIEnv*, jobject) {
   Runtime::Current()->GetHeap()->Trim();
 }
@@ -496,6 +500,7 @@
   NATIVE_METHOD(VMRuntime, setTargetSdkVersionNative, "(I)V"),
   NATIVE_METHOD(VMRuntime, registerNativeAllocation, "(I)V"),
   NATIVE_METHOD(VMRuntime, registerNativeFree, "(I)V"),
+  NATIVE_METHOD(VMRuntime, updateProcessState, "(I)V"),
   NATIVE_METHOD(VMRuntime, startJitCompilation, "()V"),
   NATIVE_METHOD(VMRuntime, trimHeap, "()V"),
   NATIVE_METHOD(VMRuntime, vmVersion, "()Ljava/lang/String;"),
diff --git a/runtime/native/java_lang_Class.cc b/runtime/native/java_lang_Class.cc
index 3389107..3e3f608 100644
--- a/runtime/native/java_lang_Class.cc
+++ b/runtime/native/java_lang_Class.cc
@@ -46,8 +46,8 @@
 static jclass Class_classForName(JNIEnv* env, jclass, jstring javaName, jboolean initialize, jobject javaLoader) {
   ScopedObjectAccess soa(env);
   ScopedUtfChars name(env, javaName);
-  if (name.c_str() == NULL) {
-    return NULL;
+  if (name.c_str() == nullptr) {
+    return nullptr;
   }
 
   // We need to validate and convert the name (from x.y.z to x/y/z).  This
@@ -57,27 +57,27 @@
     ThrowLocation throw_location = soa.Self()->GetCurrentLocationForThrow();
     soa.Self()->ThrowNewExceptionF(throw_location, "Ljava/lang/ClassNotFoundException;",
                                    "Invalid name: %s", name.c_str());
-    return NULL;
+    return nullptr;
   }
 
   std::string descriptor(DotToDescriptor(name.c_str()));
   SirtRef<mirror::ClassLoader> class_loader(soa.Self(),
                                             soa.Decode<mirror::ClassLoader*>(javaLoader));
   ClassLinker* class_linker = Runtime::Current()->GetClassLinker();
-  mirror::Class* c = class_linker->FindClass(descriptor.c_str(), class_loader);
-  if (c == NULL) {
+  SirtRef<mirror::Class> c(soa.Self(), class_linker->FindClass(descriptor.c_str(), class_loader));
+  if (c.get() == nullptr) {
     ScopedLocalRef<jthrowable> cause(env, env->ExceptionOccurred());
     env->ExceptionClear();
     jthrowable cnfe = reinterpret_cast<jthrowable>(env->NewObject(WellKnownClasses::java_lang_ClassNotFoundException,
                                                                   WellKnownClasses::java_lang_ClassNotFoundException_init,
                                                                   javaName, cause.get()));
     env->Throw(cnfe);
-    return NULL;
+    return nullptr;
   }
   if (initialize) {
     class_linker->EnsureInitialized(c, true, true);
   }
-  return soa.AddLocalReference<jclass>(c);
+  return soa.AddLocalReference<jclass>(c.get());
 }
 
 static jstring Class_getNameNative(JNIEnv* env, jobject javaThis) {
diff --git a/runtime/native/java_lang_VMClassLoader.cc b/runtime/native/java_lang_VMClassLoader.cc
index af1b548..314cdb1 100644
--- a/runtime/native/java_lang_VMClassLoader.cc
+++ b/runtime/native/java_lang_VMClassLoader.cc
@@ -78,7 +78,7 @@
     LOG(WARNING) << "Failed to open zip archive '" << location << "': " << error_msg;
     return NULL;
   }
-  UniquePtr<ZipEntry> zip_entry(zip_archive->Find(name.c_str()));
+  UniquePtr<ZipEntry> zip_entry(zip_archive->Find(name.c_str(), &error_msg));
   if (zip_entry.get() == NULL) {
     return NULL;
   }
diff --git a/runtime/native/java_lang_reflect_Constructor.cc b/runtime/native/java_lang_reflect_Constructor.cc
index 04dfcb5..5811992 100644
--- a/runtime/native/java_lang_reflect_Constructor.cc
+++ b/runtime/native/java_lang_reflect_Constructor.cc
@@ -41,24 +41,24 @@
       javaMethod, WellKnownClasses::java_lang_reflect_AbstractMethod_artMethod);
 
   mirror::ArtMethod* m = soa.Decode<mirror::Object*>(art_method)->AsArtMethod();
-  mirror::Class* c = m->GetDeclaringClass();
+  SirtRef<mirror::Class> c(soa.Self(), 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).c_str());
-    return NULL;
+                                   PrettyDescriptor(c.get()).c_str());
+    return nullptr;
   }
 
   if (!Runtime::Current()->GetClassLinker()->EnsureInitialized(c, true, true)) {
     DCHECK(soa.Self()->IsExceptionPending());
-    return NULL;
+    return nullptr;
   }
 
   mirror::Object* receiver = c->AllocNonMovableObject(soa.Self());
-  if (receiver == NULL) {
-    return NULL;
+  if (receiver == nullptr) {
+    return nullptr;
   }
 
   jobject javaReceiver = soa.AddLocalReference<jobject>(receiver);
diff --git a/runtime/native/java_lang_reflect_Field.cc b/runtime/native/java_lang_reflect_Field.cc
index 4d69a68..553aeb8 100644
--- a/runtime/native/java_lang_reflect_Field.cc
+++ b/runtime/native/java_lang_reflect_Field.cc
@@ -31,10 +31,13 @@
                           mirror::ArtField* f, JValue& value, bool allow_references)
     SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
   DCHECK_EQ(value.GetJ(), 0LL);
-  if (!Runtime::Current()->GetClassLinker()->EnsureInitialized(f->GetDeclaringClass(),
-                                                               true, true)) {
+  CHECK(!kMovingFields);
+  SirtRef<mirror::Object> sirt_obj(soa.Self(), o);
+  SirtRef<mirror::Class> sirt_klass(soa.Self(), f->GetDeclaringClass());
+  if (!Runtime::Current()->GetClassLinker()->EnsureInitialized(sirt_klass, true, true)) {
     return false;
   }
+  o = sirt_obj.get();
   switch (FieldHelper(f).GetTypeAsPrimitiveType()) {
   case Primitive::kPrimBoolean:
     value.SetZ(f->GetBoolean(o));
@@ -168,13 +171,16 @@
   return GetPrimitiveField(env, javaField, javaObj, 'S').GetS();
 }
 
-static void SetFieldValue(mirror::Object* o, mirror::ArtField* f, const JValue& new_value,
-                          bool allow_references)
+static void SetFieldValue(ScopedFastNativeObjectAccess& soa, mirror::Object* o,
+                          mirror::ArtField* f, const JValue& new_value, bool allow_references)
     SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
-  if (!Runtime::Current()->GetClassLinker()->EnsureInitialized(f->GetDeclaringClass(),
-                                                               true, true)) {
+  CHECK(!kMovingFields);
+  SirtRef<mirror::Object> sirt_obj(soa.Self(), o);
+  SirtRef<mirror::Class> sirt_klass(soa.Self(), f->GetDeclaringClass());
+  if (!Runtime::Current()->GetClassLinker()->EnsureInitialized(sirt_klass, true, true)) {
     return;
   }
+  o = sirt_obj.get();
   switch (FieldHelper(f).GetTypeAsPrimitiveType()) {
   case Primitive::kPrimBoolean:
     f->SetBoolean(o, new_value.GetZ());
@@ -237,7 +243,7 @@
     return;
   }
 
-  SetFieldValue(o, f, unboxed_value, true);
+  SetFieldValue(soa, o, f, unboxed_value, true);
 }
 
 static void SetPrimitiveField(JNIEnv* env, jobject javaField, jobject javaObj, char src_descriptor,
@@ -264,7 +270,7 @@
   }
 
   // Write the value.
-  SetFieldValue(o, f, wide_value, false);
+  SetFieldValue(soa, o, f, wide_value, false);
 }
 
 static void Field_setBoolean(JNIEnv* env, jobject javaField, jobject javaObj, jboolean z) {
diff --git a/runtime/oat.cc b/runtime/oat.cc
index 50069b2..52e74ab 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', '1', '1', '\0' };
+const uint8_t OatHeader::kOatVersion[] = { '0', '1', '2', '\0' };
 
 OatHeader::OatHeader() {
   memset(this, 0, sizeof(*this));
diff --git a/runtime/object_utils.h b/runtime/object_utils.h
index e37510c..cc996bc 100644
--- a/runtime/object_utils.h
+++ b/runtime/object_utils.h
@@ -34,34 +34,36 @@
 
 namespace art {
 
+template <typename T>
 class ObjectLock {
  public:
-  explicit ObjectLock(Thread* self, mirror::Object* object)
+  explicit ObjectLock(Thread* self, const SirtRef<T>* object)
       SHARED_LOCKS_REQUIRED(Locks::mutator_lock_)
       : self_(self), obj_(object) {
-    CHECK(object != NULL);
-    obj_->MonitorEnter(self_);
+    CHECK(object != nullptr);
+    CHECK(object->get() != nullptr);
+    obj_->get()->MonitorEnter(self_);
   }
 
   ~ObjectLock() SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
-    obj_->MonitorExit(self_);
+    obj_->get()->MonitorExit(self_);
   }
 
   void WaitIgnoringInterrupts() SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
-    Monitor::Wait(self_, obj_, 0, 0, false, kWaiting);
+    Monitor::Wait(self_, obj_->get(), 0, 0, false, kWaiting);
   }
 
   void Notify() SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
-    obj_->Notify(self_);
+    obj_->get()->Notify(self_);
   }
 
   void NotifyAll() SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
-    obj_->NotifyAll(self_);
+    obj_->get()->NotifyAll(self_);
   }
 
  private:
   Thread* const self_;
-  mirror::Object* obj_;
+  const SirtRef<T>* obj_;
   DISALLOW_COPY_AND_ASSIGN(ObjectLock);
 };
 
diff --git a/runtime/reflection.cc b/runtime/reflection.cc
index 80e16aa..ac8f5ef 100644
--- a/runtime/reflection.cc
+++ b/runtime/reflection.cc
@@ -39,8 +39,12 @@
   mirror::ArtMethod* m = soa.DecodeMethod(mid);
 
   mirror::Class* declaring_class = m->GetDeclaringClass();
-  if (!Runtime::Current()->GetClassLinker()->EnsureInitialized(declaring_class, true, true)) {
-    return NULL;
+  if (UNLIKELY(!declaring_class->IsInitialized())) {
+    SirtRef<mirror::Class> sirt_c(soa.Self(), declaring_class);
+    if (!Runtime::Current()->GetClassLinker()->EnsureInitialized(sirt_c, true, true)) {
+      return nullptr;
+    }
+    declaring_class = sirt_c.get();
   }
 
   mirror::Object* receiver = NULL;
diff --git a/runtime/runtime.cc b/runtime/runtime.cc
index 6bd2560..e1b4d7e 100644
--- a/runtime/runtime.cc
+++ b/runtime/runtime.cc
@@ -47,6 +47,7 @@
 #include "mirror/array.h"
 #include "mirror/class-inl.h"
 #include "mirror/class_loader.h"
+#include "mirror/stack_trace_element.h"
 #include "mirror/throwable.h"
 #include "monitor.h"
 #include "oat_file.h"
@@ -86,6 +87,7 @@
       resolution_method_(NULL),
       imt_conflict_method_(NULL),
       default_imt_(NULL),
+      method_verifiers_lock_("Method verifiers lock"),
       threads_being_born_(0),
       shutdown_cond_(new ConditionVariable("Runtime shutdown", *Locks::runtime_shutdown_lock_)),
       shutting_down_(false),
@@ -131,11 +133,6 @@
   heap_->WaitForGcToComplete(self);
   heap_->DeleteThreadPool();
 
-  // For RosAlloc, revoke thread local runs. Note that in tests
-  // (common_test.h) we repeat allocating and deleting Runtime
-  // objects.
-  heap_->RevokeAllThreadLocalBuffers();
-
   // Make sure our internal threads are dead before we start tearing down things they're using.
   Dbg::StopJdwp();
   delete signal_catcher_;
@@ -704,35 +701,38 @@
   }
 
   ScopedObjectAccess soa(Thread::Current());
+  ClassLinker* cl = Runtime::Current()->GetClassLinker();
 
-  mirror::Class* class_loader_class =
-      soa.Decode<mirror::Class*>(WellKnownClasses::java_lang_ClassLoader);
-  CHECK(Runtime::Current()->GetClassLinker()->EnsureInitialized(class_loader_class, true, true));
+  SirtRef<mirror::Class> class_loader_class(
+      soa.Self(), soa.Decode<mirror::Class*>(WellKnownClasses::java_lang_ClassLoader));
+  CHECK(cl->EnsureInitialized(class_loader_class, true, true));
 
   mirror::ArtMethod* getSystemClassLoader =
       class_loader_class->FindDirectMethod("getSystemClassLoader", "()Ljava/lang/ClassLoader;");
   CHECK(getSystemClassLoader != NULL);
 
   JValue result;
-  ArgArray arg_array(NULL, 0);
+  ArgArray arg_array(nullptr, 0);
   InvokeWithArgArray(soa, getSystemClassLoader, &arg_array, &result, 'L');
-  mirror::ClassLoader* class_loader = down_cast<mirror::ClassLoader*>(result.GetL());
-  CHECK(class_loader != NULL);
-
+  SirtRef<mirror::ClassLoader> class_loader(soa.Self(),
+                                            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));
-  CHECK(system_class_loader.get() != NULL);
+  ScopedLocalRef<jobject> system_class_loader(env,
+                                              soa.AddLocalReference<jobject>(class_loader.get()));
+  CHECK(system_class_loader.get() != nullptr);
 
-  soa.Self()->SetClassLoaderOverride(class_loader);
+  soa.Self()->SetClassLoaderOverride(class_loader.get());
 
-  mirror::Class* thread_class = soa.Decode<mirror::Class*>(WellKnownClasses::java_lang_Thread);
-  CHECK(Runtime::Current()->GetClassLinker()->EnsureInitialized(thread_class, true, true));
+  SirtRef<mirror::Class> thread_class(soa.Self(),
+                                      soa.Decode<mirror::Class*>(WellKnownClasses::java_lang_Thread));
+  CHECK(cl->EnsureInitialized(thread_class, true, true));
 
-  mirror::ArtField* contextClassLoader = thread_class->FindDeclaredInstanceField("contextClassLoader",
-                                                                                 "Ljava/lang/ClassLoader;");
+  mirror::ArtField* contextClassLoader =
+      thread_class->FindDeclaredInstanceField("contextClassLoader", "Ljava/lang/ClassLoader;");
   CHECK(contextClassLoader != NULL);
 
-  contextClassLoader->SetObject(soa.Self()->GetPeer(), class_loader);
+  contextClassLoader->SetObject(soa.Self()->GetPeer(), class_loader.get());
 
   return env->NewGlobalRef(system_class_loader.get());
 }
@@ -1193,9 +1193,25 @@
 }
 
 void Runtime::VisitNonThreadRoots(RootVisitor* visitor, void* arg) {
+  // Visit the classes held as static in mirror classes.
+  mirror::ArtField::VisitRoots(visitor, arg);
+  mirror::ArtMethod::VisitRoots(visitor, arg);
+  mirror::Class::VisitRoots(visitor, arg);
+  mirror::StackTraceElement::VisitRoots(visitor, arg);
+  mirror::String::VisitRoots(visitor, arg);
+  mirror::Throwable::VisitRoots(visitor, arg);
+  // Visit all the primitive array types classes.
+  mirror::PrimitiveArray<uint8_t>::VisitRoots(visitor, arg);   // BooleanArray
+  mirror::PrimitiveArray<int8_t>::VisitRoots(visitor, arg);    // ByteArray
+  mirror::PrimitiveArray<uint16_t>::VisitRoots(visitor, arg);  // CharArray
+  mirror::PrimitiveArray<double>::VisitRoots(visitor, arg);    // DoubleArray
+  mirror::PrimitiveArray<float>::VisitRoots(visitor, arg);     // FloatArray
+  mirror::PrimitiveArray<int32_t>::VisitRoots(visitor, arg);   // IntArray
+  mirror::PrimitiveArray<int64_t>::VisitRoots(visitor, arg);   // LongArray
+  mirror::PrimitiveArray<int16_t>::VisitRoots(visitor, arg);   // ShortArray
   java_vm_->VisitRoots(visitor, arg);
   if (pre_allocated_OutOfMemoryError_ != nullptr) {
-    pre_allocated_OutOfMemoryError_ = reinterpret_cast<mirror::Throwable*>(
+    pre_allocated_OutOfMemoryError_ = down_cast<mirror::Throwable*>(
         visitor(pre_allocated_OutOfMemoryError_, arg));
     DCHECK(pre_allocated_OutOfMemoryError_ != nullptr);
   }
@@ -1214,6 +1230,12 @@
           visitor(callee_save_methods_[i], arg));
     }
   }
+  {
+    MutexLock mu(Thread::Current(), method_verifiers_lock_);
+    for (verifier::MethodVerifier* verifier : method_verifiers_) {
+      verifier->VisitRoots(visitor, arg);
+    }
+  }
 }
 
 void Runtime::VisitNonConcurrentRoots(RootVisitor* visitor, void* arg) {
@@ -1360,4 +1382,18 @@
   compile_time_class_paths_.Put(class_loader, class_path);
 }
 
+void Runtime::AddMethodVerifier(verifier::MethodVerifier* verifier) {
+  DCHECK(verifier != nullptr);
+  MutexLock mu(Thread::Current(), method_verifiers_lock_);
+  method_verifiers_.insert(verifier);
+}
+
+void Runtime::RemoveMethodVerifier(verifier::MethodVerifier* verifier) {
+  DCHECK(verifier != nullptr);
+  MutexLock mu(Thread::Current(), method_verifiers_lock_);
+  auto it = method_verifiers_.find(verifier);
+  CHECK(it != method_verifiers_.end());
+  method_verifiers_.erase(it);
+}
+
 }  // namespace art
diff --git a/runtime/runtime.h b/runtime/runtime.h
index e6951d9..01a605a 100644
--- a/runtime/runtime.h
+++ b/runtime/runtime.h
@@ -52,6 +52,9 @@
   class String;
   class Throwable;
 }  // namespace mirror
+namespace verifier {
+class MethodVerifier;
+}
 class ClassLinker;
 class DexFile;
 class InternTable;
@@ -320,14 +323,16 @@
       SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
 
   // Visit all of the roots we can do safely do concurrently.
-  void VisitConcurrentRoots(RootVisitor* visitor, void* arg, bool only_dirty, bool clean_dirty);
+  void VisitConcurrentRoots(RootVisitor* visitor, void* arg, bool only_dirty, bool clean_dirty)
+      SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
 
   // Visit all of the non thread roots, we can do this with mutators unpaused.
-  void VisitNonThreadRoots(RootVisitor* visitor, void* arg);
+  void VisitNonThreadRoots(RootVisitor* visitor, void* arg)
+      SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
 
   // Visit all other roots which must be done with mutators suspended.
   void VisitNonConcurrentRoots(RootVisitor* visitor, void* arg)
-    SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
+      SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
 
   // Sweep system weaks, the system weak is deleted if the visitor return nullptr. Otherwise, the
   // system weak is updated to be the visitor's returned value.
@@ -438,6 +443,9 @@
     return use_compile_time_class_path_;
   }
 
+  void AddMethodVerifier(verifier::MethodVerifier* verifier);
+  void RemoveMethodVerifier(verifier::MethodVerifier* verifier);
+
   const std::vector<const DexFile*>& GetCompileTimeClassPath(jobject class_loader);
   void SetCompileTimeClassPath(jobject class_loader, std::vector<const DexFile*>& class_path);
 
@@ -520,6 +528,10 @@
 
   mirror::ObjectArray<mirror::ArtMethod>* default_imt_;
 
+  // Method verifier set, used so that we can update their GC roots.
+  Mutex method_verifiers_lock_;
+  std::set<verifier::MethodVerifier*> method_verifiers_;
+
   // A non-zero value indicates that a thread has been created but not yet initialized. Guarded by
   // the shutdown lock so that threads aren't born while we're shutting down.
   size_t threads_being_born_ GUARDED_BY(Locks::runtime_shutdown_lock_);
diff --git a/runtime/stack.cc b/runtime/stack.cc
index a505383..4e3fb4a 100644
--- a/runtime/stack.cc
+++ b/runtime/stack.cc
@@ -259,6 +259,7 @@
 }
 
 instrumentation::InstrumentationStackFrame& StackVisitor::GetInstrumentationStackFrame(uint32_t depth) const {
+  CHECK_LT(depth, thread_->GetInstrumentationStack()->size());
   return thread_->GetInstrumentationStack()->at(depth);
 }
 
diff --git a/runtime/thread-inl.h b/runtime/thread-inl.h
index 8449607..e47fd37 100644
--- a/runtime/thread-inl.h
+++ b/runtime/thread-inl.h
@@ -50,7 +50,8 @@
   // old_state_and_flags.suspend_request is true.
   DCHECK_NE(new_state, kRunnable);
   DCHECK_EQ(this, Thread::Current());
-  union StateAndFlags old_state_and_flags = state_and_flags_;
+  union StateAndFlags old_state_and_flags;
+  old_state_and_flags.as_int = state_and_flags_.as_int;
   state_and_flags_.as_struct.state = new_state;
   return static_cast<ThreadState>(old_state_and_flags.as_struct.state);
 }
@@ -87,7 +88,7 @@
   union StateAndFlags old_state_and_flags;
   union StateAndFlags new_state_and_flags;
   do {
-    old_state_and_flags = state_and_flags_;
+    old_state_and_flags.as_int = state_and_flags_.as_int;
     if (UNLIKELY((old_state_and_flags.as_struct.flags & kCheckpointRequest) != 0)) {
       RunCheckpointFunction();
       continue;
@@ -104,22 +105,23 @@
 
 inline ThreadState Thread::TransitionFromSuspendedToRunnable() {
   bool done = false;
-  union StateAndFlags old_state_and_flags = state_and_flags_;
+  union StateAndFlags old_state_and_flags;
+  old_state_and_flags.as_int = state_and_flags_.as_int;
   int16_t old_state = old_state_and_flags.as_struct.state;
   DCHECK_NE(static_cast<ThreadState>(old_state), kRunnable);
   do {
     Locks::mutator_lock_->AssertNotHeld(this);  // Otherwise we starve GC..
-    old_state_and_flags = state_and_flags_;
+    old_state_and_flags.as_int = state_and_flags_.as_int;
     DCHECK_EQ(old_state_and_flags.as_struct.state, old_state);
     if (UNLIKELY((old_state_and_flags.as_struct.flags & kSuspendRequest) != 0)) {
       // Wait while our suspend count is non-zero.
       MutexLock mu(this, *Locks::thread_suspend_count_lock_);
-      old_state_and_flags = state_and_flags_;
+      old_state_and_flags.as_int = state_and_flags_.as_int;
       DCHECK_EQ(old_state_and_flags.as_struct.state, old_state);
       while ((old_state_and_flags.as_struct.flags & kSuspendRequest) != 0) {
         // Re-check when Thread::resume_cond_ is notified.
         Thread::resume_cond_->Wait(this);
-        old_state_and_flags = state_and_flags_;
+        old_state_and_flags.as_int = state_and_flags_.as_int;
         DCHECK_EQ(old_state_and_flags.as_struct.state, old_state);
       }
       DCHECK_EQ(GetSuspendCount(), 0);
@@ -127,10 +129,11 @@
     // Re-acquire shared mutator_lock_ access.
     Locks::mutator_lock_->SharedLock(this);
     // Atomically change from suspended to runnable if no suspend request pending.
-    old_state_and_flags = state_and_flags_;
+    old_state_and_flags.as_int = state_and_flags_.as_int;
     DCHECK_EQ(old_state_and_flags.as_struct.state, old_state);
     if (LIKELY((old_state_and_flags.as_struct.flags & kSuspendRequest) == 0)) {
-      union StateAndFlags new_state_and_flags = old_state_and_flags;
+      union StateAndFlags new_state_and_flags;
+      new_state_and_flags.as_int = old_state_and_flags.as_int;
       new_state_and_flags.as_struct.state = kRunnable;
       // CAS the value without a memory barrier, that occurred in the lock above.
       done = android_atomic_cas(old_state_and_flags.as_int, new_state_and_flags.as_int,
diff --git a/runtime/thread.cc b/runtime/thread.cc
index 1add507..2861213 100644
--- a/runtime/thread.cc
+++ b/runtime/thread.cc
@@ -579,19 +579,21 @@
 }
 
 bool Thread::RequestCheckpoint(Closure* function) {
-  union StateAndFlags old_state_and_flags = state_and_flags_;
+  union StateAndFlags old_state_and_flags;
+  old_state_and_flags.as_int = state_and_flags_.as_int;
   if (old_state_and_flags.as_struct.state != kRunnable) {
     return false;  // Fail, thread is suspended and so can't run a checkpoint.
   }
   if ((old_state_and_flags.as_struct.flags & kCheckpointRequest) != 0) {
     return false;  // Fail, already a checkpoint pending.
   }
-  CHECK(checkpoint_function_ == NULL);
+  CHECK(checkpoint_function_ == nullptr);
   checkpoint_function_ = function;
   // Checkpoint function installed now install flag bit.
   // We must be runnable to request a checkpoint.
-  old_state_and_flags.as_struct.state = kRunnable;
-  union StateAndFlags new_state_and_flags = old_state_and_flags;
+  DCHECK_EQ(old_state_and_flags.as_struct.state, kRunnable);
+  union StateAndFlags new_state_and_flags;
+  new_state_and_flags.as_int = old_state_and_flags.as_int;
   new_state_and_flags.as_struct.flags |= kCheckpointRequest;
   int succeeded = android_atomic_cmpxchg(old_state_and_flags.as_int, new_state_and_flags.as_int,
                                          &state_and_flags_.as_int);
@@ -985,8 +987,9 @@
     mirror::Object* lock =
         soa.DecodeField(WellKnownClasses::java_lang_Thread_lock)->GetObject(opeer_);
     // (This conditional is only needed for tests, where Thread.lock won't have been set.)
-    if (lock != NULL) {
-      ObjectLock locker(self, lock);
+    if (lock != nullptr) {
+      SirtRef<mirror::Object> sirt_obj(self, lock);
+      ObjectLock<mirror::Object> locker(self, &sirt_obj);
       locker.Notify();
     }
   }
@@ -1281,7 +1284,7 @@
       return true;  // Ignore runtime frames (in particular callee save).
     }
     method_trace_->Set(count_, m);
-    dex_pc_trace_->Set(count_, GetDexPc());
+    dex_pc_trace_->Set(count_, m->IsProxyMethod() ? DexFile::kDexNoIndex : GetDexPc());
     ++count_;
     return true;
   }
@@ -1363,19 +1366,31 @@
     // Prepare parameters for StackTraceElement(String cls, String method, String file, int line)
     mirror::ArtMethod* method = down_cast<mirror::ArtMethod*>(method_trace->Get(i));
     MethodHelper mh(method);
-    mirror::IntArray* pc_trace = down_cast<mirror::IntArray*>(method_trace->Get(depth));
-    uint32_t dex_pc = pc_trace->Get(i);
-    int32_t line_number = mh.GetLineNumFromDexPC(dex_pc);
-    // Allocate element, potentially triggering GC
-    // TODO: reuse class_name_object via Class::name_?
-    const char* descriptor = mh.GetDeclaringClassDescriptor();
-    CHECK(descriptor != NULL);
-    std::string class_name(PrettyDescriptor(descriptor));
-    SirtRef<mirror::String> class_name_object(soa.Self(),
-                                              mirror::String::AllocFromModifiedUtf8(soa.Self(),
-                                                                                    class_name.c_str()));
-    if (class_name_object.get() == NULL) {
-      return NULL;
+    int32_t line_number;
+    SirtRef<mirror::String> class_name_object(soa.Self(), NULL);
+    SirtRef<mirror::String> source_name_object(soa.Self(), NULL);
+    if (method->IsProxyMethod()) {
+      line_number = -1;
+      class_name_object.reset(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));
+      uint32_t dex_pc = pc_trace->Get(i);
+      line_number = mh.GetLineNumFromDexPC(dex_pc);
+      // Allocate element, potentially triggering GC
+      // TODO: reuse class_name_object via Class::name_?
+      const char* descriptor = mh.GetDeclaringClassDescriptor();
+      CHECK(descriptor != NULL);
+      std::string class_name(PrettyDescriptor(descriptor));
+      class_name_object.reset(mirror::String::AllocFromModifiedUtf8(soa.Self(), class_name.c_str()));
+      if (class_name_object.get() == NULL) {
+        return NULL;
+      }
+      const char* source_file = mh.GetDeclaringClassSourceFile();
+      source_name_object.reset(mirror::String::AllocFromModifiedUtf8(soa.Self(), source_file));
+      if (source_name_object.get() == NULL) {
+        return NULL;
+      }
     }
     const char* method_name = mh.GetName();
     CHECK(method_name != NULL);
@@ -1385,10 +1400,6 @@
     if (method_name_object.get() == NULL) {
       return NULL;
     }
-    const char* source_file = mh.GetDeclaringClassSourceFile();
-    SirtRef<mirror::String> source_name_object(soa.Self(),
-                                               mirror::String::AllocFromModifiedUtf8(soa.Self(),
-                                                                                     source_file));
     mirror::StackTraceElement* obj = mirror::StackTraceElement::Alloc(
         soa.Self(), class_name_object, method_name_object, source_name_object, line_number);
     if (obj == NULL) {
@@ -1434,9 +1445,9 @@
   ClearException();
   Runtime* runtime = Runtime::Current();
 
-  mirror::ClassLoader* cl = NULL;
-  if (throw_location.GetMethod() != NULL) {
-    cl = throw_location.GetMethod()->GetDeclaringClass()->GetClassLoader();
+  mirror::ClassLoader* cl = nullptr;
+  if (saved_throw_method.get() != nullptr) {
+    cl = saved_throw_method.get()->GetDeclaringClass()->GetClassLoader();
   }
   SirtRef<mirror::ClassLoader> class_loader(this, cl);
   SirtRef<mirror::Class>
@@ -1448,7 +1459,7 @@
     return;
   }
 
-  if (UNLIKELY(!runtime->GetClassLinker()->EnsureInitialized(exception_class.get(), true, true))) {
+  if (UNLIKELY(!runtime->GetClassLinker()->EnsureInitialized(exception_class, true, true))) {
     DCHECK(IsExceptionPending());
     return;
   }
@@ -1458,7 +1469,9 @@
 
   // If we couldn't allocate the exception, throw the pre-allocated out of memory exception.
   if (exception.get() == nullptr) {
-    SetException(throw_location, Runtime::Current()->GetPreAllocatedOutOfMemoryError());
+    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;
   }
 
@@ -1818,6 +1831,12 @@
     self_->EndAssertNoThreadSuspension(last_no_assert_suspension_cause_);
     // Do instrumentation events after allowing thread suspension again.
     instrumentation::Instrumentation* instrumentation = Runtime::Current()->GetInstrumentation();
+    if (!is_deoptimization_) {
+      // The debugger may suspend this thread and walk its stack. Let's do this before popping
+      // instrumentation frames.
+      instrumentation->ExceptionCaughtEvent(self_, throw_location_, catch_method, handler_dex_pc_,
+                                            exception_);
+    }
     for (size_t i = 0; i < instrumentation_frames_to_pop_; ++i) {
       // We pop the instrumentation stack here so as not to corrupt it during the stack walk.
       if (i != instrumentation_frames_to_pop_ - 1 || self_->GetInstrumentationStack()->front().method_ != catch_method) {
@@ -1825,10 +1844,7 @@
         instrumentation->PopMethodForUnwind(self_, is_deoptimization_);
       }
     }
-    if (!is_deoptimization_) {
-      instrumentation->ExceptionCaughtEvent(self_, throw_location_, catch_method, handler_dex_pc_,
-                                            exception_);
-    } else {
+    if (is_deoptimization_) {
       // TODO: proper return value.
       self_->SetDeoptimizationShadowFrame(top_shadow_frame_);
     }
@@ -1984,11 +2000,7 @@
         // Portable path use DexGcMap and store in Method.native_gc_map_.
         const uint8_t* gc_map = m->GetNativeGcMap();
         CHECK(gc_map != NULL) << PrettyMethod(m);
-        uint32_t gc_map_length = static_cast<uint32_t>((gc_map[0] << 24) |
-                                                       (gc_map[1] << 16) |
-                                                       (gc_map[2] << 8) |
-                                                       (gc_map[3] << 0));
-        verifier::DexPcToReferenceMap dex_gc_map(gc_map + 4, gc_map_length);
+        verifier::DexPcToReferenceMap dex_gc_map(gc_map);
         uint32_t dex_pc = GetDexPc();
         const uint8_t* reg_bitmap = dex_gc_map.FindBitMap(dex_pc);
         DCHECK(reg_bitmap != NULL);
@@ -2112,12 +2124,11 @@
     opeer_ = visitor(opeer_, arg);
   }
   if (exception_ != nullptr) {
-    exception_ = reinterpret_cast<mirror::Throwable*>(visitor(exception_, arg));
+    exception_ = down_cast<mirror::Throwable*>(visitor(exception_, arg));
   }
   throw_location_.VisitRoots(visitor, arg);
   if (class_loader_override_ != nullptr) {
-    class_loader_override_ = reinterpret_cast<mirror::ClassLoader*>(
-        visitor(class_loader_override_, arg));
+    class_loader_override_ = down_cast<mirror::ClassLoader*>(visitor(class_loader_override_, arg));
   }
   jni_env_->locals.VisitRoots(visitor, arg);
   jni_env_->monitors.VisitRoots(visitor, arg);
@@ -2136,7 +2147,7 @@
       frame.this_object_ = visitor(frame.this_object_, arg);
     }
     DCHECK(frame.method_ != nullptr);
-    frame.method_ = reinterpret_cast<mirror::ArtMethod*>(visitor(frame.method_, arg));
+    frame.method_ = down_cast<mirror::ArtMethod*>(visitor(frame.method_, arg));
   }
 }
 
diff --git a/runtime/thread.h b/runtime/thread.h
index db2f7b4..44b2186 100644
--- a/runtime/thread.h
+++ b/runtime/thread.h
@@ -147,7 +147,8 @@
   }
 
   bool IsSuspended() const {
-    union StateAndFlags state_and_flags = state_and_flags_;
+    union StateAndFlags state_and_flags;
+    state_and_flags.as_int = state_and_flags_.as_int;
     return state_and_flags.as_struct.state != kRunnable &&
         (state_and_flags.as_struct.flags & kSuspendRequest) != 0;
   }
@@ -638,7 +639,8 @@
 
   // 32 bits of atomically changed state and flags. Keeping as 32 bits allows and atomic CAS to
   // change from being Suspended to Runnable without a suspend request occurring.
-  union StateAndFlags {
+  union PACKED(4) StateAndFlags {
+    StateAndFlags() {}
     struct PACKED(4) {
       // Bitfield of flag values. Must be changed atomically so that flag values aren't lost. See
       // ThreadFlags for bit field meanings.
@@ -650,6 +652,11 @@
       volatile uint16_t state;
     } as_struct;
     volatile int32_t as_int;
+
+   private:
+    // gcc does not handle struct with volatile member assignments correctly.
+    // See http://gcc.gnu.org/bugzilla/show_bug.cgi?id=47409
+    DISALLOW_COPY_AND_ASSIGN(StateAndFlags);
   };
   union StateAndFlags state_and_flags_;
   COMPILE_ASSERT(sizeof(union StateAndFlags) == sizeof(int32_t),
diff --git a/runtime/thread_list.cc b/runtime/thread_list.cc
index dd3f11c..aed8c77 100644
--- a/runtime/thread_list.cc
+++ b/runtime/thread_list.cc
@@ -162,6 +162,35 @@
 }
 #endif
 
+// Unlike suspending all threads where we can wait to acquire the mutator_lock_, suspending an
+// individual thread requires polling. delay_us is the requested sleep and total_delay_us
+// accumulates the total time spent sleeping for timeouts. The first sleep is just a yield,
+// subsequently sleeps increase delay_us from 1ms to 500ms by doubling.
+static void ThreadSuspendSleep(Thread* self, useconds_t* delay_us, useconds_t* total_delay_us,
+                               bool holding_locks) {
+  if (!holding_locks) {
+    for (int i = kLockLevelCount - 1; i >= 0; --i) {
+      BaseMutex* held_mutex = self->GetHeldMutex(static_cast<LockLevel>(i));
+      if (held_mutex != NULL) {
+        LOG(FATAL) << "Holding " << held_mutex->GetName() << " while sleeping for thread suspension";
+      }
+    }
+  }
+  useconds_t new_delay_us = (*delay_us) * 2;
+  CHECK_GE(new_delay_us, *delay_us);
+  if (new_delay_us < 500000) {  // Don't allow sleeping to be more than 0.5s.
+    *delay_us = new_delay_us;
+  }
+  if (*delay_us == 0) {
+    sched_yield();
+    // Default to 1 milliseconds (note that this gets multiplied by 2 before the first sleep).
+    *delay_us = 500;
+  } else {
+    usleep(*delay_us);
+    *total_delay_us += *delay_us;
+  }
+}
+
 size_t ThreadList::RunCheckpoint(Closure* checkpoint_function) {
   Thread* self = Thread::Current();
   if (kIsDebugBuild) {
@@ -208,17 +237,15 @@
   for (const auto& thread : suspended_count_modified_threads) {
     if (!thread->IsSuspended()) {
       // Wait until the thread is suspended.
-      uint64_t start = NanoTime();
+      useconds_t total_delay_us = 0;
       do {
-        // Sleep for 100us.
-        usleep(100);
+        useconds_t delay_us = 100;
+        ThreadSuspendSleep(self, &delay_us, &total_delay_us, true);
       } while (!thread->IsSuspended());
-      uint64_t end = NanoTime();
-      // Shouldn't need to wait for longer than 1 millisecond.
-      const uint64_t threshold = 1;
-      if (NsToMs(end - start) > threshold) {
-        LOG(INFO) << "Warning: waited longer than " << threshold
-                  << " ms for thread suspend\n";
+      // Shouldn't need to wait for longer than 1000 microseconds.
+      constexpr useconds_t kLongWaitThresholdUS = 1000;
+      if (UNLIKELY(total_delay_us > kLongWaitThresholdUS)) {
+        LOG(WARNING) << "Waited " << total_delay_us << " us for thread suspend!";
       }
     }
     // We know for sure that the thread is suspended at this point.
@@ -354,34 +381,6 @@
   }
 }
 
-// Unlike suspending all threads where we can wait to acquire the mutator_lock_, suspending an
-// individual thread requires polling. delay_us is the requested sleep and total_delay_us
-// accumulates the total time spent sleeping for timeouts. The first sleep is just a yield,
-// subsequently sleeps increase delay_us from 1ms to 500ms by doubling.
-static void ThreadSuspendSleep(Thread* self, useconds_t* delay_us, useconds_t* total_delay_us) {
-  for (int i = kLockLevelCount - 1; i >= 0; --i) {
-    BaseMutex* held_mutex = self->GetHeldMutex(static_cast<LockLevel>(i));
-    if (held_mutex != NULL) {
-      LOG(FATAL) << "Holding " << held_mutex->GetName() << " while sleeping for thread suspension";
-    }
-  }
-  {
-    useconds_t new_delay_us = (*delay_us) * 2;
-    CHECK_GE(new_delay_us, *delay_us);
-    if (new_delay_us < 500000) {  // Don't allow sleeping to be more than 0.5s.
-      *delay_us = new_delay_us;
-    }
-  }
-  if ((*delay_us) == 0) {
-    sched_yield();
-    // Default to 1 milliseconds (note that this gets multiplied by 2 before the first sleep).
-    (*delay_us) = 500;
-  } else {
-    usleep(*delay_us);
-    (*total_delay_us) += (*delay_us);
-  }
-}
-
 Thread* ThreadList::SuspendThreadByPeer(jobject peer, bool request_suspension,
                                         bool debug_suspension, bool* timed_out) {
   static const useconds_t kTimeoutUs = 30 * 1000000;  // 30s.
@@ -432,7 +431,7 @@
       }
       // Release locks and come out of runnable state.
     }
-    ThreadSuspendSleep(self, &delay_us, &total_delay_us);
+    ThreadSuspendSleep(self, &delay_us, &total_delay_us, false);
   }
 }
 
@@ -445,13 +444,13 @@
   static const useconds_t kTimeoutUs = 30 * 1000000;  // 30s.
   useconds_t total_delay_us = 0;
   useconds_t delay_us = 0;
-  bool did_suspend_request = false;
   *timed_out = false;
+  Thread* suspended_thread = nullptr;
   Thread* self = Thread::Current();
   CHECK_NE(thread_id, kInvalidThreadId);
   while (true) {
-    Thread* thread = NULL;
     {
+      Thread* thread = NULL;
       ScopedObjectAccess soa(self);
       MutexLock mu(self, *Locks::thread_list_lock_);
       for (const auto& it : list_) {
@@ -460,17 +459,20 @@
           break;
         }
       }
-      if (thread == NULL) {
+      if (thread == nullptr) {
+        CHECK(suspended_thread == nullptr) << "Suspended thread " << suspended_thread
+            << " no longer in thread list";
         // There's a race in inflating a lock and the owner giving up ownership and then dying.
         ThreadSuspendByThreadIdWarning(WARNING, "No such thread id for suspend", thread_id);
         return NULL;
       }
       {
         MutexLock mu(self, *Locks::thread_suspend_count_lock_);
-        if (!did_suspend_request) {
+        if (suspended_thread == nullptr) {
           thread->ModifySuspendCount(self, +1, debug_suspension);
-          did_suspend_request = true;
+          suspended_thread = thread;
         } else {
+          CHECK_EQ(suspended_thread, thread);
           // If the caller isn't requesting suspension, a suspension should have already occurred.
           CHECK_GT(thread->GetSuspendCount(), 0);
         }
@@ -487,7 +489,7 @@
         }
         if (total_delay_us >= kTimeoutUs) {
           ThreadSuspendByThreadIdWarning(WARNING, "Thread suspension timed out", thread_id);
-          if (did_suspend_request) {
+          if (suspended_thread != nullptr) {
             thread->ModifySuspendCount(soa.Self(), -1, debug_suspension);
           }
           *timed_out = true;
@@ -496,7 +498,7 @@
       }
       // Release locks and come out of runnable state.
     }
-    ThreadSuspendSleep(self, &delay_us, &total_delay_us);
+    ThreadSuspendSleep(self, &delay_us, &total_delay_us, false);
   }
 }
 
@@ -719,9 +721,7 @@
   self->Destroy();
 
   uint32_t thin_lock_id = self->thin_lock_thread_id_;
-  self->thin_lock_thread_id_ = 0;
-  ReleaseThreadId(self, thin_lock_id);
-  while (self != NULL) {
+  while (self != nullptr) {
     // Remove and delete the Thread* while holding the thread_list_lock_ and
     // thread_suspend_count_lock_ so that the unregistering thread cannot be suspended.
     // Note: deliberately not using MutexLock that could hold a stale self pointer.
@@ -732,10 +732,14 @@
     if (!self->IsSuspended()) {
       list_.remove(self);
       delete self;
-      self = NULL;
+      self = nullptr;
     }
     Locks::thread_list_lock_->ExclusiveUnlock(self);
   }
+  // Release the thread ID after the thread is finished and deleted to avoid cases where we can
+  // temporarily have multiple threads with the same thread id. When this occurs, it causes
+  // problems in FindThreadByThreadId / SuspendThreadByThreadId.
+  ReleaseThreadId(nullptr, thin_lock_id);
 
   // Clear the TLS data, so that the underlying native thread is recognizably detached.
   // (It may wish to reattach later.)
diff --git a/runtime/throw_location.cc b/runtime/throw_location.cc
index 01497ef..1cc3e74 100644
--- a/runtime/throw_location.cc
+++ b/runtime/throw_location.cc
@@ -25,7 +25,7 @@
 namespace art {
 
 std::string ThrowLocation::Dump() const {
-  if (method_ != NULL) {
+  if (method_ != nullptr) {
     return StringPrintf("%s:%d", PrettyMethod(method_).c_str(),
                         MethodHelper(method_).GetLineNumFromDexPC(dex_pc_));
   } else {
@@ -35,12 +35,11 @@
 
 void ThrowLocation::VisitRoots(RootVisitor* visitor, void* arg) {
   if (this_object_ != nullptr) {
-    this_object_ = const_cast<mirror::Object*>(visitor(this_object_, arg));
+    this_object_ = visitor(this_object_, arg);
     DCHECK(this_object_ != nullptr);
   }
   if (method_ != nullptr) {
-    method_ = const_cast<mirror::ArtMethod*>(
-        reinterpret_cast<const mirror::ArtMethod*>(visitor(method_, arg)));
+    method_ = down_cast<mirror::ArtMethod*>(visitor(method_, arg));
     DCHECK(method_ != nullptr);
   }
 }
diff --git a/runtime/verifier/dex_gc_map.h b/runtime/verifier/dex_gc_map.h
index 2a95ba2..4570ae8 100644
--- a/runtime/verifier/dex_gc_map.h
+++ b/runtime/verifier/dex_gc_map.h
@@ -38,11 +38,13 @@
 // Lightweight wrapper for Dex PC to reference bit maps.
 class DexPcToReferenceMap {
  public:
-  DexPcToReferenceMap(const uint8_t* data, size_t data_length) : data_(data) {
+  explicit DexPcToReferenceMap(const uint8_t* data) : data_(data) {
     CHECK(data_ != NULL);
-    // Check the size of the table agrees with the number of entries
-    size_t data_size = data_length - 4;
-    DCHECK_EQ(EntryWidth() * NumEntries(), data_size);
+  }
+
+  // The total size of the reference bit map including header.
+  size_t RawSize() const {
+    return EntryWidth() * NumEntries() + 4u /* header */;
   }
 
   // The number of entries in the table
diff --git a/runtime/verifier/method_verifier.cc b/runtime/verifier/method_verifier.cc
index 1e45c60..9183b5f 100644
--- a/runtime/verifier/method_verifier.cc
+++ b/runtime/verifier/method_verifier.cc
@@ -319,10 +319,12 @@
       allow_soft_failures_(allow_soft_failures),
       has_check_casts_(false),
       has_virtual_or_interface_invokes_(false) {
+  Runtime::Current()->AddMethodVerifier(this);
   DCHECK(class_def != nullptr);
 }
 
 MethodVerifier::~MethodVerifier() {
+  Runtime::Current()->RemoveMethodVerifier(this);
   STLDeleteElements(&failure_messages_);
 }
 
@@ -1068,13 +1070,13 @@
     bool compile = IsCandidateForCompilation(ref, method_access_flags_);
     if (compile) {
       /* Generate a register map and add it to the method. */
-      const std::vector<uint8_t>* dex_gc_map = GenerateLengthPrefixedGcMap();
+      const std::vector<uint8_t>* dex_gc_map = GenerateGcMap();
       if (dex_gc_map == NULL) {
         DCHECK_NE(failures_.size(), 0U);
         return false;  // Not a real failure, but a failure to encode
       }
       if (kIsDebugBuild) {
-        VerifyLengthPrefixedGcMap(*dex_gc_map);
+        VerifyGcMap(*dex_gc_map);
       }
       verifier::MethodVerifier::SetDexGcMap(ref, dex_gc_map);
     }
@@ -4054,7 +4056,7 @@
   return pc_to_concrete_method_map.release();
 }
 
-const std::vector<uint8_t>* MethodVerifier::GenerateLengthPrefixedGcMap() {
+const std::vector<uint8_t>* MethodVerifier::GenerateGcMap() {
   size_t num_entries, ref_bitmap_bits, pc_bits;
   ComputeGcMapSizes(&num_entries, &ref_bitmap_bits, &pc_bits);
   // There's a single byte to encode the size of each bitmap
@@ -4092,12 +4094,7 @@
     Fail(VERIFY_ERROR_BAD_CLASS_HARD) << "Failed to encode GC map (size=" << table_size << ")";
     return NULL;
   }
-  table->reserve(table_size + 4);  // table_size plus the length prefix
-  // Write table size
-  table->push_back((table_size & 0xff000000) >> 24);
-  table->push_back((table_size & 0x00ff0000) >> 16);
-  table->push_back((table_size & 0x0000ff00) >> 8);
-  table->push_back((table_size & 0x000000ff) >> 0);
+  table->reserve(table_size);
   // Write table header
   table->push_back(format | ((ref_bitmap_bytes >> DexPcToReferenceMap::kRegMapFormatShift) &
                              ~DexPcToReferenceMap::kRegMapFormatMask));
@@ -4115,18 +4112,15 @@
       line->WriteReferenceBitMap(*table, ref_bitmap_bytes);
     }
   }
-  DCHECK_EQ(table->size(), table_size + 4);  // table_size plus the length prefix
+  DCHECK_EQ(table->size(), table_size);
   return table;
 }
 
-void MethodVerifier::VerifyLengthPrefixedGcMap(const std::vector<uint8_t>& data) {
+void MethodVerifier::VerifyGcMap(const std::vector<uint8_t>& data) {
   // Check that for every GC point there is a map entry, there aren't entries for non-GC points,
   // that the table data is well formed and all references are marked (or not) in the bitmap
-  DCHECK_GE(data.size(), 4u);
-  size_t table_size = data.size() - 4u;
-  DCHECK_EQ(table_size, static_cast<size_t>((data[0] << 24) | (data[1] << 16) |
-                                            (data[2] << 8) | (data[3] << 0)));
-  DexPcToReferenceMap map(&data[4], table_size);
+  DexPcToReferenceMap map(&data[0]);
+  DCHECK_EQ(data.size(), map.RawSize());
   size_t map_index = 0;
   for (size_t i = 0; i < code_item_->insns_size_in_code_units_; i++) {
     const uint8_t* reg_bitmap = map.FindBitMap(i, false);
@@ -4393,5 +4387,9 @@
   return (rejected_classes_->find(ref) != rejected_classes_->end());
 }
 
+void MethodVerifier::VisitRoots(RootVisitor* visitor, void* arg) {
+  reg_types_.VisitRoots(visitor, arg);
+}
+
 }  // namespace verifier
 }  // namespace art
diff --git a/runtime/verifier/method_verifier.h b/runtime/verifier/method_verifier.h
index f72898e..dffda96 100644
--- a/runtime/verifier/method_verifier.h
+++ b/runtime/verifier/method_verifier.h
@@ -212,6 +212,8 @@
   static void Init() SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
   static void Shutdown();
 
+  static void AddRejectedClass(ClassReference ref)
+      LOCKS_EXCLUDED(rejected_classes_lock_);
   static bool IsClassRejected(ClassReference ref)
       LOCKS_EXCLUDED(rejected_classes_lock_);
 
@@ -237,6 +239,8 @@
   static bool IsCandidateForCompilation(MethodReference& method_ref,
                                         const uint32_t access_flags);
 
+  void VisitRoots(RootVisitor* visitor, void* arg) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
+
  private:
   // Adds the given string to the beginning of the last failure message.
   void PrependToLastFailMessage(std::string);
@@ -614,10 +618,10 @@
    * encode it in some clever fashion.
    * Returns a pointer to a newly-allocated RegisterMap, or NULL on failure.
    */
-  const std::vector<uint8_t>* GenerateLengthPrefixedGcMap();
+  const std::vector<uint8_t>* GenerateGcMap();
 
   // Verify that the GC map associated with method_ is well formed
-  void VerifyLengthPrefixedGcMap(const std::vector<uint8_t>& data);
+  void VerifyGcMap(const std::vector<uint8_t>& data);
 
   // Compute sizes for GC map data
   void ComputeGcMapSizes(size_t* gc_points, size_t* ref_bitmap_bits, size_t* log2_max_gc_pc);
@@ -660,9 +664,6 @@
   static ReaderWriterMutex* rejected_classes_lock_ DEFAULT_MUTEX_ACQUIRED_AFTER;
   static RejectedClassesTable* rejected_classes_ GUARDED_BY(rejected_classes_lock_);
 
-  static void AddRejectedClass(ClassReference ref)
-      LOCKS_EXCLUDED(rejected_classes_lock_);
-
   RegTypeCache reg_types_;
 
   PcToRegisterLineTable reg_table_;
diff --git a/runtime/verifier/reg_type.cc b/runtime/verifier/reg_type.cc
index d82e75d..f394bce 100644
--- a/runtime/verifier/reg_type.cc
+++ b/runtime/verifier/reg_type.cc
@@ -969,6 +969,12 @@
   }
 }
 
+void RegType::VisitRoots(RootVisitor* visitor, void* arg) {
+  if (klass_ != nullptr) {
+    klass_ = down_cast<mirror::Class*>(visitor(klass_, arg));
+  }
+}
+
 void UninitializedThisReferenceType::CheckInvariants() const {
   CHECK_EQ(GetAllocationPc(), 0U) << *this;
 }
diff --git a/runtime/verifier/reg_type.h b/runtime/verifier/reg_type.h
index f371733..8df481f 100644
--- a/runtime/verifier/reg_type.h
+++ b/runtime/verifier/reg_type.h
@@ -20,6 +20,7 @@
 #include "base/macros.h"
 #include "globals.h"
 #include "primitive.h"
+#include "root_visitor.h"
 
 #include "jni.h"
 
@@ -269,6 +270,8 @@
 
   virtual ~RegType() {}
 
+  void VisitRoots(RootVisitor* visitor, void* arg) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
+
  protected:
   RegType(mirror::Class* klass, const std::string& descriptor, uint16_t cache_id)
       SHARED_LOCKS_REQUIRED(Locks::mutator_lock_)
@@ -282,7 +285,7 @@
 
 
   const std::string descriptor_;
-  mirror::Class* const klass_;
+  mirror::Class* klass_;
   const uint16_t cache_id_;
 
   friend class RegTypeCache;
diff --git a/runtime/verifier/reg_type_cache.cc b/runtime/verifier/reg_type_cache.cc
index 9c9673a..3d24414 100644
--- a/runtime/verifier/reg_type_cache.cc
+++ b/runtime/verifier/reg_type_cache.cc
@@ -554,5 +554,11 @@
   }
 }
 
+void RegTypeCache::VisitRoots(RootVisitor* visitor, void* arg) {
+  for (RegType* entry : entries_) {
+    entry->VisitRoots(visitor, arg);
+  }
+}
+
 }  // namespace verifier
 }  // namespace art
diff --git a/runtime/verifier/reg_type_cache.h b/runtime/verifier/reg_type_cache.h
index a9f8bff..a811696 100644
--- a/runtime/verifier/reg_type_cache.h
+++ b/runtime/verifier/reg_type_cache.h
@@ -21,6 +21,7 @@
 #include "base/macros.h"
 #include "base/stl_util.h"
 #include "reg_type.h"
+#include "root_visitor.h"
 #include "runtime.h"
 
 #include <stdint.h>
@@ -139,6 +140,8 @@
   void Dump(std::ostream& os) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
   const RegType& RegTypeFromPrimitiveType(Primitive::Type) const;
 
+  void VisitRoots(RootVisitor* visitor, void* arg) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
+
  private:
   void FillPrimitiveAndSmallConstantTypes() SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
   mirror::Class* ResolveClass(const char* descriptor, mirror::ClassLoader* loader)
diff --git a/runtime/zip_archive.cc b/runtime/zip_archive.cc
index db273ec..8cb1993 100644
--- a/runtime/zip_archive.cc
+++ b/runtime/zip_archive.cc
@@ -30,272 +30,23 @@
 
 namespace art {
 
-static const size_t kBufSize = 32 * KB;
-
-// Get 2 little-endian bytes.
-static uint32_t Le16ToHost(const byte* src) {
-  return ((src[0] <<  0) |
-          (src[1] <<  8));
-}
-
-// Get 4 little-endian bytes.
-static uint32_t Le32ToHost(const byte* src) {
-  return ((src[0] <<  0) |
-          (src[1] <<  8) |
-          (src[2] << 16) |
-          (src[3] << 24));
-}
-
-uint16_t ZipEntry::GetCompressionMethod() {
-  return Le16ToHost(ptr_ + ZipArchive::kCDEMethod);
-}
-
-uint32_t ZipEntry::GetCompressedLength() {
-  return Le32ToHost(ptr_ + ZipArchive::kCDECompLen);
-}
-
 uint32_t ZipEntry::GetUncompressedLength() {
-  return Le32ToHost(ptr_ + ZipArchive::kCDEUncompLen);
+  return zip_entry_->uncompressed_length;
 }
 
 uint32_t ZipEntry::GetCrc32() {
-  return Le32ToHost(ptr_ + ZipArchive::kCDECRC);
+  return zip_entry_->crc32;
 }
 
-off64_t ZipEntry::GetDataOffset() {
-  // All we have is the offset to the Local File Header, which is
-  // variable size, so we have to read the contents of the struct to
-  // figure out where the actual data starts.
-
-  // We also need to make sure that the lengths are not so large that
-  // somebody trying to map the compressed or uncompressed data runs
-  // off the end of the mapped region.
-
-  off64_t dir_offset = zip_archive_->dir_offset_;
-  int64_t lfh_offset = Le32ToHost(ptr_ + ZipArchive::kCDELocalOffset);
-  if (lfh_offset + ZipArchive::kLFHLen >= dir_offset) {
-    LOG(WARNING) << "Zip: bad LFH offset in zip";
-    return -1;
-  }
-
-  if (lseek64(zip_archive_->fd_, lfh_offset, SEEK_SET) != lfh_offset) {
-    PLOG(WARNING) << "Zip: failed seeking to LFH at offset " << lfh_offset;
-    return -1;
-  }
-
-  uint8_t lfh_buf[ZipArchive::kLFHLen];
-  ssize_t actual = TEMP_FAILURE_RETRY(read(zip_archive_->fd_, lfh_buf, sizeof(lfh_buf)));
-  if (actual != sizeof(lfh_buf)) {
-    LOG(WARNING) << "Zip: failed reading LFH from offset " << lfh_offset;
-    return -1;
-  }
-
-  if (Le32ToHost(lfh_buf) != ZipArchive::kLFHSignature) {
-    LOG(WARNING) << "Zip: didn't find signature at start of LFH, offset " << lfh_offset;
-    return -1;
-  }
-
-  uint32_t gpbf = Le16ToHost(lfh_buf + ZipArchive::kLFHGPBFlags);
-  if ((gpbf & ZipArchive::kGPFUnsupportedMask) != 0) {
-    LOG(WARNING) << "Invalid General Purpose Bit Flag: " << gpbf;
-    return -1;
-  }
-
-  off64_t data_offset = (lfh_offset + ZipArchive::kLFHLen
-                       + Le16ToHost(lfh_buf + ZipArchive::kLFHNameLen)
-                       + Le16ToHost(lfh_buf + ZipArchive::kLFHExtraLen));
-  if (data_offset >= dir_offset) {
-    LOG(WARNING) << "Zip: bad data offset " << data_offset << " in zip";
-    return -1;
-  }
-
-  // check lengths
-
-  if (static_cast<off64_t>(data_offset + GetCompressedLength()) > dir_offset) {
-    LOG(WARNING) << "Zip: bad compressed length in zip "
-                 << "(" << data_offset << " + " << GetCompressedLength()
-                 << " > " << dir_offset << ")";
-    return -1;
-  }
-
-  if (GetCompressionMethod() == kCompressStored
-      && static_cast<off64_t>(data_offset + GetUncompressedLength()) > dir_offset) {
-    LOG(WARNING) << "Zip: bad uncompressed length in zip "
-                 << "(" << data_offset << " + " << GetUncompressedLength()
-                 << " > " << dir_offset << ")";
-    return -1;
-  }
-
-  return data_offset;
-}
-
-static bool CopyFdToMemory(uint8_t* begin, size_t size, int in, size_t count) {
-  uint8_t* dst = begin;
-  std::vector<uint8_t> buf(kBufSize);
-  while (count != 0) {
-    size_t bytes_to_read = (count > kBufSize) ? kBufSize : count;
-    ssize_t actual = TEMP_FAILURE_RETRY(read(in, &buf[0], bytes_to_read));
-    if (actual != static_cast<ssize_t>(bytes_to_read)) {
-      PLOG(WARNING) << "Zip: short read";
-      return false;
-    }
-    memcpy(dst, &buf[0], bytes_to_read);
-    dst += bytes_to_read;
-    count -= bytes_to_read;
-  }
-  DCHECK_EQ(dst, begin + size);
-  return true;
-}
-
-class ZStream {
- public:
-  ZStream(byte* write_buf, size_t write_buf_size) {
-    // Initialize the zlib stream struct.
-    memset(&zstream_, 0, sizeof(zstream_));
-    zstream_.zalloc = Z_NULL;
-    zstream_.zfree = Z_NULL;
-    zstream_.opaque = Z_NULL;
-    zstream_.next_in = NULL;
-    zstream_.avail_in = 0;
-    zstream_.next_out = reinterpret_cast<Bytef*>(write_buf);
-    zstream_.avail_out = write_buf_size;
-    zstream_.data_type = Z_UNKNOWN;
-  }
-
-  z_stream& Get() {
-    return zstream_;
-  }
-
-  ~ZStream() {
-    inflateEnd(&zstream_);
-  }
- private:
-  z_stream zstream_;
-};
-
-static bool InflateToMemory(uint8_t* begin, size_t size,
-                            int in, size_t uncompressed_length, size_t compressed_length) {
-  uint8_t* dst = begin;
-  UniquePtr<uint8_t[]> read_buf(new uint8_t[kBufSize]);
-  UniquePtr<uint8_t[]> write_buf(new uint8_t[kBufSize]);
-  if (read_buf.get() == NULL || write_buf.get() == NULL) {
-    LOG(WARNING) << "Zip: failed to allocate buffer to inflate";
-    return false;
-  }
-
-  UniquePtr<ZStream> zstream(new ZStream(write_buf.get(), kBufSize));
-
-  // Use the undocumented "negative window bits" feature to tell zlib
-  // that there's no zlib header waiting for it.
-  int zerr = inflateInit2(&zstream->Get(), -MAX_WBITS);
-  if (zerr != Z_OK) {
-    if (zerr == Z_VERSION_ERROR) {
-      LOG(ERROR) << "Installed zlib is not compatible with linked version (" << ZLIB_VERSION << ")";
-    } else {
-      LOG(WARNING) << "Call to inflateInit2 failed (zerr=" << zerr << ")";
-    }
-    return false;
-  }
-
-  size_t remaining = compressed_length;
-  do {
-    // read as much as we can
-    if (zstream->Get().avail_in == 0) {
-      size_t bytes_to_read = (remaining > kBufSize) ? kBufSize : remaining;
-
-        ssize_t actual = TEMP_FAILURE_RETRY(read(in, read_buf.get(), bytes_to_read));
-        if (actual != static_cast<ssize_t>(bytes_to_read)) {
-          LOG(WARNING) << "Zip: inflate read failed (" << actual << " vs " << bytes_to_read << ")";
-          return false;
-        }
-        remaining -= bytes_to_read;
-        zstream->Get().next_in = read_buf.get();
-        zstream->Get().avail_in = bytes_to_read;
-    }
-
-    // uncompress the data
-    zerr = inflate(&zstream->Get(), Z_NO_FLUSH);
-    if (zerr != Z_OK && zerr != Z_STREAM_END) {
-      LOG(WARNING) << "Zip: inflate zerr=" << zerr
-                   << " (next_in=" << zstream->Get().next_in
-                   << " avail_in=" << zstream->Get().avail_in
-                   << " next_out=" << zstream->Get().next_out
-                   << " avail_out=" << zstream->Get().avail_out
-                   << ")";
-      return false;
-    }
-
-    // write when we're full or when we're done
-    if (zstream->Get().avail_out == 0 ||
-        (zerr == Z_STREAM_END && zstream->Get().avail_out != kBufSize)) {
-      size_t bytes_to_write = zstream->Get().next_out - write_buf.get();
-      memcpy(dst, write_buf.get(), bytes_to_write);
-      dst += bytes_to_write;
-      zstream->Get().next_out = write_buf.get();
-      zstream->Get().avail_out = kBufSize;
-    }
-  } while (zerr == Z_OK);
-
-  DCHECK_EQ(zerr, Z_STREAM_END);  // other errors should've been caught
-
-  // paranoia
-  if (zstream->Get().total_out != uncompressed_length) {
-    LOG(WARNING) << "Zip: size mismatch on inflated file ("
-                 << zstream->Get().total_out << " vs " << uncompressed_length << ")";
-    return false;
-  }
-
-  DCHECK_EQ(dst, begin + size);
-  return true;
-}
 
 bool ZipEntry::ExtractToFile(File& file, std::string* error_msg) {
-  uint32_t length = GetUncompressedLength();
-  int result = TEMP_FAILURE_RETRY(ftruncate(file.Fd(), length));
-  if (result == -1) {
-    *error_msg = StringPrintf("Zip: failed to ftruncate '%s' to length %ud", file.GetPath().c_str(),
-                              length);
+  const int32_t error = ExtractEntryToFile(handle_, zip_entry_, file.Fd());
+  if (error) {
+    *error_msg = std::string(ErrorCodeString(error));
     return false;
   }
 
-  UniquePtr<MemMap> map(MemMap::MapFile(length, PROT_READ | PROT_WRITE, MAP_SHARED, file.Fd(), 0,
-                                        file.GetPath().c_str(), error_msg));
-  if (map.get() == NULL) {
-    *error_msg = StringPrintf("Zip: failed to mmap space for '%s': %s", file.GetPath().c_str(),
-                              error_msg->c_str());
-    return false;
-  }
-
-  return ExtractToMemory(map->Begin(), map->Size(), error_msg);
-}
-
-bool ZipEntry::ExtractToMemory(uint8_t* begin, size_t size, std::string* error_msg) {
-  // If size is zero, data offset will be meaningless, so bail out early.
-  if (size == 0) {
-    return true;
-  }
-  off64_t data_offset = GetDataOffset();
-  if (data_offset == -1) {
-    *error_msg = StringPrintf("Zip: data_offset=%lld", data_offset);
-    return false;
-  }
-  if (lseek64(zip_archive_->fd_, data_offset, SEEK_SET) != data_offset) {
-    *error_msg = StringPrintf("Zip: lseek to data at %lld failed", data_offset);
-    return false;
-  }
-
-  // TODO: this doesn't verify the data's CRC, but probably should (especially
-  // for uncompressed data).
-  switch (GetCompressionMethod()) {
-    case kCompressStored:
-      return CopyFdToMemory(begin, size, zip_archive_->fd_, GetUncompressedLength());
-    case kCompressDeflated:
-      return InflateToMemory(begin, size, zip_archive_->fd_,
-                             GetUncompressedLength(), GetCompressedLength());
-    default:
-      *error_msg = StringPrintf("Zip: unknown compression method 0x%x", GetCompressionMethod());
-      return false;
-  }
+  return true;
 }
 
 MemMap* ZipEntry::ExtractToMemMap(const char* entry_filename, std::string* error_msg) {
@@ -303,18 +54,18 @@
   name += " extracted in memory from ";
   name += entry_filename;
   UniquePtr<MemMap> map(MemMap::MapAnonymous(name.c_str(),
-                                             NULL,
-                                             GetUncompressedLength(),
+                                             NULL, GetUncompressedLength(),
                                              PROT_READ | PROT_WRITE, error_msg));
   if (map.get() == nullptr) {
     DCHECK(!error_msg->empty());
-    return NULL;
+    return nullptr;
   }
 
-  bool success = ExtractToMemory(map->Begin(), map->Size(), error_msg);
-  if (!success) {
-    LOG(ERROR) << "Zip: Failed to extract '" << entry_filename << "' to memory";
-    return NULL;
+  const int32_t error = ExtractToMemory(handle_, zip_entry_,
+                                        map->Begin(), map->Size());
+  if (error) {
+    *error_msg = std::string(ErrorCodeString(error));
+    return nullptr;
   }
 
   return map.release();
@@ -336,238 +87,47 @@
 
 ZipArchive* ZipArchive::Open(const char* filename, std::string* error_msg) {
   DCHECK(filename != nullptr);
-  int fd = open(filename, O_RDONLY, 0);
-  if (fd == -1) {
-    *error_msg = StringPrintf("Zip: unable to open '%s': %s", filename, strerror(errno));
-    return NULL;
+
+  ZipArchiveHandle handle;
+  const int32_t error = OpenArchive(filename, &handle);
+  if (error) {
+    *error_msg = std::string(ErrorCodeString(error));
+    CloseArchive(handle);
+    return nullptr;
   }
-  return OpenFromFd(fd, filename, error_msg);
+
+  SetCloseOnExec(GetFileDescriptor(handle));
+  return new ZipArchive(handle);
 }
 
 ZipArchive* ZipArchive::OpenFromFd(int fd, const char* filename, std::string* error_msg) {
-  SetCloseOnExec(fd);
-  UniquePtr<ZipArchive> zip_archive(new ZipArchive(fd, filename));
-  CHECK(zip_archive.get() != nullptr);
-  if (!zip_archive->MapCentralDirectory(error_msg)) {
-      zip_archive->Close();
-      return NULL;
+  DCHECK(filename != nullptr);
+  DCHECK_GT(fd, 0);
+
+  ZipArchiveHandle handle;
+  const int32_t error = OpenArchiveFd(fd, filename, &handle);
+  if (error) {
+    *error_msg = std::string(ErrorCodeString(error));
+    CloseArchive(handle);
+    return nullptr;
   }
-  if (!zip_archive->Parse(error_msg)) {
-      zip_archive->Close();
-      return NULL;
-  }
-  return zip_archive.release();
+
+  SetCloseOnExec(GetFileDescriptor(handle));
+  return new ZipArchive(handle);
 }
 
-ZipEntry* ZipArchive::Find(const char* name) const {
-  DCHECK(name != NULL);
-  DirEntries::const_iterator it = dir_entries_.find(name);
-  if (it == dir_entries_.end()) {
-    return NULL;
-  }
-  return new ZipEntry(this, (*it).second);
-}
+ZipEntry* ZipArchive::Find(const char* name, std::string* error_msg) const {
+  DCHECK(name != nullptr);
 
-void ZipArchive::Close() {
-  if (fd_ != -1) {
-    close(fd_);
-  }
-  fd_ = -1;
-  num_entries_ = 0;
-  dir_offset_ = 0;
-}
-
-std::string ZipArchive::ErrorStringPrintf(const char* fmt, ...) {
-  va_list ap;
-  va_start(ap, fmt);
-  std::string result(StringPrintf("Zip '%s' : ", filename_.c_str()));
-  StringAppendV(&result, fmt, ap);
-  va_end(ap);
-  return result;
-}
-
-// Find the zip Central Directory and memory-map it.
-//
-// On success, returns true after populating fields from the EOCD area:
-//   num_entries_
-//   dir_offset_
-//   dir_map_
-bool ZipArchive::MapCentralDirectory(std::string* error_msg) {
-  /*
-   * Get and test file length.
-   */
-  off64_t file_length = lseek64(fd_, 0, SEEK_END);
-  if (file_length < kEOCDLen) {
-    *error_msg = ErrorStringPrintf("length %lld is too small to be zip", file_length);
-    return false;
+  // Resist the urge to delete the space. <: is a bigraph sequence.
+  UniquePtr< ::ZipEntry> zip_entry(new ::ZipEntry);
+  const int32_t error = FindEntry(handle_, name, zip_entry.get());
+  if (error) {
+    *error_msg = std::string(ErrorCodeString(error));
+    return nullptr;
   }
 
-  size_t read_amount = kMaxEOCDSearch;
-  if (file_length < off64_t(read_amount)) {
-    read_amount = file_length;
-  }
-
-  UniquePtr<uint8_t[]> scan_buf(new uint8_t[read_amount]);
-  CHECK(scan_buf.get() != nullptr);
-
-  /*
-   * Make sure this is a Zip archive.
-   */
-  if (lseek64(fd_, 0, SEEK_SET) != 0) {
-    *error_msg = ErrorStringPrintf("seek to start failed: %s", strerror(errno));
-    return false;
-  }
-
-  ssize_t actual = TEMP_FAILURE_RETRY(read(fd_, scan_buf.get(), sizeof(int32_t)));
-  if (actual != static_cast<ssize_t>(sizeof(int32_t))) {
-    *error_msg = ErrorStringPrintf("couldn\'t read first signature from zip archive: %s",
-                                   strerror(errno));
-    return false;
-  }
-
-  unsigned int header = Le32ToHost(scan_buf.get());
-  if (header != kLFHSignature) {
-    *error_msg = ErrorStringPrintf("not a zip archive (found 0x%x)", header);
-    return false;
-  }
-
-  // Perform the traditional EOCD snipe hunt.
-  //
-  // We're searching for the End of Central Directory magic number,
-  // which appears at the start of the EOCD block.  It's followed by
-  // 18 bytes of EOCD stuff and up to 64KB of archive comment.  We
-  // need to read the last part of the file into a buffer, dig through
-  // it to find the magic number, parse some values out, and use those
-  // to determine the extent of the CD.
-  //
-  // We start by pulling in the last part of the file.
-  off64_t search_start = file_length - read_amount;
-
-  if (lseek64(fd_, search_start, SEEK_SET) != search_start) {
-    *error_msg = ErrorStringPrintf("seek %lld failed: %s", search_start, strerror(errno));
-    return false;
-  }
-  actual = TEMP_FAILURE_RETRY(read(fd_, scan_buf.get(), read_amount));
-  if (actual != static_cast<ssize_t>(read_amount)) {
-    *error_msg = ErrorStringPrintf("read %lld, expected %zd. %s", search_start, read_amount,
-                                   strerror(errno));
-    return false;
-  }
-
-
-  // Scan backward for the EOCD magic.  In an archive without a trailing
-  // comment, we'll find it on the first try.  (We may want to consider
-  // doing an initial minimal read; if we don't find it, retry with a
-  // second read as above.)
-  int i;
-  for (i = read_amount - kEOCDLen; i >= 0; i--) {
-    if (scan_buf.get()[i] == 0x50 && Le32ToHost(&(scan_buf.get())[i]) == kEOCDSignature) {
-      break;
-    }
-  }
-  if (i < 0) {
-    *error_msg = ErrorStringPrintf("EOCD not found, not a zip file");
-    return false;
-  }
-
-  off64_t eocd_offset = search_start + i;
-  const byte* eocd_ptr = scan_buf.get() + i;
-
-  CHECK(eocd_offset < file_length);
-
-  // Grab the CD offset and size, and the number of entries in the
-  // archive.  Verify that they look reasonable.
-  uint16_t disk_number = Le16ToHost(eocd_ptr + kEOCDDiskNumber);
-  uint16_t disk_with_central_dir = Le16ToHost(eocd_ptr + kEOCDDiskNumberForCD);
-  uint16_t num_entries = Le16ToHost(eocd_ptr + kEOCDNumEntries);
-  uint16_t total_num_entries = Le16ToHost(eocd_ptr + kEOCDTotalNumEntries);
-  uint32_t dir_size = Le32ToHost(eocd_ptr + kEOCDSize);
-  uint32_t dir_offset = Le32ToHost(eocd_ptr + kEOCDFileOffset);
-  uint16_t comment_size = Le16ToHost(eocd_ptr + kEOCDCommentSize);
-
-  if ((uint64_t) dir_offset + (uint64_t) dir_size > (uint64_t) eocd_offset) {
-    *error_msg = ErrorStringPrintf("bad offsets (dir=%ud, size=%ud, eocd=%lld)",
-                                   dir_offset, dir_size, eocd_offset);
-    return false;
-  }
-  if (num_entries == 0) {
-    *error_msg = ErrorStringPrintf("empty archive?");
-    return false;
-  } else if (num_entries != total_num_entries || disk_number != 0 || disk_with_central_dir != 0) {
-    *error_msg = ErrorStringPrintf("spanned archives not supported");
-    return false;
-  }
-
-  // Check to see if comment is a sane size
-  if ((comment_size > (file_length - kEOCDLen))
-      || (eocd_offset > (file_length - kEOCDLen) - comment_size)) {
-    *error_msg = ErrorStringPrintf("comment size runs off end of file");
-    return false;
-  }
-
-  // It all looks good.  Create a mapping for the CD.
-  dir_map_.reset(MemMap::MapFile(dir_size, PROT_READ, MAP_SHARED, fd_, dir_offset,
-                                 filename_.c_str(), error_msg));
-  if (dir_map_.get() == NULL) {
-    return false;
-  }
-
-  num_entries_ = num_entries;
-  dir_offset_ = dir_offset;
-  return true;
-}
-
-bool ZipArchive::Parse(std::string* error_msg) {
-  const byte* cd_ptr = dir_map_->Begin();
-  size_t cd_length = dir_map_->Size();
-
-  // Walk through the central directory, adding entries to the hash
-  // table and verifying values.
-  const byte* ptr = cd_ptr;
-  for (int i = 0; i < num_entries_; i++) {
-    if (Le32ToHost(ptr) != kCDESignature) {
-      *error_msg = ErrorStringPrintf("missed a central dir sig (at %d)", i);
-      return false;
-    }
-    if (ptr + kCDELen > cd_ptr + cd_length) {
-      *error_msg = ErrorStringPrintf("ran off the end (at %d)", i);
-      return false;
-    }
-
-    int64_t local_hdr_offset = Le32ToHost(ptr + kCDELocalOffset);
-    if (local_hdr_offset >= dir_offset_) {
-      *error_msg = ErrorStringPrintf("bad LFH offset %lld at entry %d", local_hdr_offset, i);
-      return false;
-    }
-
-    uint16_t gpbf = Le16ToHost(ptr + kCDEGPBFlags);
-    if ((gpbf & kGPFUnsupportedMask) != 0) {
-      *error_msg = ErrorStringPrintf("invalid general purpose bit flag %x", gpbf);
-      return false;
-    }
-
-    uint16_t name_len = Le16ToHost(ptr + kCDENameLen);
-    uint16_t extra_len = Le16ToHost(ptr + kCDEExtraLen);
-    uint16_t comment_len = Le16ToHost(ptr + kCDECommentLen);
-
-    // add the CDE filename to the hash table
-    const char* name = reinterpret_cast<const char*>(ptr + kCDELen);
-
-    // Check name for NULL characters
-    if (memchr(name, 0, name_len) != NULL) {
-      *error_msg = ErrorStringPrintf("filename contains NUL byte");
-      return false;
-    }
-
-    dir_entries_.Put(StringPiece(name, name_len), ptr);
-    ptr += kCDELen + name_len + extra_len + comment_len;
-    if (ptr > cd_ptr + cd_length) {
-      *error_msg = ErrorStringPrintf("bad CD advance (%p vs %p) at entry %d",
-                                     ptr, cd_ptr + cd_length, i);
-      return false;
-    }
-  }
-  return true;
+  return new ZipEntry(handle_, zip_entry.release());
 }
 
 }  // namespace art
diff --git a/runtime/zip_archive.h b/runtime/zip_archive.h
index 8ff952b..1f48e0a 100644
--- a/runtime/zip_archive.h
+++ b/runtime/zip_archive.h
@@ -18,8 +18,8 @@
 #define ART_RUNTIME_ZIP_ARCHIVE_H_
 
 #include <stdint.h>
-#include <zlib.h>
 #include <string>
+#include <ziparchive/zip_archive.h>
 
 #include "base/logging.h"
 #include "base/stringpiece.h"
@@ -38,33 +38,17 @@
 class ZipEntry {
  public:
   bool ExtractToFile(File& file, std::string* error_msg);
-  bool ExtractToMemory(uint8_t* begin, size_t size, std::string* error_msg);
   MemMap* ExtractToMemMap(const char* entry_filename, std::string* error_msg);
 
   uint32_t GetUncompressedLength();
   uint32_t GetCrc32();
 
  private:
-  ZipEntry(const ZipArchive* zip_archive, const byte* ptr) : zip_archive_(zip_archive), ptr_(ptr) {}
+  ZipEntry(ZipArchiveHandle handle,
+           ::ZipEntry* zip_entry) : handle_(handle), zip_entry_(zip_entry) {}
 
-  // Zip compression methods
-  enum {
-    kCompressStored     = 0,        // no compression
-    kCompressDeflated   = 8,        // standard deflate
-  };
-
-  // kCompressStored, kCompressDeflated, ...
-  uint16_t GetCompressionMethod();
-
-  uint32_t GetCompressedLength();
-
-  // returns -1 on error
-  off64_t GetDataOffset();
-
-  const ZipArchive* zip_archive_;
-
-  // pointer to zip entry within central directory
-  const byte* ptr_;
+  ZipArchiveHandle handle_;
+  ::ZipEntry* const zip_entry_;
 
   friend class ZipArchive;
   DISALLOW_COPY_AND_ASSIGN(ZipEntry);
@@ -72,74 +56,23 @@
 
 class ZipArchive {
  public:
-  // Zip file constants.
-  static const uint32_t kEOCDSignature      = 0x06054b50;
-  static const int32_t kEOCDLen             = 22;
-  static const int32_t kEOCDDiskNumber      =  4;              // number of the current disk
-  static const int32_t kEOCDDiskNumberForCD =  6;              // disk number with the Central Directory
-  static const int32_t kEOCDNumEntries      =  8;              // offset to #of entries in file
-  static const int32_t kEOCDTotalNumEntries = 10;              // offset to total #of entries in spanned archives
-  static const int32_t kEOCDSize            = 12;              // size of the central directory
-  static const int32_t kEOCDFileOffset      = 16;              // offset to central directory
-  static const int32_t kEOCDCommentSize     = 20;              // offset to the length of the file comment
-
-  static const int32_t kMaxCommentLen = 65535;  // longest possible in uint16_t
-  static const int32_t kMaxEOCDSearch = (kMaxCommentLen + kEOCDLen);
-
-  static const uint32_t kLFHSignature = 0x04034b50;
-  static const int32_t kLFHLen        = 30;  // excluding variable-len fields
-  static const int32_t kLFHGPBFlags   = 6;   // offset to GPB flags
-  static const int32_t kLFHNameLen    = 26;  // offset to filename length
-  static const int32_t kLFHExtraLen   = 28;  // offset to extra length
-
-  static const uint32_t kCDESignature   = 0x02014b50;
-  static const int32_t kCDELen          = 46;  // excluding variable-len fields
-  static const int32_t kCDEGPBFlags     = 8;   // offset to GPB flags
-  static const int32_t kCDEMethod       = 10;  // offset to compression method
-  static const int32_t kCDEModWhen      = 12;  // offset to modification timestamp
-  static const int32_t kCDECRC          = 16;  // offset to entry CRC
-  static const int32_t kCDECompLen      = 20;  // offset to compressed length
-  static const int32_t kCDEUncompLen    = 24;  // offset to uncompressed length
-  static const int32_t kCDENameLen      = 28;  // offset to filename length
-  static const int32_t kCDEExtraLen     = 30;  // offset to extra length
-  static const int32_t kCDECommentLen   = 32;  // offset to comment length
-  static const int32_t kCDELocalOffset  = 42;  // offset to local hdr
-
-  // General Purpose Bit Flag
-  static const int32_t kGPFEncryptedFlag   = (1 << 0);
-  static const int32_t kGPFUnsupportedMask = (kGPFEncryptedFlag);
-
   // return new ZipArchive instance on success, NULL on error.
   static ZipArchive* Open(const char* filename, std::string* error_msg);
   static ZipArchive* OpenFromFd(int fd, const char* filename, std::string* error_msg);
 
-  ZipEntry* Find(const char* name) const;
+  ZipEntry* Find(const char* name, std::string* error_msg) const;
 
   ~ZipArchive() {
-    Close();
+    CloseArchive(handle_);
   }
 
  private:
-  explicit ZipArchive(int fd, const char* filename)
-      : fd_(fd), num_entries_(0), dir_offset_(0), filename_(filename) {}
-
-  bool MapCentralDirectory(std::string* error_msg);
-  bool Parse(std::string* error_msg);
-  void Close();
-  std::string ErrorStringPrintf(const char* fmt, ...)
-          __attribute__((__format__(__printf__, 2, 3))) COLD_ATTR;
-
-  int fd_;
-  uint16_t num_entries_;
-  off64_t dir_offset_;
-  UniquePtr<MemMap> dir_map_;
-  typedef SafeMap<StringPiece, const byte*> DirEntries;
-  DirEntries dir_entries_;
-  // Containing file for error reporting.
-  const std::string filename_;
+  explicit ZipArchive(ZipArchiveHandle handle) : handle_(handle) {}
 
   friend class ZipEntry;
 
+  ZipArchiveHandle handle_;
+
   DISALLOW_COPY_AND_ASSIGN(ZipArchive);
 };
 
diff --git a/runtime/zip_archive_test.cc b/runtime/zip_archive_test.cc
index 622dc89..16394b0 100644
--- a/runtime/zip_archive_test.cc
+++ b/runtime/zip_archive_test.cc
@@ -19,6 +19,7 @@
 #include <fcntl.h>
 #include <sys/stat.h>
 #include <sys/types.h>
+#include <zlib.h>
 
 #include "UniquePtr.h"
 #include "common_test.h"
@@ -33,8 +34,9 @@
   UniquePtr<ZipArchive> zip_archive(ZipArchive::Open(GetLibCoreDexFileName().c_str(), &error_msg));
   ASSERT_TRUE(zip_archive.get() != false) << error_msg;
   ASSERT_TRUE(error_msg.empty());
-  UniquePtr<ZipEntry> zip_entry(zip_archive->Find("classes.dex"));
+  UniquePtr<ZipEntry> zip_entry(zip_archive->Find("classes.dex", &error_msg));
   ASSERT_TRUE(zip_entry.get() != false);
+  ASSERT_TRUE(error_msg.empty());
 
   ScratchFile tmp;
   ASSERT_NE(-1, tmp.GetFd());
diff --git a/test/044-proxy/expected.txt b/test/044-proxy/expected.txt
index 13e3a28..12df250 100644
--- a/test/044-proxy/expected.txt
+++ b/test/044-proxy/expected.txt
@@ -42,6 +42,7 @@
  (no args)
 --- blob
 Success: method blob res=mix
+$Proxy1.getTrace null:-1
 Invoke public abstract void Shapes.upChuck()
  (no args)
 Got expected ioobe
@@ -49,8 +50,8 @@
  (no args)
 Got expected ie
 
-Proxy interfaces: [interface Quads, interface Colors]
-Proxy methods: [public final java.lang.String $Proxy1.blob(), public final double $Proxy1.blue(int), public final R0a $Proxy1.checkMe(), public final R0aa $Proxy1.checkMe(), public final R0base $Proxy1.checkMe(), public final void $Proxy1.circle(int), public final boolean $Proxy1.equals(java.lang.Object), public final int $Proxy1.green(double), public final int $Proxy1.hashCode(), public final int $Proxy1.mauve(java.lang.String), public final int $Proxy1.rectangle(int,int), public final int $Proxy1.red(float), public final int $Proxy1.square(int,int), public final java.lang.String $Proxy1.toString(), public final int $Proxy1.trapezoid(int,double,int), public final void $Proxy1.upCheck() throws java.lang.InterruptedException, public final void $Proxy1.upChuck()]
+Proxy interfaces: [interface Quads, interface Colors, interface Trace]
+Proxy methods: [public final java.lang.String $Proxy1.blob(), public final double $Proxy1.blue(int), public final R0a $Proxy1.checkMe(), public final R0aa $Proxy1.checkMe(), public final R0base $Proxy1.checkMe(), public final void $Proxy1.circle(int), public final boolean $Proxy1.equals(java.lang.Object), public final void $Proxy1.getTrace(), public final int $Proxy1.green(double), public final int $Proxy1.hashCode(), public final int $Proxy1.mauve(java.lang.String), public final int $Proxy1.rectangle(int,int), public final int $Proxy1.red(float), public final int $Proxy1.square(int,int), public final java.lang.String $Proxy1.toString(), public final int $Proxy1.trapezoid(int,double,int), public final void $Proxy1.upCheck() throws java.lang.InterruptedException, public final void $Proxy1.upChuck()]
 Decl annos: []
 Param annos (0) : []
 Dupe threw expected exception
diff --git a/test/044-proxy/src/BasicTest.java b/test/044-proxy/src/BasicTest.java
index 46aa3fe..ea46f49 100644
--- a/test/044-proxy/src/BasicTest.java
+++ b/test/044-proxy/src/BasicTest.java
@@ -51,6 +51,8 @@
         colors.blue(777);
         colors.mauve("sorry");
         colors.blob();
+        Trace trace = (Trace) proxy;
+        trace.getTrace();
 
         try {
             shapes.upChuck();
@@ -96,7 +98,7 @@
 
         /* create the proxy class */
         Class proxyClass = Proxy.getProxyClass(Shapes.class.getClassLoader(),
-                            new Class[] { Quads.class, Colors.class });
+                            new Class[] { Quads.class, Colors.class, Trace.class });
 
         /* create a proxy object, passing the handler object in */
         Object proxy = null;
@@ -156,6 +158,10 @@
     public R0aa checkMe();
 }
 
+interface Trace {
+    public void getTrace();
+}
+
 /*
  * Some return types.
  */
@@ -248,6 +254,20 @@
                 throw new RuntimeException("huh?");
         }
 
+        if (method.getDeclaringClass() == Trace.class) {
+          if (method.getName().equals("getTrace")) {
+            StackTraceElement[] stackTrace = Thread.currentThread().getStackTrace();
+            for (int i = 0; i < stackTrace.length; i++) {
+                StackTraceElement ste = stackTrace[i];
+                if (ste.getMethodName().equals("getTrace")) {
+                  System.out.println(ste.getClassName() + "." + ste.getMethodName() + " " +
+                                     ste.getFileName() + ":" + ste.getLineNumber());
+                }
+            }
+            return null;
+          }
+        }
+
         System.out.println("Invoke " + method);
         if (args == null || args.length == 0) {
             System.out.println(" (no args)");
diff --git a/test/JniTest/JniTest.java b/test/JniTest/JniTest.java
index a1b1f0c..9194da5 100644
--- a/test/JniTest/JniTest.java
+++ b/test/JniTest/JniTest.java
@@ -20,12 +20,24 @@
     public static void main(String[] args) {
         System.loadLibrary("arttest");
         testFindClassOnAttachedNativeThread();
+        testFindFieldOnAttachedNativeThread();
         testCallStaticVoidMethodOnSubClass();
         testGetMirandaMethod();
     }
 
     private static native void testFindClassOnAttachedNativeThread();
 
+    private static boolean testFindFieldOnAttachedNativeThreadField;
+
+    private static void testFindFieldOnAttachedNativeThread() {
+      testFindFieldOnAttachedNativeThreadNative();
+      if (!testFindFieldOnAttachedNativeThreadField) {
+            throw new AssertionError();
+        }
+    }
+
+    private static native void testFindFieldOnAttachedNativeThreadNative();
+
     private static void testCallStaticVoidMethodOnSubClass() {
         testCallStaticVoidMethodOnSubClassNative();
         if (!testCallStaticVoidMethodOnSubClass_SuperClass.executed) {
diff --git a/test/JniTest/jni_test.cc b/test/JniTest/jni_test.cc
index cfcbb64..d15e180 100644
--- a/test/JniTest/jni_test.cc
+++ b/test/JniTest/jni_test.cc
@@ -67,6 +67,42 @@
   assert(pthread_join_result == 0);
 }
 
+static void* testFindFieldOnAttachedNativeThread(void*) {
+  assert(jvm != NULL);
+
+  JNIEnv* env = NULL;
+  JavaVMAttachArgs args = { JNI_VERSION_1_6, __FUNCTION__, NULL };
+  int attach_result = jvm->AttachCurrentThread(&env, &args);
+  assert(attach_result == 0);
+
+  jclass clazz = env->FindClass("JniTest");
+  assert(clazz != NULL);
+  assert(!env->ExceptionCheck());
+
+  jfieldID field = env->GetStaticFieldID(clazz, "testFindFieldOnAttachedNativeThreadField", "Z");
+  assert(field != NULL);
+  assert(!env->ExceptionCheck());
+
+  env->SetStaticBooleanField(clazz, field, JNI_TRUE);
+
+  int detach_result = jvm->DetachCurrentThread();
+  assert(detach_result == 0);
+  return NULL;
+}
+
+extern "C" JNIEXPORT void JNICALL Java_JniTest_testFindFieldOnAttachedNativeThreadNative(JNIEnv*,
+                                                                                         jclass) {
+  pthread_t pthread;
+  int pthread_create_result = pthread_create(&pthread,
+                                             NULL,
+                                             testFindFieldOnAttachedNativeThread,
+                                             NULL);
+  assert(pthread_create_result == 0);
+  int pthread_join_result = pthread_join(pthread, NULL);
+  assert(pthread_join_result == 0);
+}
+
+
 // http://b/11243757
 extern "C" JNIEXPORT void JNICALL Java_JniTest_testCallStaticVoidMethodOnSubClassNative(JNIEnv* env,
                                                                                         jclass) {
diff --git a/test/ThreadStress/ThreadStress.java b/test/ThreadStress/ThreadStress.java
index 8d8135d..795c790 100644
--- a/test/ThreadStress/ThreadStress.java
+++ b/test/ThreadStress/ThreadStress.java
@@ -128,13 +128,13 @@
         Thread[] runners = new Thread[numberOfThreads];
         for (int r = 0; r < runners.length; r++) {
             final ThreadStress ts = threadStresses[r];
-            runners[r] = new Thread() {
+            runners[r] = new Thread("Runner thread " + r) {
                 final ThreadStress threadStress = ts;
                 public void run() {
                     int id = threadStress.id;
-                    System.out.println("Starting runner for " + id);
+                    System.out.println("Starting worker for " + id);
                     while (threadStress.nextOperation < operationsPerThread) {
-                        Thread thread = new Thread(ts);
+                        Thread thread = new Thread(ts, "Worker thread " + id);
                         thread.start();
                         try {
                             thread.join();
@@ -144,14 +144,14 @@
                                            + (operationsPerThread - threadStress.nextOperation)
                                            + " operations remaining.");
                     }
-                    System.out.println("Finishing runner for " + id);
+                    System.out.println("Finishing worker for " + id);
                 }
             };
         }
 
         // The notifier thread is a daemon just loops forever to wake
         // up threads in Operation.WAIT
-        Thread notifier = new Thread() {
+        Thread notifier = new Thread("Notifier") {
             public void run() {
                 while (true) {
                     synchronized (lock) {
diff --git a/tools/cpplint.py b/tools/cpplint.py
index 30b5216..c2f6514 100755
--- a/tools/cpplint.py
+++ b/tools/cpplint.py
@@ -1,4 +1,4 @@
-#!/usr/bin/python
+#!/usr/bin/env python
 #
 # Copyright (c) 2009 Google Inc. All rights reserved.
 #
diff --git a/tools/generate-operator-out.py b/tools/generate-operator-out.py
index 0c085fb..19266b4 100755
--- a/tools/generate-operator-out.py
+++ b/tools/generate-operator-out.py
@@ -1,4 +1,4 @@
-#!/usr/bin/python
+#!/usr/bin/env python
 #
 # Copyright (C) 2012 The Android Open Source Project
 #