Merge "ART: Bitvector extensions for dumping and size handling"
diff --git a/build/Android.gtest.mk b/build/Android.gtest.mk
index 4b655b5..12af0c4 100644
--- a/build/Android.gtest.mk
+++ b/build/Android.gtest.mk
@@ -17,6 +17,8 @@
 LOCAL_PATH := art
 
 RUNTIME_GTEST_COMMON_SRC_FILES := \
+	runtime/arch/arch_test.cc \
+	runtime/arch/stub_test.cc \
 	runtime/barrier_test.cc \
 	runtime/base/bit_field_test.cc \
 	runtime/base/bit_vector_test.cc \
diff --git a/compiler/common_compiler_test.h b/compiler/common_compiler_test.h
index fdf09a5..8bba84a 100644
--- a/compiler/common_compiler_test.h
+++ b/compiler/common_compiler_test.h
@@ -132,34 +132,24 @@
 
 class CommonCompilerTest : public CommonRuntimeTest {
  public:
-  static void MakeExecutable(const std::vector<uint8_t>& code) {
-    CHECK_NE(code.size(), 0U);
-    MakeExecutable(&code[0], code.size());
-  }
-
   // Create an OatMethod based on pointers (for unit tests).
   OatFile::OatMethod CreateOatMethod(const void* code,
                                      const size_t frame_size_in_bytes,
                                      const uint32_t core_spill_mask,
                                      const uint32_t fp_spill_mask,
-                                     const uint8_t* mapping_table,
-                                     const uint8_t* vmap_table,
                                      const uint8_t* gc_map) {
+    CHECK(code != nullptr);
     const byte* base;
-    uint32_t code_offset, mapping_table_offset, vmap_table_offset, gc_map_offset;
-    if (mapping_table == nullptr && vmap_table == nullptr && gc_map == nullptr) {
+    uint32_t code_offset, gc_map_offset;
+    if (gc_map == nullptr) {
       base = reinterpret_cast<const byte*>(code);  // Base of data points at code.
       base -= kPointerSize;  // Move backward so that code_offset != 0.
       code_offset = kPointerSize;
-      mapping_table_offset = 0;
-      vmap_table_offset = 0;
       gc_map_offset = 0;
     } else {
       // TODO: 64bit support.
       base = nullptr;  // Base of data in oat file, ie 0.
       code_offset = PointerToLowMemUInt32(code);
-      mapping_table_offset = PointerToLowMemUInt32(mapping_table);
-      vmap_table_offset = PointerToLowMemUInt32(vmap_table);
       gc_map_offset = PointerToLowMemUInt32(gc_map);
     }
     return OatFile::OatMethod(base,
@@ -167,8 +157,6 @@
                               frame_size_in_bytes,
                               core_spill_mask,
                               fp_spill_mask,
-                              mapping_table_offset,
-                              vmap_table_offset,
                               gc_map_offset);
   }
 
@@ -185,19 +173,44 @@
     }
     if (compiled_method != nullptr) {
       const std::vector<uint8_t>* code = compiled_method->GetQuickCode();
-      if (code == nullptr) {
+      const void* code_ptr;
+      if (code != nullptr) {
+        uint32_t code_size = code->size();
+        CHECK_NE(0u, code_size);
+        const std::vector<uint8_t>& vmap_table = compiled_method->GetVmapTable();
+        uint32_t vmap_table_offset = vmap_table.empty() ? 0u
+            : sizeof(OatMethodHeader) + vmap_table.size();
+        const std::vector<uint8_t>& mapping_table = compiled_method->GetMappingTable();
+        uint32_t mapping_table_offset = mapping_table.empty() ? 0u
+            : sizeof(OatMethodHeader) + vmap_table.size() + mapping_table.size();
+        OatMethodHeader method_header(vmap_table_offset, mapping_table_offset, code_size);
+
+        header_code_and_maps_chunks_.push_back(std::vector<uint8_t>());
+        std::vector<uint8_t>* chunk = &header_code_and_maps_chunks_.back();
+        size_t size = sizeof(method_header) + code_size + vmap_table.size() + mapping_table.size();
+        size_t code_offset = compiled_method->AlignCode(size - code_size);
+        size_t padding = code_offset - (size - code_size);
+        chunk->reserve(padding + size);
+        chunk->resize(sizeof(method_header));
+        memcpy(&(*chunk)[0], &method_header, sizeof(method_header));
+        chunk->insert(chunk->begin(), vmap_table.begin(), vmap_table.end());
+        chunk->insert(chunk->begin(), mapping_table.begin(), mapping_table.end());
+        chunk->insert(chunk->begin(), padding, 0);
+        chunk->insert(chunk->end(), code->begin(), code->end());
+        CHECK_EQ(padding + size, chunk->size());
+        code_ptr = &(*chunk)[code_offset];
+      } else {
         code = compiled_method->GetPortableCode();
+        code_ptr = &(*code)[0];
       }
-      MakeExecutable(*code);
-      const void* method_code = CompiledMethod::CodePointer(&(*code)[0],
+      MakeExecutable(code_ptr, code->size());
+      const void* method_code = CompiledMethod::CodePointer(code_ptr,
                                                             compiled_method->GetInstructionSet());
       LOG(INFO) << "MakeExecutable " << PrettyMethod(method) << " code=" << method_code;
       OatFile::OatMethod oat_method = CreateOatMethod(method_code,
                                                       compiled_method->GetFrameSizeInBytes(),
                                                       compiled_method->GetCoreSpillMask(),
                                                       compiled_method->GetFpSpillMask(),
-                                                      &compiled_method->GetMappingTable()[0],
-                                                      &compiled_method->GetVmapTable()[0],
                                                       nullptr);
       oat_method.LinkMethod(method);
       method->SetEntryPointFromInterpreter(artInterpreterToCompiledCodeBridge);
@@ -211,8 +224,6 @@
                                                         kStackAlignment,
                                                         0,
                                                         0,
-                                                        nullptr,
-                                                        nullptr,
                                                         nullptr);
         oat_method.LinkMethod(method);
         method->SetEntryPointFromInterpreter(interpreter::artInterpreterToInterpreterBridge);
@@ -230,8 +241,6 @@
                                                             sirt_size,
                                                         callee_save_method->GetCoreSpillMask(),
                                                         callee_save_method->GetFpSpillMask(),
-                                                        nullptr,
-                                                        nullptr,
                                                         nullptr);
         oat_method.LinkMethod(method);
         method->SetEntryPointFromInterpreter(artInterpreterToCompiledCodeBridge);
@@ -436,6 +445,9 @@
 
  private:
   UniquePtr<MemMap> image_reservation_;
+
+  // Chunks must not move their storage after being created - use the node-based std::list.
+  std::list<std::vector<uint8_t> > header_code_and_maps_chunks_;
 };
 
 }  // namespace art
diff --git a/compiler/dex/mir_optimization.cc b/compiler/dex/mir_optimization.cc
index 51419f4..937e258 100644
--- a/compiler/dex/mir_optimization.cc
+++ b/compiler/dex/mir_optimization.cc
@@ -42,6 +42,11 @@
   MIR* mir;
 
   for (mir = bb->first_mir_insn; mir != NULL; mir = mir->next) {
+    // Skip pass if BB has MIR without SSA representation.
+    if (mir->ssa_rep == NULL) {
+       return;
+    }
+
     uint64_t df_attributes = oat_data_flow_attributes_[mir->dalvikInsn.opcode];
 
     DecodedInstruction *d_insn = &mir->dalvikInsn;
diff --git a/compiler/dex/quick/gen_common.cc b/compiler/dex/quick/gen_common.cc
index aa9b2a4..313174d 100644
--- a/compiler/dex/quick/gen_common.cc
+++ b/compiler/dex/quick/gen_common.cc
@@ -19,12 +19,17 @@
 #include "dex/quick/mir_to_lir-inl.h"
 #include "entrypoints/quick/quick_entrypoints.h"
 #include "mirror/array.h"
+#include "mirror/object_array-inl.h"
 #include "mirror/object-inl.h"
 #include "verifier/method_verifier.h"
 #include <functional>
 
 namespace art {
 
+// Shortcuts to repeatedly used long types.
+typedef mirror::ObjectArray<mirror::Object> ObjArray;
+typedef mirror::ObjectArray<mirror::Class> ClassArray;
+
 /*
  * This source files contains "gen" codegen routines that should
  * be applicable to most targets.  Only mid-level support utilities
@@ -519,8 +524,8 @@
       r_base = TargetReg(kArg0);
       LockTemp(r_base);
       LoadRefDisp(r_method, mirror::ArtMethod::DexCacheResolvedTypesOffset().Int32Value(), r_base);
-      LoadRefDisp(r_base, mirror::Array::DataOffset(sizeof(mirror::Object*)).Int32Value() +
-                   sizeof(int32_t*) * field_info.StorageIndex(), r_base);
+      int32_t offset_of_field = ObjArray::OffsetOfElement(field_info.StorageIndex()).Int32Value();
+      LoadRefDisp(r_base, offset_of_field, r_base);
       // r_base now points at static storage (Class*) or NULL if the type is not yet resolved.
       if (!field_info.IsInitialized() &&
           (mir->optimization_flags & MIR_IGNORE_CLINIT_CHECK) == 0) {
@@ -608,8 +613,8 @@
       r_base = TargetReg(kArg0);
       LockTemp(r_base);
       LoadRefDisp(r_method, mirror::ArtMethod::DexCacheResolvedTypesOffset().Int32Value(), r_base);
-      LoadRefDisp(r_base, mirror::Array::DataOffset(sizeof(mirror::Object*)).Int32Value() +
-                  sizeof(int32_t*) * field_info.StorageIndex(), r_base);
+      int32_t offset_of_field = ObjArray::OffsetOfElement(field_info.StorageIndex()).Int32Value();
+      LoadRefDisp(r_base, offset_of_field, r_base);
       // r_base now points at static storage (Class*) or NULL if the type is not yet resolved.
       if (!field_info.IsInitialized() &&
           (mir->optimization_flags & MIR_IGNORE_CLINIT_CHECK) == 0) {
@@ -865,9 +870,7 @@
     int32_t dex_cache_offset =
         mirror::ArtMethod::DexCacheResolvedTypesOffset().Int32Value();
     Load32Disp(rl_method.reg, dex_cache_offset, res_reg);
-    int32_t offset_of_type =
-        mirror::Array::DataOffset(sizeof(mirror::Class*)).Int32Value() + (sizeof(mirror::Class*)
-                          * type_idx);
+    int32_t offset_of_type = ClassArray::OffsetOfElement(type_idx).Int32Value();
     Load32Disp(res_reg, offset_of_type, rl_result.reg);
     if (!cu_->compiler_driver->CanAssumeTypeIsPresentInDexCache(*cu_->dex_file,
         type_idx) || SLOW_TYPE_PATH) {
@@ -914,8 +917,8 @@
 
 void Mir2Lir::GenConstString(uint32_t string_idx, RegLocation rl_dest) {
   /* NOTE: Most strings should be available at compile time */
-  int32_t offset_of_string = mirror::Array::DataOffset(sizeof(mirror::String*)).Int32Value() +
-                 (sizeof(mirror::String*) * string_idx);
+  int32_t offset_of_string = mirror::ObjectArray<mirror::String>::OffsetOfElement(string_idx).
+                                                                                      Int32Value();
   if (!cu_->compiler_driver->CanAssumeStringIsPresentInDexCache(
       *cu_->dex_file, string_idx) || SLOW_STRING_PATH) {
     // slow path, resolve string if not in dex cache
@@ -1079,9 +1082,7 @@
     LoadRefDisp(check_class, mirror::ArtMethod::DexCacheResolvedTypesOffset().Int32Value(),
                 check_class);
     LoadRefDisp(object.reg,  mirror::Object::ClassOffset().Int32Value(), object_class);
-    int32_t offset_of_type =
-      mirror::Array::DataOffset(sizeof(mirror::Class*)).Int32Value() +
-      (sizeof(mirror::Class*) * type_idx);
+    int32_t offset_of_type = ClassArray::OffsetOfElement(type_idx).Int32Value();
     LoadRefDisp(check_class, offset_of_type, check_class);
   }
 
@@ -1139,9 +1140,7 @@
     LoadValueDirectFixed(rl_src, TargetReg(kArg0));  // kArg0 <= ref
     LoadRefDisp(TargetReg(kArg1), mirror::ArtMethod::DexCacheResolvedTypesOffset().Int32Value(),
                 class_reg);
-    int32_t offset_of_type =
-        mirror::Array::DataOffset(sizeof(mirror::Class*)).Int32Value() + (sizeof(mirror::Class*)
-        * type_idx);
+    int32_t offset_of_type = ClassArray::OffsetOfElement(type_idx).Int32Value();
     LoadRefDisp(class_reg, offset_of_type, class_reg);
     if (!can_assume_type_is_in_dex_cache) {
       // Need to test presence of type in dex cache at runtime
@@ -1275,9 +1274,7 @@
     // Load dex cache entry into class_reg (kArg2)
     LoadRefDisp(TargetReg(kArg1), mirror::ArtMethod::DexCacheResolvedTypesOffset().Int32Value(),
                 class_reg);
-    int32_t offset_of_type =
-        mirror::Array::DataOffset(sizeof(mirror::Class*)).Int32Value() +
-        (sizeof(mirror::Class*) * type_idx);
+    int32_t offset_of_type = ClassArray::OffsetOfElement(type_idx).Int32Value();
     LoadRefDisp(class_reg, offset_of_type, class_reg);
     if (!cu_->compiler_driver->CanAssumeTypeIsPresentInDexCache(*cu_->dex_file, type_idx)) {
       // Need to test presence of type in dex cache at runtime
diff --git a/compiler/image_writer.cc b/compiler/image_writer.cc
index 3400b01..c35d400 100644
--- a/compiler/image_writer.cc
+++ b/compiler/image_writer.cc
@@ -680,14 +680,6 @@
         copy->SetNativeMethod<kVerifyNone>(GetOatAddress(jni_dlsym_lookup_offset_));
       } else {
         // Normal (non-abstract non-native) methods have various tables to relocate.
-        uint32_t mapping_table_off = orig->GetOatMappingTableOffset();
-        const byte* mapping_table = GetOatAddress(mapping_table_off);
-        copy->SetMappingTable<kVerifyNone>(mapping_table);
-
-        uint32_t vmap_table_offset = orig->GetOatVmapTableOffset();
-        const byte* vmap_table = GetOatAddress(vmap_table_offset);
-        copy->SetVmapTable<kVerifyNone>(vmap_table);
-
         uint32_t native_gc_map_offset = orig->GetOatNativeGcMapOffset();
         const byte* native_gc_map = GetOatAddress(native_gc_map_offset);
         copy->SetNativeGcMap<kVerifyNone>(reinterpret_cast<const uint8_t*>(native_gc_map));
diff --git a/compiler/oat_test.cc b/compiler/oat_test.cc
index 766ef7b..b5d3923 100644
--- a/compiler/oat_test.cc
+++ b/compiler/oat_test.cc
@@ -176,7 +176,8 @@
   // If this test is failing and you have to update these constants,
   // it is time to update OatHeader::kOatVersion
   EXPECT_EQ(80U, sizeof(OatHeader));
-  EXPECT_EQ(28U, sizeof(OatMethodOffsets));
+  EXPECT_EQ(20U, sizeof(OatMethodOffsets));
+  EXPECT_EQ(12U, sizeof(OatMethodHeader));
 }
 
 TEST_F(OatTest, OatHeaderIsValid) {
diff --git a/compiler/oat_writer.cc b/compiler/oat_writer.cc
index 2114fe9..bbc9c3e 100644
--- a/compiler/oat_writer.cc
+++ b/compiler/oat_writer.cc
@@ -155,12 +155,15 @@
   }
 
   static uint32_t GetOffset(OatClass* oat_class, size_t method_offsets_index) ALWAYS_INLINE {
-    return oat_class->method_offsets_[method_offsets_index].mapping_table_offset_;
+    uint32_t offset = oat_class->method_headers_[method_offsets_index].mapping_table_offset_;
+    return offset == 0u ? 0u :
+        (oat_class->method_offsets_[method_offsets_index].code_offset_ & ~1) - offset;
   }
 
   static void SetOffset(OatClass* oat_class, size_t method_offsets_index, uint32_t offset)
       ALWAYS_INLINE {
-    oat_class->method_offsets_[method_offsets_index].mapping_table_offset_ = offset;
+    oat_class->method_headers_[method_offsets_index].mapping_table_offset_ =
+        (oat_class->method_offsets_[method_offsets_index].code_offset_ & ~1) - offset;
   }
 
   static const char* Name() ALWAYS_INLINE {
@@ -174,12 +177,15 @@
   }
 
   static uint32_t GetOffset(OatClass* oat_class, size_t method_offsets_index) ALWAYS_INLINE {
-    return oat_class->method_offsets_[method_offsets_index].vmap_table_offset_;
+    uint32_t offset = oat_class->method_headers_[method_offsets_index].vmap_table_offset_;
+    return offset == 0u ? 0u :
+        (oat_class->method_offsets_[method_offsets_index].code_offset_ & ~1) - offset;
   }
 
   static void SetOffset(OatClass* oat_class, size_t method_offsets_index, uint32_t offset)
       ALWAYS_INLINE {
-    oat_class->method_offsets_[method_offsets_index].vmap_table_offset_ = offset;
+    oat_class->method_headers_[method_offsets_index].vmap_table_offset_ =
+        (oat_class->method_offsets_[method_offsets_index].code_offset_ & ~1) - offset;
   }
 
   static const char* Name() ALWAYS_INLINE {
@@ -368,17 +374,22 @@
           }
         }
 
+        DCHECK_LT(method_offsets_index_, oat_class->method_headers_.size());
+        OatMethodHeader* method_header = &oat_class->method_headers_[method_offsets_index_];
+        method_header->code_size_ = code_size;
+
         // Deduplicate code arrays.
-        auto code_iter = dedupe_map_.find(quick_code);
+        auto code_iter = dedupe_map_.find(compiled_method);
         if (code_iter != dedupe_map_.end()) {
           quick_code_offset = code_iter->second;
+          FixupMethodHeader(method_header, quick_code_offset - thumb_offset);
         } else {
-          dedupe_map_.Put(quick_code, quick_code_offset);
-          OatMethodHeader method_header(code_size);
-          offset_ += sizeof(method_header);  // Method header is prepended before code.
-          writer_->oat_header_->UpdateChecksum(&method_header, sizeof(method_header));
-          offset_ += code_size;
+          dedupe_map_.Put(compiled_method, quick_code_offset);
+          FixupMethodHeader(method_header, quick_code_offset - thumb_offset);
+          writer_->oat_header_->UpdateChecksum(method_header, sizeof(*method_header));
+          offset_ += sizeof(*method_header);  // Method header is prepended before code.
           writer_->oat_header_->UpdateChecksum(&(*quick_code)[0], code_size);
+          offset_ += code_size;
         }
       }
       frame_size_in_bytes = compiled_method->GetFrameSizeInBytes();
@@ -420,9 +431,22 @@
   }
 
  private:
+  static void FixupMethodHeader(OatMethodHeader* method_header, uint32_t code_offset) {
+    // The code offset was 0 when the mapping/vmap table offset was set, so it's set
+    // to 0-offset and we need to adjust it by code_offset.
+    if (method_header->mapping_table_offset_ != 0u) {
+      method_header->mapping_table_offset_ += code_offset;
+      DCHECK_LT(method_header->mapping_table_offset_, code_offset);
+    }
+    if (method_header->vmap_table_offset_ != 0u) {
+      method_header->vmap_table_offset_ += code_offset;
+      DCHECK_LT(method_header->vmap_table_offset_, code_offset);
+    }
+  }
+
   // Deduplication is already done on a pointer basis by the compiler driver,
   // so we can simply compare the pointers to find out if things are duplicated.
-  SafeMap<const std::vector<uint8_t>*, uint32_t> dedupe_map_;
+  SafeMap<const CompiledMethod*, uint32_t, CodeOffsetsKeyComparator> dedupe_map_;
 };
 
 template <typename DataAccess>
@@ -477,7 +501,7 @@
     OatClass* oat_class = writer_->oat_classes_[oat_class_index_];
     CompiledMethod* compiled_method = oat_class->GetCompiledMethod(class_def_method_index);
 
-    OatMethodOffsets offsets(0u, kStackAlignment, 0u, 0u, 0u, 0u, 0u);
+    OatMethodOffsets offsets(0u, kStackAlignment, 0u, 0u, 0u);
     if (compiled_method != nullptr) {
       DCHECK_LT(method_offsets_index_, oat_class->method_offsets_.size());
       offsets = oat_class->method_offsets_[method_offsets_index_];
@@ -511,8 +535,6 @@
       offsets.frame_size_in_bytes_ = callee_save_method->GetFrameSizeInBytes() + sirt_size;
       offsets.core_spill_mask_ = callee_save_method->GetCoreSpillMask();
       offsets.fp_spill_mask_ = callee_save_method->GetFpSpillMask();
-      DCHECK_EQ(offsets.mapping_table_offset_, 0u);
-      DCHECK_EQ(offsets.vmap_table_offset_, 0u);
       DCHECK_EQ(offsets.gc_map_offset_, 0u);
     }
 
@@ -528,10 +550,8 @@
     method->SetFrameSizeInBytes(offsets.frame_size_in_bytes_);
     method->SetCoreSpillMask(offsets.core_spill_mask_);
     method->SetFpSpillMask(offsets.fp_spill_mask_);
-    method->SetOatMappingTableOffset(offsets.mapping_table_offset_);
     // Portable code offsets are set by ElfWriterMclinker::FixupCompiledCodeOffset after linking.
     method->SetQuickOatCodeOffset(offsets.code_offset_);
-    method->SetOatVmapTableOffset(offsets.vmap_table_offset_);
     method->SetOatNativeGcMapOffset(offsets.gc_map_offset_);
 
     return true;
@@ -584,7 +604,7 @@
                    offset_ + sizeof(OatMethodHeader) + compiled_method->CodeDelta())
             << PrettyMethod(it.GetMemberIndex(), *dex_file_);
         if (method_offsets.code_offset_ >= offset_) {
-          OatMethodHeader method_header(code_size);
+          const OatMethodHeader& method_header = oat_class->method_headers_[method_offsets_index_];
           if (!out->WriteFully(&method_header, sizeof(method_header))) {
             ReportWriteFailure("method header", it);
             return false;
@@ -1153,6 +1173,7 @@
 
   status_ = status;
   method_offsets_.resize(num_non_null_compiled_methods);
+  method_headers_.resize(num_non_null_compiled_methods);
 
   uint32_t oat_method_offsets_offset_from_oat_class = sizeof(type_) + sizeof(status_);
   if (type_ == kOatClassSomeCompiled) {
diff --git a/compiler/oat_writer.h b/compiler/oat_writer.h
index 1abacd8..7cdd532 100644
--- a/compiler/oat_writer.h
+++ b/compiler/oat_writer.h
@@ -225,12 +225,13 @@
     // not is kOatClassBitmap, the bitmap will be NULL.
     BitVector* method_bitmap_;
 
-    // OatMethodOffsets for each CompiledMethod present in the
-    // OatClass. Note that some may be missing if
+    // OatMethodOffsets and OatMethodHeaders for each CompiledMethod
+    // present in the OatClass. Note that some may be missing if
     // OatClass::compiled_methods_ contains NULL values (and
     // oat_method_offsets_offsets_from_oat_class_ should contain 0
     // values in this case).
     std::vector<OatMethodOffsets> method_offsets_;
+    std::vector<OatMethodHeader> method_headers_;
 
    private:
     DISALLOW_COPY_AND_ASSIGN(OatClass);
@@ -299,6 +300,22 @@
   uint32_t size_oat_class_method_bitmaps_;
   uint32_t size_oat_class_method_offsets_;
 
+  struct CodeOffsetsKeyComparator {
+    bool operator()(const CompiledMethod* lhs, const CompiledMethod* rhs) const {
+      if (lhs->GetQuickCode() != rhs->GetQuickCode()) {
+        return lhs->GetQuickCode() < rhs->GetQuickCode();
+      }
+      // If the code is the same, all other fields are likely to be the same as well.
+      if (UNLIKELY(&lhs->GetMappingTable() != &rhs->GetMappingTable())) {
+        return &lhs->GetMappingTable() < &rhs->GetMappingTable();
+      }
+      if (UNLIKELY(&lhs->GetVmapTable() != &rhs->GetVmapTable())) {
+        return &lhs->GetVmapTable() < &rhs->GetVmapTable();
+      }
+      return false;
+    }
+  };
+
   DISALLOW_COPY_AND_ASSIGN(OatWriter);
 };
 
diff --git a/compiler/utils/x86_64/assembler_x86_64.cc b/compiler/utils/x86_64/assembler_x86_64.cc
index 7d02c7c..9507e12 100644
--- a/compiler/utils/x86_64/assembler_x86_64.cc
+++ b/compiler/utils/x86_64/assembler_x86_64.cc
@@ -1493,7 +1493,7 @@
 }
 
 void X86_64Assembler::EmitOptionalRex32(CpuRegister reg) {
-  EmitOptionalRex(false, false, reg.NeedsRex(), false, false);
+  EmitOptionalRex(false, false, false, false, reg.NeedsRex());
 }
 
 void X86_64Assembler::EmitOptionalRex32(CpuRegister dst, CpuRegister src) {
@@ -1540,8 +1540,9 @@
 }
 
 void X86_64Assembler::EmitRex64(CpuRegister reg) {
-  EmitOptionalRex(false, true, reg.NeedsRex(), false, false);
+  EmitOptionalRex(false, true, false, false, reg.NeedsRex());
 }
+
 void X86_64Assembler::EmitRex64(CpuRegister dst, CpuRegister src) {
   EmitOptionalRex(false, true, dst.NeedsRex(), false, src.NeedsRex());
 }
diff --git a/dex2oat/dex2oat.cc b/dex2oat/dex2oat.cc
index ac76c35..d3e56da 100644
--- a/dex2oat/dex2oat.cc
+++ b/dex2oat/dex2oat.cc
@@ -110,7 +110,7 @@
   UsageError("      Example: --oat-file=/system/framework/boot.oat");
   UsageError("");
   UsageError("  --oat-fd=<number>: specifies the oat output destination via a file descriptor.");
-  UsageError("      Example: --oat-file=/system/framework/boot.oat");
+  UsageError("      Example: --oat-fd=6");
   UsageError("");
   UsageError("  --oat-location=<oat-name>: specifies a symbolic name for the file corresponding");
   UsageError("      to the file descriptor specified by --oat-fd.");
@@ -909,7 +909,6 @@
       profile_file = option.substr(strlen("--profile-file=")).data();
       VLOG(compiler) << "dex2oat: profile file is " << profile_file;
     } else if (option == "--no-profile-file") {
-      LOG(INFO) << "dex2oat: no profile file supplied (explictly)";
       // No profile
     } else if (option == "--print-pass-names") {
       PassDriver::PrintPassNames();
@@ -1079,7 +1078,7 @@
   }
 
   timings.StartSplit("dex2oat Setup");
-  LOG(INFO) << "dex2oat: " << CommandLine();
+  LOG(INFO) << CommandLine();
 
   Runtime::Options runtime_options;
   std::vector<const DexFile*> boot_class_path;
diff --git a/disassembler/disassembler_x86.cc b/disassembler/disassembler_x86.cc
index 68e77d4..5cc6acf 100644
--- a/disassembler/disassembler_x86.cc
+++ b/disassembler/disassembler_x86.cc
@@ -145,6 +145,9 @@
     }
   } while (have_prefixes);
   uint8_t rex = (supports_rex_ && (*instr >= 0x40) && (*instr <= 0x4F)) ? *instr : 0;
+  if (rex != 0) {
+    instr++;
+  }
   bool has_modrm = false;
   bool reg_is_opcode = false;
   size_t immediate_bytes = 0;
@@ -735,7 +738,7 @@
   std::ostringstream args;
   if (reg_in_opcode) {
     DCHECK(!has_modrm);
-    DumpReg(args, rex, *instr & 0x7, false, prefix[2], GPR);
+    DumpBaseReg(args, rex, *instr & 0x7);
   }
   instr++;
   uint32_t address_bits = 0;
@@ -746,14 +749,18 @@
     uint8_t reg_or_opcode = (modrm >> 3) & 7;
     uint8_t rm = modrm & 7;
     std::ostringstream address;
-    if (mod == 0 && rm == 5) {  // fixed address
-      address_bits = *reinterpret_cast<const uint32_t*>(instr);
-      address << StringPrintf("[0x%x]", address_bits);
+    if (mod == 0 && rm == 5) {
+      if (!supports_rex_) {  // Absolute address.
+        address_bits = *reinterpret_cast<const uint32_t*>(instr);
+        address << StringPrintf("[0x%x]", address_bits);
+      } else {  // 64-bit RIP relative addressing.
+        address << StringPrintf("[RIP + 0x%x]",  *reinterpret_cast<const uint32_t*>(instr));
+      }
       instr += 4;
     } else if (rm == 4 && mod != 3) {  // SIB
       uint8_t sib = *instr;
       instr++;
-      uint8_t ss = (sib >> 6) & 3;
+      uint8_t scale = (sib >> 6) & 3;
       uint8_t index = (sib >> 3) & 7;
       uint8_t base = sib & 7;
       address << "[";
@@ -765,11 +772,22 @@
       }
       if (index != 4) {
         DumpIndexReg(address, rex, index);
-        if (ss != 0) {
-          address << StringPrintf(" * %d", 1 << ss);
+        if (scale != 0) {
+          address << StringPrintf(" * %d", 1 << scale);
         }
       }
-      if (mod == 1) {
+      if (mod == 0) {
+        if (base == 5) {
+          if (index != 4) {
+            address << StringPrintf(" + %d", *reinterpret_cast<const int32_t*>(instr));
+          } else {
+            // 64-bit low 32-bit absolute address, redundant absolute address encoding on 32-bit.
+            address_bits = *reinterpret_cast<const uint32_t*>(instr);
+            address << StringPrintf("%d", address_bits);
+          }
+          instr += 4;
+        }
+      } else if (mod == 1) {
         address << StringPrintf(" + %d", *reinterpret_cast<const int8_t*>(instr));
         instr++;
       } else if (mod == 2) {
diff --git a/oatdump/oatdump.cc b/oatdump/oatdump.cc
index 5054f96..1a67952 100644
--- a/oatdump/oatdump.cc
+++ b/oatdump/oatdump.cc
@@ -44,6 +44,7 @@
 #include "mirror/object_array-inl.h"
 #include "noop_compiler_callbacks.h"
 #include "oat.h"
+#include "oat_file-inl.h"
 #include "object_utils.h"
 #include "os.h"
 #include "runtime.h"
diff --git a/runtime/Android.mk b/runtime/Android.mk
index d433fd5..bc971a9 100644
--- a/runtime/Android.mk
+++ b/runtime/Android.mk
@@ -36,10 +36,10 @@
 	base/unix_file/string_file.cc \
 	check_jni.cc \
 	catch_block_stack_visitor.cc \
-	catch_finder.cc \
 	class_linker.cc \
 	common_throws.cc \
 	debugger.cc \
+	deoptimize_stack_visitor.cc \
 	dex_file.cc \
 	dex_file_verifier.cc \
 	dex_instruction.cc \
@@ -129,6 +129,7 @@
 	os_linux.cc \
 	parsed_options.cc \
 	primitive.cc \
+	quick_exception_handler.cc \
 	quick/inline_method_analyser.cc \
 	reference_table.cc \
 	reflection.cc \
diff --git a/runtime/arch/arch_test.cc b/runtime/arch/arch_test.cc
new file mode 100644
index 0000000..47c6d28
--- /dev/null
+++ b/runtime/arch/arch_test.cc
@@ -0,0 +1,498 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <stdint.h>
+
+#include "common_runtime_test.h"
+#include "mirror/art_method.h"
+
+namespace art {
+
+class ArchTest : public CommonRuntimeTest {
+ protected:
+  static void CheckFrameSize(InstructionSet isa, Runtime::CalleeSaveType type, uint32_t save_size)
+      NO_THREAD_SAFETY_ANALYSIS {
+    Runtime* r = Runtime::Current();
+
+    Thread* t = Thread::Current();
+    t->TransitionFromSuspendedToRunnable();  // So we can create callee-save methods.
+
+    mirror::ArtMethod* save_method = r->CreateCalleeSaveMethod(isa, type);
+    EXPECT_EQ(save_method->GetFrameSizeInBytes(), save_size) << "Expected and real size differs for "
+        << type << " core spills=" << std::hex << save_method->GetCoreSpillMask() << " fp spills="
+        << save_method->GetFpSpillMask() << std::dec;
+
+    t->TransitionFromRunnableToSuspended(ThreadState::kNative);  // So we can shut down.
+  }
+};
+
+
+TEST_F(ArchTest, ARM) {
+#include "arch/arm/asm_support_arm.h"
+#undef ART_RUNTIME_ARCH_ARM_ASM_SUPPORT_ARM_H_
+
+
+#ifdef FRAME_SIZE_SAVE_ALL_CALLEE_SAVE
+  CheckFrameSize(InstructionSet::kArm, Runtime::kSaveAll, FRAME_SIZE_SAVE_ALL_CALLEE_SAVE);
+#else
+  LOG(WARNING) << "No frame size for SaveAll";
+#endif
+#ifdef FRAME_SIZE_REFS_ONLY_CALLEE_SAVE
+  CheckFrameSize(InstructionSet::kArm, Runtime::kRefsOnly, FRAME_SIZE_REFS_ONLY_CALLEE_SAVE);
+#else
+  LOG(WARNING) << "No frame size for RefsOnly";
+#endif
+#ifdef FRAME_SIZE_REFS_AND_ARGS_CALLEE_SAVE
+  CheckFrameSize(InstructionSet::kArm, Runtime::kRefsAndArgs, FRAME_SIZE_REFS_AND_ARGS_CALLEE_SAVE);
+#else
+  LOG(WARNING) << "No frame size for RefsAndArgs";
+#endif
+
+
+#ifdef RUNTIME_SAVE_ALL_CALLEE_SAVE_FRAME_OFFSET
+#undef RUNTIME_SAVE_ALL_CALLEE_SAVE_FRAME_OFFSET
+#endif
+#ifdef RUNTIME_REFS_ONLY_CALLEE_SAVE_FRAME_OFFSET
+#undef RUNTIME_REFS_ONLY_CALLEE_SAVE_FRAME_OFFSET
+#endif
+#ifdef RUNTIME_REF_AND_ARGS_CALLEE_SAVE_FRAME_OFFSET
+#undef RUNTIME_REF_AND_ARGS_CALLEE_SAVE_FRAME_OFFSET
+#endif
+#ifdef THREAD_SELF_OFFSET
+#undef THREAD_SELF_OFFSET
+#endif
+#ifdef THREAD_CARD_TABLE_OFFSET
+#undef THREAD_CARD_TABLE_OFFSET
+#endif
+#ifdef THREAD_EXCEPTION_OFFSET
+#undef THREAD_EXCEPTION_OFFSET
+#endif
+#ifdef THREAD_ID_OFFSET
+#undef THREAD_ID_OFFSET
+#endif
+#ifdef FRAME_SIZE_SAVE_ALL_CALLEE_SAVE
+#undef FRAME_SIZE_SAVE_ALL_CALLEE_SAVE
+#endif
+#ifdef FRAME_SIZE_REFS_ONLY_CALLEE_SAVE
+#undef FRAME_SIZE_REFS_ONLY_CALLEE_SAVE
+#endif
+#ifdef FRAME_SIZE_REFS_AND_ARGS_CALLEE_SAVE
+#undef FRAME_SIZE_REFS_AND_ARGS_CALLEE_SAVE
+#endif
+}
+
+
+TEST_F(ArchTest, ARM64) {
+#include "arch/arm64/asm_support_arm64.h"
+#undef ART_RUNTIME_ARCH_ARM64_ASM_SUPPORT_ARM64_H_
+
+
+#ifdef FRAME_SIZE_SAVE_ALL_CALLEE_SAVE
+  CheckFrameSize(InstructionSet::kArm64, Runtime::kSaveAll, FRAME_SIZE_SAVE_ALL_CALLEE_SAVE);
+#else
+  LOG(WARNING) << "No frame size for SaveAll";
+#endif
+#ifdef FRAME_SIZE_REFS_ONLY_CALLEE_SAVE
+  CheckFrameSize(InstructionSet::kArm64, Runtime::kRefsOnly, FRAME_SIZE_REFS_ONLY_CALLEE_SAVE);
+#else
+  LOG(WARNING) << "No frame size for RefsOnly";
+#endif
+#ifdef FRAME_SIZE_REFS_AND_ARGS_CALLEE_SAVE
+  CheckFrameSize(InstructionSet::kArm64, Runtime::kRefsAndArgs, FRAME_SIZE_REFS_AND_ARGS_CALLEE_SAVE);
+#else
+  LOG(WARNING) << "No frame size for RefsAndArgs";
+#endif
+
+
+#ifdef RUNTIME_SAVE_ALL_CALLEE_SAVE_FRAME_OFFSET
+#undef RUNTIME_SAVE_ALL_CALLEE_SAVE_FRAME_OFFSET
+#endif
+#ifdef RUNTIME_REFS_ONLY_CALLEE_SAVE_FRAME_OFFSET
+#undef RUNTIME_REFS_ONLY_CALLEE_SAVE_FRAME_OFFSET
+#endif
+#ifdef RUNTIME_REF_AND_ARGS_CALLEE_SAVE_FRAME_OFFSET
+#undef RUNTIME_REF_AND_ARGS_CALLEE_SAVE_FRAME_OFFSET
+#endif
+#ifdef THREAD_SELF_OFFSET
+#undef THREAD_SELF_OFFSET
+#endif
+#ifdef THREAD_CARD_TABLE_OFFSET
+#undef THREAD_CARD_TABLE_OFFSET
+#endif
+#ifdef THREAD_EXCEPTION_OFFSET
+#undef THREAD_EXCEPTION_OFFSET
+#endif
+#ifdef THREAD_ID_OFFSET
+#undef THREAD_ID_OFFSET
+#endif
+#ifdef FRAME_SIZE_SAVE_ALL_CALLEE_SAVE
+#undef FRAME_SIZE_SAVE_ALL_CALLEE_SAVE
+#endif
+#ifdef FRAME_SIZE_REFS_ONLY_CALLEE_SAVE
+#undef FRAME_SIZE_REFS_ONLY_CALLEE_SAVE
+#endif
+#ifdef FRAME_SIZE_REFS_AND_ARGS_CALLEE_SAVE
+#undef FRAME_SIZE_REFS_AND_ARGS_CALLEE_SAVE
+#endif
+}
+
+
+TEST_F(ArchTest, MIPS) {
+#include "arch/mips/asm_support_mips.h"
+#undef ART_RUNTIME_ARCH_MIPS_ASM_SUPPORT_MIPS_H_
+
+
+#ifdef FRAME_SIZE_SAVE_ALL_CALLEE_SAVE
+  CheckFrameSize(InstructionSet::kMips, Runtime::kSaveAll, FRAME_SIZE_SAVE_ALL_CALLEE_SAVE);
+#else
+  LOG(WARNING) << "No frame size for SaveAll";
+#endif
+#ifdef FRAME_SIZE_REFS_ONLY_CALLEE_SAVE
+  CheckFrameSize(InstructionSet::kMips, Runtime::kRefsOnly, FRAME_SIZE_REFS_ONLY_CALLEE_SAVE);
+#else
+  LOG(WARNING) << "No frame size for RefsOnly";
+#endif
+#ifdef FRAME_SIZE_REFS_AND_ARGS_CALLEE_SAVE
+  CheckFrameSize(InstructionSet::kMips, Runtime::kRefsAndArgs, FRAME_SIZE_REFS_AND_ARGS_CALLEE_SAVE);
+#else
+  LOG(WARNING) << "No frame size for RefsAndArgs";
+#endif
+
+
+#ifdef RUNTIME_SAVE_ALL_CALLEE_SAVE_FRAME_OFFSET
+#undef RUNTIME_SAVE_ALL_CALLEE_SAVE_FRAME_OFFSET
+#endif
+#ifdef RUNTIME_REFS_ONLY_CALLEE_SAVE_FRAME_OFFSET
+#undef RUNTIME_REFS_ONLY_CALLEE_SAVE_FRAME_OFFSET
+#endif
+#ifdef RUNTIME_REF_AND_ARGS_CALLEE_SAVE_FRAME_OFFSET
+#undef RUNTIME_REF_AND_ARGS_CALLEE_SAVE_FRAME_OFFSET
+#endif
+#ifdef THREAD_SELF_OFFSET
+#undef THREAD_SELF_OFFSET
+#endif
+#ifdef THREAD_CARD_TABLE_OFFSET
+#undef THREAD_CARD_TABLE_OFFSET
+#endif
+#ifdef THREAD_EXCEPTION_OFFSET
+#undef THREAD_EXCEPTION_OFFSET
+#endif
+#ifdef THREAD_ID_OFFSET
+#undef THREAD_ID_OFFSET
+#endif
+#ifdef FRAME_SIZE_SAVE_ALL_CALLEE_SAVE
+#undef FRAME_SIZE_SAVE_ALL_CALLEE_SAVE
+#endif
+#ifdef FRAME_SIZE_REFS_ONLY_CALLEE_SAVE
+#undef FRAME_SIZE_REFS_ONLY_CALLEE_SAVE
+#endif
+#ifdef FRAME_SIZE_REFS_AND_ARGS_CALLEE_SAVE
+#undef FRAME_SIZE_REFS_AND_ARGS_CALLEE_SAVE
+#endif
+}
+
+
+TEST_F(ArchTest, X86) {
+#include "arch/x86/asm_support_x86.h"
+#undef ART_RUNTIME_ARCH_X86_ASM_SUPPORT_X86_H_
+
+
+#ifdef FRAME_SIZE_SAVE_ALL_CALLEE_SAVE
+  CheckFrameSize(InstructionSet::kX86, Runtime::kSaveAll, FRAME_SIZE_SAVE_ALL_CALLEE_SAVE);
+#else
+  LOG(WARNING) << "No frame size for SaveAll";
+#endif
+#ifdef FRAME_SIZE_REFS_ONLY_CALLEE_SAVE
+  CheckFrameSize(InstructionSet::kX86, Runtime::kRefsOnly, FRAME_SIZE_REFS_ONLY_CALLEE_SAVE);
+#else
+  LOG(WARNING) << "No frame size for RefsOnly";
+#endif
+#ifdef FRAME_SIZE_REFS_AND_ARGS_CALLEE_SAVE
+  CheckFrameSize(InstructionSet::kX86, Runtime::kRefsAndArgs, FRAME_SIZE_REFS_AND_ARGS_CALLEE_SAVE);
+#else
+  LOG(WARNING) << "No frame size for RefsAndArgs";
+#endif
+
+
+#ifdef RUNTIME_SAVE_ALL_CALLEE_SAVE_FRAME_OFFSET
+#undef RUNTIME_SAVE_ALL_CALLEE_SAVE_FRAME_OFFSET
+#endif
+#ifdef RUNTIME_REFS_ONLY_CALLEE_SAVE_FRAME_OFFSET
+#undef RUNTIME_REFS_ONLY_CALLEE_SAVE_FRAME_OFFSET
+#endif
+#ifdef RUNTIME_REF_AND_ARGS_CALLEE_SAVE_FRAME_OFFSET
+#undef RUNTIME_REF_AND_ARGS_CALLEE_SAVE_FRAME_OFFSET
+#endif
+#ifdef THREAD_SELF_OFFSET
+#undef THREAD_SELF_OFFSET
+#endif
+#ifdef THREAD_CARD_TABLE_OFFSET
+#undef THREAD_CARD_TABLE_OFFSET
+#endif
+#ifdef THREAD_EXCEPTION_OFFSET
+#undef THREAD_EXCEPTION_OFFSET
+#endif
+#ifdef THREAD_ID_OFFSET
+#undef THREAD_ID_OFFSET
+#endif
+#ifdef FRAME_SIZE_SAVE_ALL_CALLEE_SAVE
+#undef FRAME_SIZE_SAVE_ALL_CALLEE_SAVE
+#endif
+#ifdef FRAME_SIZE_REFS_ONLY_CALLEE_SAVE
+#undef FRAME_SIZE_REFS_ONLY_CALLEE_SAVE
+#endif
+#ifdef FRAME_SIZE_REFS_AND_ARGS_CALLEE_SAVE
+#undef FRAME_SIZE_REFS_AND_ARGS_CALLEE_SAVE
+#endif
+}
+
+
+TEST_F(ArchTest, X86_64) {
+#include "arch/x86_64/asm_support_x86_64.h"
+#undef ART_RUNTIME_ARCH_X86_64_ASM_SUPPORT_X86_64_H_
+
+
+#ifdef FRAME_SIZE_SAVE_ALL_CALLEE_SAVE
+  CheckFrameSize(InstructionSet::kX86_64, Runtime::kSaveAll, FRAME_SIZE_SAVE_ALL_CALLEE_SAVE);
+#else
+  LOG(WARNING) << "No frame size for SaveAll";
+#endif
+#ifdef FRAME_SIZE_REFS_ONLY_CALLEE_SAVE
+  CheckFrameSize(InstructionSet::kX86_64, Runtime::kRefsOnly, FRAME_SIZE_REFS_ONLY_CALLEE_SAVE);
+#else
+  LOG(WARNING) << "No frame size for RefsOnly";
+#endif
+#ifdef FRAME_SIZE_REFS_AND_ARGS_CALLEE_SAVE
+  CheckFrameSize(InstructionSet::kX86_64, Runtime::kRefsAndArgs, FRAME_SIZE_REFS_AND_ARGS_CALLEE_SAVE);
+#else
+  LOG(WARNING) << "No frame size for RefsAndArgs";
+#endif
+
+
+#ifdef RUNTIME_SAVE_ALL_CALLEE_SAVE_FRAME_OFFSET
+#undef RUNTIME_SAVE_ALL_CALLEE_SAVE_FRAME_OFFSET
+#endif
+#ifdef RUNTIME_REFS_ONLY_CALLEE_SAVE_FRAME_OFFSET
+#undef RUNTIME_REFS_ONLY_CALLEE_SAVE_FRAME_OFFSET
+#endif
+#ifdef RUNTIME_REF_AND_ARGS_CALLEE_SAVE_FRAME_OFFSET
+#undef RUNTIME_REF_AND_ARGS_CALLEE_SAVE_FRAME_OFFSET
+#endif
+#ifdef THREAD_SELF_OFFSET
+#undef THREAD_SELF_OFFSET
+#endif
+#ifdef THREAD_CARD_TABLE_OFFSET
+#undef THREAD_CARD_TABLE_OFFSET
+#endif
+#ifdef THREAD_EXCEPTION_OFFSET
+#undef THREAD_EXCEPTION_OFFSET
+#endif
+#ifdef THREAD_ID_OFFSET
+#undef THREAD_ID_OFFSET
+#endif
+#ifdef FRAME_SIZE_SAVE_ALL_CALLEE_SAVE
+#undef FRAME_SIZE_SAVE_ALL_CALLEE_SAVE
+#endif
+#ifdef FRAME_SIZE_REFS_ONLY_CALLEE_SAVE
+#undef FRAME_SIZE_REFS_ONLY_CALLEE_SAVE
+#endif
+#ifdef FRAME_SIZE_REFS_AND_ARGS_CALLEE_SAVE
+#undef FRAME_SIZE_REFS_AND_ARGS_CALLEE_SAVE
+#endif
+}
+
+
+TEST_F(ArchTest, ThreadOffsets) {
+#if defined(__arm__)
+#include "arch/arm/asm_support_arm.h"
+#undef ART_RUNTIME_ARCH_ARM_ASM_SUPPORT_ARM_H_
+#elif defined(__aarch64__)
+#include "arch/arm64/asm_support_arm64.h"
+#undef ART_RUNTIME_ARCH_ARM64_ASM_SUPPORT_ARM64_H_
+#elif defined(__mips__)
+#include "arch/mips/asm_support_mips.h"
+#undef ART_RUNTIME_ARCH_MIPS_ASM_SUPPORT_MIPS_H_
+#elif defined(__i386__)
+#include "arch/x86/asm_support_x86.h"
+#undef ART_RUNTIME_ARCH_X86_ASM_SUPPORT_X86_H_
+#elif defined(__x86_64__)
+#include "arch/x86_64/asm_support_x86_64.h"
+#undef ART_RUNTIME_ARCH_X86_64_ASM_SUPPORT_X86_64_H_
+#else
+  // This happens for the host test.
+#ifdef __LP64__
+#include "arch/x86_64/asm_support_x86_64.h"
+#undef ART_RUNTIME_ARCH_X86_64_ASM_SUPPORT_X86_64_H_
+#else
+#include "arch/x86/asm_support_x86.h"
+#undef ART_RUNTIME_ARCH_X86_ASM_SUPPORT_X86_H_
+#endif
+#endif
+
+  // Ugly hack, change when possible.
+#ifdef __LP64__
+#define POINTER_SIZE 8
+#else
+#define POINTER_SIZE 4
+#endif
+
+#if defined(THREAD_SELF_OFFSET)
+  ThreadOffset<POINTER_SIZE> self_offset = Thread::SelfOffset<POINTER_SIZE>();
+  EXPECT_EQ(self_offset.Int32Value(), THREAD_SELF_OFFSET);
+#else
+  LOG(INFO) << "No Thread Self Offset found.";
+#endif
+
+#if defined(THREAD_CARD_TABLE_OFFSET)
+  ThreadOffset<POINTER_SIZE> card_offset = Thread::CardTableOffset<POINTER_SIZE>();
+  EXPECT_EQ(card_offset.Int32Value(), THREAD_CARD_TABLE_OFFSET);
+#else
+  LOG(INFO) << "No Thread Card Table Offset found.";
+#endif
+
+#if defined(THREAD_EXCEPTION_OFFSET)
+  ThreadOffset<POINTER_SIZE> exc_offset = Thread::ExceptionOffset<POINTER_SIZE>();
+    EXPECT_EQ(exc_offset.Int32Value(), THREAD_EXCEPTION_OFFSET);
+#else
+  LOG(INFO) << "No Thread Exception Offset found.";
+#endif
+
+#if defined(THREAD_ID_OFFSET)
+  ThreadOffset<POINTER_SIZE> id_offset = Thread::ThinLockIdOffset<POINTER_SIZE>();
+  EXPECT_EQ(id_offset.Int32Value(), THREAD_ID_OFFSET);
+#else
+  LOG(INFO) << "No Thread ID Offset found.";
+#endif
+
+
+  // Undefine everything for the next test
+#ifdef RUNTIME_SAVE_ALL_CALLEE_SAVE_FRAME_OFFSET
+#undef RUNTIME_SAVE_ALL_CALLEE_SAVE_FRAME_OFFSET
+#endif
+#ifdef RUNTIME_REFS_ONLY_CALLEE_SAVE_FRAME_OFFSET
+#undef RUNTIME_REFS_ONLY_CALLEE_SAVE_FRAME_OFFSET
+#endif
+#ifdef RUNTIME_REF_AND_ARGS_CALLEE_SAVE_FRAME_OFFSET
+#undef RUNTIME_REF_AND_ARGS_CALLEE_SAVE_FRAME_OFFSET
+#endif
+#ifdef THREAD_SELF_OFFSET
+#undef THREAD_SELF_OFFSET
+#endif
+#ifdef THREAD_CARD_TABLE_OFFSET
+#undef THREAD_CARD_TABLE_OFFSET
+#endif
+#ifdef THREAD_EXCEPTION_OFFSET
+#undef THREAD_EXCEPTION_OFFSET
+#endif
+#ifdef THREAD_ID_OFFSET
+#undef THREAD_ID_OFFSET
+#endif
+#ifdef FRAME_SIZE_SAVE_ALL_CALLEE_SAVE
+#undef FRAME_SIZE_SAVE_ALL_CALLEE_SAVE
+#endif
+#ifdef FRAME_SIZE_REFS_ONLY_CALLEE_SAVE
+#undef FRAME_SIZE_REFS_ONLY_CALLEE_SAVE
+#endif
+#ifdef FRAME_SIZE_REFS_AND_ARGS_CALLEE_SAVE
+#undef FRAME_SIZE_REFS_AND_ARGS_CALLEE_SAVE
+#endif
+}
+
+
+TEST_F(ArchTest, CalleeSaveMethodOffsets) {
+#if defined(__arm__)
+#include "arch/arm/asm_support_arm.h"
+#undef ART_RUNTIME_ARCH_ARM_ASM_SUPPORT_ARM_H_
+#elif defined(__aarch64__)
+#include "arch/arm64/asm_support_arm64.h"
+#undef ART_RUNTIME_ARCH_ARM64_ASM_SUPPORT_ARM64_H_
+#elif defined(__mips__)
+#include "arch/mips/asm_support_mips.h"
+#undef ART_RUNTIME_ARCH_MIPS_ASM_SUPPORT_MIPS_H_
+#elif defined(__i386__)
+#include "arch/x86/asm_support_x86.h"
+#undef ART_RUNTIME_ARCH_X86_ASM_SUPPORT_X86_H_
+#elif defined(__x86_64__)
+#include "arch/x86_64/asm_support_x86_64.h"
+#undef ART_RUNTIME_ARCH_X86_64_ASM_SUPPORT_X86_64_H_
+#else
+  // This happens for the host test.
+#ifdef __LP64__
+#include "arch/x86_64/asm_support_x86_64.h"
+#undef ART_RUNTIME_ARCH_X86_64_ASM_SUPPORT_X86_64_H_
+#else
+#include "arch/x86/asm_support_x86.h"
+#undef ART_RUNTIME_ARCH_X86_ASM_SUPPORT_X86_H_
+#endif
+#endif
+
+
+#if defined(RUNTIME_SAVE_ALL_CALLEE_SAVE_FRAME_OFFSET)
+  EXPECT_EQ(Runtime::GetCalleeSaveMethodOffset(Runtime::kSaveAll),
+            static_cast<size_t>(RUNTIME_SAVE_ALL_CALLEE_SAVE_FRAME_OFFSET));
+#else
+  LOG(INFO) << "No Runtime Save-all Offset found.";
+#endif
+
+#if defined(RUNTIME_REFS_ONLY_CALLEE_SAVE_FRAME_OFFSET)
+  EXPECT_EQ(Runtime::GetCalleeSaveMethodOffset(Runtime::kRefsOnly),
+            static_cast<size_t>(RUNTIME_REFS_ONLY_CALLEE_SAVE_FRAME_OFFSET));
+#else
+  LOG(INFO) << "No Runtime Refs-only Offset found.";
+#endif
+
+#if defined(RUNTIME_REF_AND_ARGS_CALLEE_SAVE_FRAME_OFFSET)
+  EXPECT_EQ(Runtime::GetCalleeSaveMethodOffset(Runtime::kRefsAndArgs),
+            static_cast<size_t>(RUNTIME_REF_AND_ARGS_CALLEE_SAVE_FRAME_OFFSET));
+#else
+  LOG(INFO) << "No Runtime Refs-and-Args Offset found.";
+#endif
+
+
+  // Undefine everything for the next test
+#ifdef RUNTIME_SAVE_ALL_CALLEE_SAVE_FRAME_OFFSET
+#undef RUNTIME_SAVE_ALL_CALLEE_SAVE_FRAME_OFFSET
+#endif
+#ifdef RUNTIME_REFS_ONLY_CALLEE_SAVE_FRAME_OFFSET
+#undef RUNTIME_REFS_ONLY_CALLEE_SAVE_FRAME_OFFSET
+#endif
+#ifdef RUNTIME_REF_AND_ARGS_CALLEE_SAVE_FRAME_OFFSET
+#undef RUNTIME_REF_AND_ARGS_CALLEE_SAVE_FRAME_OFFSET
+#endif
+#ifdef THREAD_SELF_OFFSET
+#undef THREAD_SELF_OFFSET
+#endif
+#ifdef THREAD_CARD_TABLE_OFFSET
+#undef THREAD_CARD_TABLE_OFFSET
+#endif
+#ifdef THREAD_EXCEPTION_OFFSET
+#undef THREAD_EXCEPTION_OFFSET
+#endif
+#ifdef THREAD_ID_OFFSET
+#undef THREAD_ID_OFFSET
+#endif
+#ifdef FRAME_SIZE_SAVE_ALL_CALLEE_SAVE
+#undef FRAME_SIZE_SAVE_ALL_CALLEE_SAVE
+#endif
+#ifdef FRAME_SIZE_REFS_ONLY_CALLEE_SAVE
+#undef FRAME_SIZE_REFS_ONLY_CALLEE_SAVE
+#endif
+#ifdef FRAME_SIZE_REFS_AND_ARGS_CALLEE_SAVE
+#undef FRAME_SIZE_REFS_AND_ARGS_CALLEE_SAVE
+#endif
+}
+
+}  // namespace art
diff --git a/runtime/arch/arm/asm_support_arm.S b/runtime/arch/arm/asm_support_arm.S
index fb85feb..594252a 100644
--- a/runtime/arch/arm/asm_support_arm.S
+++ b/runtime/arch/arm/asm_support_arm.S
@@ -19,6 +19,13 @@
 
 #include "asm_support_arm.h"
 
+// Define special registers.
+
+// Register holding suspend check count down.
+#define rSUSPEND r4
+// Register holding Thread::Current().
+#define rSELF r9
+
 .cfi_sections   .debug_frame
 .syntax unified
 .arch armv7-a
diff --git a/runtime/arch/arm/asm_support_arm.h b/runtime/arch/arm/asm_support_arm.h
index 4b64076..a73d522 100644
--- a/runtime/arch/arm/asm_support_arm.h
+++ b/runtime/arch/arm/asm_support_arm.h
@@ -19,10 +19,6 @@
 
 #include "asm_support.h"
 
-// Register holding suspend check count down.
-#define rSUSPEND r4
-// Register holding Thread::Current().
-#define rSELF r9
 // Offset of field Thread::tls32_.state_and_flags verified in InitCpu
 #define THREAD_FLAGS_OFFSET 0
 // Offset of field Thread::tls32_.thin_lock_thread_id verified in InitCpu
@@ -32,4 +28,8 @@
 // Offset of field Thread::tlsPtr_.exception verified in InitCpu
 #define THREAD_EXCEPTION_OFFSET 116
 
+#define FRAME_SIZE_SAVE_ALL_CALLEE_SAVE 176
+#define FRAME_SIZE_REFS_ONLY_CALLEE_SAVE 32
+#define FRAME_SIZE_REFS_AND_ARGS_CALLEE_SAVE 48
+
 #endif  // ART_RUNTIME_ARCH_ARM_ASM_SUPPORT_ARM_H_
diff --git a/runtime/arch/arm/quick_entrypoints_arm.S b/runtime/arch/arm/quick_entrypoints_arm.S
index 4903732..bc80644 100644
--- a/runtime/arch/arm/quick_entrypoints_arm.S
+++ b/runtime/arch/arm/quick_entrypoints_arm.S
@@ -46,6 +46,11 @@
     sub sp, #12       @ 3 words of space, bottom word will hold Method*
     .pad #12
     .cfi_adjust_cfa_offset 12
+
+     // Ugly compile-time check, but we only have the preprocessor.
+#if (FRAME_SIZE_SAVE_ALL_CALLEE_SAVE != 36 + 128 + 12)
+#error "SAVE_ALL_CALLEE_SAVE_FRAME(ARM) size not as expected."
+#endif
 .endm
 
     /*
@@ -66,6 +71,11 @@
     sub sp, #4                @ bottom word will hold Method*
     .pad #4
     .cfi_adjust_cfa_offset 4
+
+    // Ugly compile-time check, but we only have the preprocessor.
+#if (FRAME_SIZE_REFS_ONLY_CALLEE_SAVE != 28 + 4)
+#error "REFS_ONLY_CALLEE_SAVE_FRAME(ARM) size not as expected."
+#endif
 .endm
 
 .macro RESTORE_REF_ONLY_CALLEE_SAVE_FRAME
@@ -114,6 +124,11 @@
     sub sp, #8                        @ 2 words of space, bottom word will hold Method*
     .pad #8
     .cfi_adjust_cfa_offset 8
+
+    // Ugly compile-time check, but we only have the preprocessor.
+#if (FRAME_SIZE_REFS_AND_ARGS_CALLEE_SAVE != 40 + 8)
+#error "REFS_AND_ARGS_CALLEE_SAVE_FRAME(ARM64) size not as expected."
+#endif
 .endm
 
 .macro RESTORE_REF_AND_ARGS_CALLEE_SAVE_FRAME
@@ -492,11 +507,22 @@
     blx lr
 .Lcheck_assignability:
     push {r0-r2, lr}             @ save arguments
+    .save {r0-r2, lr}
+    .cfi_adjust_cfa_offset 16
+    .cfi_rel_offset r0, 0
+    .cfi_rel_offset r1, 4
+    .cfi_rel_offset r2, 8
+    .cfi_rel_offset lr, 12
     mov r1, ip
     mov r0, r3
     bl artIsAssignableFromCode
     cbz r0, .Lthrow_array_store_exception
     pop {r0-r2, lr}
+    .cfi_restore r0
+    .cfi_restore r1
+    .cfi_restore r2
+    .cfi_restore lr
+    .cfi_adjust_cfa_offset -16
     add r3, r0, #OBJECT_ARRAY_DATA_OFFSET
     str r2, [r3, r1, lsl #2]
     ldr r3, [r9, #THREAD_CARD_TABLE_OFFSET]
@@ -505,6 +531,11 @@
     blx lr
 .Lthrow_array_store_exception:
     pop {r0-r2, lr}
+    .cfi_restore r0
+    .cfi_restore r1
+    .cfi_restore r2
+    .cfi_restore lr
+    .cfi_adjust_cfa_offset -16
     SETUP_SAVE_ALL_CALLEE_SAVE_FRAME
     mov r1, r2
     mov r2, r9                   @ pass Thread::Current
diff --git a/runtime/arch/arm64/asm_support_arm64.S b/runtime/arch/arm64/asm_support_arm64.S
index 634f777..9614c29 100644
--- a/runtime/arch/arm64/asm_support_arm64.S
+++ b/runtime/arch/arm64/asm_support_arm64.S
@@ -19,6 +19,19 @@
 
 #include "asm_support_arm64.h"
 
+// Define special registers.
+
+// Register holding Thread::Current().
+#define xSELF x18
+// Frame Pointer
+#define xFP   x29
+// Link Register
+#define xLR   x30
+// Define the intraprocedural linkage temporary registers.
+#define xIP0 x16
+#define xIP1 x17
+
+
 .cfi_sections   .debug_frame
 
 .macro ENTRY name
diff --git a/runtime/arch/arm64/asm_support_arm64.h b/runtime/arch/arm64/asm_support_arm64.h
index a7e68ed..b18e415 100644
--- a/runtime/arch/arm64/asm_support_arm64.h
+++ b/runtime/arch/arm64/asm_support_arm64.h
@@ -28,15 +28,6 @@
 // Offset of field Runtime::callee_save_methods_[kRefsAndArgs]
 #define RUNTIME_REF_AND_ARGS_CALLEE_SAVE_FRAME_OFFSET 16
 
-// Register holding Thread::Current().
-#define xSELF x18
-// Frame Pointer
-#define xFP   x29
-// Link Register
-#define xLR   x30
-// Define the intraprocedural linkage temporary registers.
-#define xIP0 x16
-#define xIP1 x17
 // Offset of field Thread::suspend_count_ verified in InitCpu
 #define THREAD_FLAGS_OFFSET 0
 // Offset of field Thread::card_table_ verified in InitCpu
@@ -46,4 +37,8 @@
 // Offset of field Thread::thin_lock_thread_id_ verified in InitCpu
 #define THREAD_ID_OFFSET 12
 
+#define FRAME_SIZE_SAVE_ALL_CALLEE_SAVE 368
+#define FRAME_SIZE_REFS_ONLY_CALLEE_SAVE 176
+#define FRAME_SIZE_REFS_AND_ARGS_CALLEE_SAVE 304
+
 #endif  // ART_RUNTIME_ARCH_ARM64_ASM_SUPPORT_ARM64_H_
diff --git a/runtime/arch/arm64/quick_entrypoints_arm64.S b/runtime/arch/arm64/quick_entrypoints_arm64.S
index 6ce5d06..71f5bf7 100644
--- a/runtime/arch/arm64/quick_entrypoints_arm64.S
+++ b/runtime/arch/arm64/quick_entrypoints_arm64.S
@@ -36,6 +36,11 @@
     sub sp, sp, #368
     .cfi_adjust_cfa_offset 368
 
+    // Ugly compile-time check, but we only have the preprocessor.
+#if (FRAME_SIZE_SAVE_ALL_CALLEE_SAVE != 368)
+#error "SAVE_ALL_CALLEE_SAVE_FRAME(ARM64) size not as expected."
+#endif
+
     // FP args
     stp d1, d2,   [sp, #8]
     stp d2, d3, [sp, #24]
@@ -95,8 +100,61 @@
      * Macro that sets up the callee save frame to conform with
      * Runtime::CreateCalleeSaveMethod(kRefsOnly).
      */
+// WIP.
 .macro SETUP_REF_ONLY_CALLEE_SAVE_FRAME
-    brk 0
+    adrp x9, :got:_ZN3art7Runtime9instance_E
+    ldr x9, [x9, #:got_lo12:_ZN3art7Runtime9instance_E]
+
+    // Our registers aren't intermixed - just spill in order.
+    ldr x9,[x9]  // x9 = & (art::Runtime * art::Runtime.instance_) .
+
+    // x9 = (ArtMethod*) Runtime.instance_.callee_save_methods[kRefAndArgs]  .
+    ldr x9, [x9, RUNTIME_REFS_ONLY_CALLEE_SAVE_FRAME_OFFSET ]
+
+    sub sp, sp, #176
+    .cfi_adjust_cfa_offset 176
+
+    // Ugly compile-time check, but we only have the preprocessor.
+#if (FRAME_SIZE_REFS_ONLY_CALLEE_SAVE != 176)
+#error "REFS_ONLY_CALLEE_SAVE_FRAME(ARM64) size not as expected."
+#endif
+
+    // FP callee-saves
+    stp d8, d9,   [sp, #8]
+    stp d10, d11, [sp, #24]
+    stp d12, d13, [sp, #40]
+    stp d14, d15, [sp, #56]
+
+    // Callee saved.
+    stp xSELF, x19, [sp, #72]
+    .cfi_rel_offset x18, 72
+    .cfi_rel_offset x19, 80
+
+    stp x20, x21, [sp, #88]
+    .cfi_rel_offset x20, 88
+    .cfi_rel_offset x21, 96
+
+    stp x22, x23, [sp, #104]
+    .cfi_rel_offset x22, 104
+    .cfi_rel_offset x23, 112
+
+    stp x24, x25, [sp, #120]
+    .cfi_rel_offset x24, 120
+    .cfi_rel_offset x25, 128
+
+    stp x26, x27, [sp, #136]
+    .cfi_rel_offset x26, 136
+    .cfi_rel_offset x27, 144
+
+    stp x28, xFP, [sp, #152]    // Save FP.
+    .cfi_rel_offset x28, 152
+    .cfi_rel_offset x29, 160
+
+    str xLR, [sp, #168]
+    .cfi_rel_offset x30, 168
+
+    // Loads appropriate callee-save-method
+    str x9, [sp]    // Store ArtMethod* Runtime::callee_save_methods_[kRefsAndArgs]
 .endm
 
 .macro RESTORE_REF_ONLY_CALLEE_SAVE_FRAME
@@ -112,6 +170,11 @@
     sub sp, sp, #304
     .cfi_adjust_cfa_offset 304
 
+    // Ugly compile-time check, but we only have the preprocessor.
+#if (FRAME_SIZE_REFS_AND_ARGS_CALLEE_SAVE != 304)
+#error "REFS_AND_ARGS_CALLEE_SAVE_FRAME(ARM64) size not as expected."
+#endif
+
     stp d0, d1,   [sp, #16]
     stp d2, d3,   [sp, #32]
     stp d4, d5,   [sp, #48]
@@ -325,10 +388,14 @@
     DELIVER_PENDING_EXCEPTION
 .endm
 
+// FIXME: Temporary fix for TR(XSELF).
 .macro NO_ARG_RUNTIME_EXCEPTION c_name, cxx_name
     .extern \cxx_name
 ENTRY \c_name
-    brk 0
+    SETUP_SAVE_ALL_CALLEE_SAVE_FRAME  // save all registers as basis for long jump context
+    mov x0, x19                        // pass Thread::Current
+    mov x1, sp                        // pass SP
+    b   \cxx_name                     // \cxx_name(Thread*, SP)
 END \c_name
 .endm
 
@@ -339,15 +406,19 @@
     SETUP_SAVE_ALL_CALLEE_SAVE_FRAME  // save all registers as basis for long jump context.
     mov x1, x19                       // pass Thread::Current.
     mov x2, sp                        // pass SP.
-    b   \cxx_name                     // \cxx_name(Thread*, SP).
+    b   \cxx_name                     // \cxx_name(arg, Thread*, SP).
     brk 0
 END \c_name
 .endm
 
+// FIXME: Temporary fix for TR(XSELF).
 .macro TWO_ARG_RUNTIME_EXCEPTION c_name, cxx_name
     .extern \cxx_name
 ENTRY \c_name
     SETUP_SAVE_ALL_CALLEE_SAVE_FRAME  // save all registers as basis for long jump context
+    mov x2, x19                       // pass Thread::Current
+    mov x3, sp                        // pass SP
+    b   \cxx_name                     // \cxx_name(arg1, arg2, Thread*, SP)
     brk 0
 END \c_name
 .endm
@@ -864,7 +935,58 @@
 
 UNIMPLEMENTED art_quick_lock_object
 UNIMPLEMENTED art_quick_unlock_object
-UNIMPLEMENTED art_quick_check_cast
+
+    /*
+     * Entry from managed code that calls artIsAssignableFromCode and on failure calls
+     * artThrowClassCastException.
+     */
+    .extern artThrowClassCastException
+ENTRY art_quick_check_cast
+    // Store arguments and link register
+    sub sp, sp, #32                     // Stack needs to be 16b aligned on calls
+    .cfi_adjust_cfa_offset 32
+    stp x0, x1, [sp]
+    .cfi_rel_offset x0, 0
+    .cfi_rel_offset x1, 8
+    stp xSELF, xLR, [sp, #16]
+    .cfi_rel_offset x18, 16
+    .cfi_rel_offset x30, 24
+
+    // Call runtime code
+    bl artIsAssignableFromCode
+
+    // Check for exception
+    cbz x0, .Lthrow_class_cast_exception
+
+    // Restore and return
+    ldp x0, x1, [sp]
+    .cfi_restore x0
+    .cfi_restore x1
+    ldp xSELF, xLR, [sp, #16]
+    .cfi_restore x18
+    .cfi_restore x30
+    add sp, sp, #32
+    .cfi_adjust_cfa_offset -32
+    ret
+
+.Lthrow_class_cast_exception:
+    // Restore
+    ldp x0, x1, [sp]
+    .cfi_restore x0
+    .cfi_restore x1
+    ldp xSELF, xLR, [sp, #16]
+    .cfi_restore x18
+    .cfi_restore x30
+    add sp, sp, #32
+    .cfi_adjust_cfa_offset -32
+
+    SETUP_SAVE_ALL_CALLEE_SAVE_FRAME  // save all registers as basis for long jump context
+    mov x2, xSELF                     // pass Thread::Current
+    mov x3, sp                        // pass SP
+    b artThrowClassCastException      // (Class*, Class*, Thread*, SP)
+    brk 0                             // We should not return here...
+END art_quick_check_cast
+
 UNIMPLEMENTED art_quick_aput_obj_with_null_and_bound_check
 UNIMPLEMENTED art_quick_aput_obj_with_bound_check
 UNIMPLEMENTED art_quick_aput_obj
diff --git a/runtime/arch/mips/asm_support_mips.S b/runtime/arch/mips/asm_support_mips.S
index d110b95..d8ec9cd 100644
--- a/runtime/arch/mips/asm_support_mips.S
+++ b/runtime/arch/mips/asm_support_mips.S
@@ -19,6 +19,14 @@
 
 #include "asm_support_mips.h"
 
+// Define special registers.
+
+// Register holding suspend check count down.
+#define rSUSPEND $s0
+// Register holding Thread::Current().
+#define rSELF $s1
+
+
     /* Cache alignment for function entry */
 .macro ENTRY name
     .type \name, %function
diff --git a/runtime/arch/mips/asm_support_mips.h b/runtime/arch/mips/asm_support_mips.h
index 36ce1b6..2b4a745 100644
--- a/runtime/arch/mips/asm_support_mips.h
+++ b/runtime/arch/mips/asm_support_mips.h
@@ -19,10 +19,6 @@
 
 #include "asm_support.h"
 
-// Register holding suspend check count down.
-#define rSUSPEND $s0
-// Register holding Thread::Current().
-#define rSELF $s1
 // Offset of field Thread::tls32_.state_and_flags verified in InitCpu
 #define THREAD_FLAGS_OFFSET 0
 // Offset of field Thread::tlsPtr_.card_table verified in InitCpu
@@ -30,4 +26,8 @@
 // Offset of field Thread::tlsPtr_.exception verified in InitCpu
 #define THREAD_EXCEPTION_OFFSET 116
 
+#define FRAME_SIZE_SAVE_ALL_CALLEE_SAVE 64
+#define FRAME_SIZE_REFS_ONLY_CALLEE_SAVE 64
+#define FRAME_SIZE_REFS_AND_ARGS_CALLEE_SAVE 64
+
 #endif  // ART_RUNTIME_ARCH_MIPS_ASM_SUPPORT_MIPS_H_
diff --git a/runtime/arch/mips/quick_entrypoints_mips.S b/runtime/arch/mips/quick_entrypoints_mips.S
index c3ae563..95fcd73 100644
--- a/runtime/arch/mips/quick_entrypoints_mips.S
+++ b/runtime/arch/mips/quick_entrypoints_mips.S
@@ -34,6 +34,12 @@
 .macro SETUP_SAVE_ALL_CALLEE_SAVE_FRAME
     addiu  $sp, $sp, -64
     .cfi_adjust_cfa_offset 64
+
+     // Ugly compile-time check, but we only have the preprocessor.
+#if (FRAME_SIZE_SAVE_ALL_CALLEE_SAVE != 64)
+#error "SAVE_ALL_CALLEE_SAVE_FRAME(MIPS) size not as expected."
+#endif
+
     sw     $ra, 60($sp)
     .cfi_rel_offset 31, 60
     sw     $s8, 56($sp)
@@ -68,6 +74,12 @@
 .macro SETUP_REF_ONLY_CALLEE_SAVE_FRAME
     addiu  $sp, $sp, -64
     .cfi_adjust_cfa_offset 64
+
+    // Ugly compile-time check, but we only have the preprocessor.
+#if (FRAME_SIZE_REFS_ONLY_CALLEE_SAVE != 64)
+#error "REFS_ONLY_CALLEE_SAVE_FRAME(MIPS) size not as expected."
+#endif
+
     sw     $ra, 60($sp)
     .cfi_rel_offset 31, 60
     sw     $s8, 56($sp)
@@ -144,6 +156,12 @@
 .macro SETUP_REF_AND_ARGS_CALLEE_SAVE_FRAME
     addiu  $sp, $sp, -64
     .cfi_adjust_cfa_offset 64
+
+    // Ugly compile-time check, but we only have the preprocessor.
+#if (FRAME_SIZE_REFS_AND_ARGS_CALLEE_SAVE != 64)
+#error "REFS_AND_ARGS_CALLEE_SAVE_FRAME(MIPS) size not as expected."
+#endif
+
     sw     $ra, 60($sp)
     .cfi_rel_offset 31, 60
     sw     $s8, 56($sp)
diff --git a/runtime/arch/stub_test.cc b/runtime/arch/stub_test.cc
new file mode 100644
index 0000000..543e695
--- /dev/null
+++ b/runtime/arch/stub_test.cc
@@ -0,0 +1,357 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "common_runtime_test.h"
+
+#include <cstdio>
+
+namespace art {
+
+
+class StubTest : public CommonRuntimeTest {
+ protected:
+  // We need callee-save methods set up in the Runtime for exceptions.
+  void SetUp() OVERRIDE {
+    // Do the normal setup.
+    CommonRuntimeTest::SetUp();
+
+    {
+      // Create callee-save methods
+      ScopedObjectAccess soa(Thread::Current());
+      for (int i = 0; i < Runtime::kLastCalleeSaveType; i++) {
+        Runtime::CalleeSaveType type = Runtime::CalleeSaveType(i);
+        if (!runtime_->HasCalleeSaveMethod(type)) {
+          runtime_->SetCalleeSaveMethod(runtime_->CreateCalleeSaveMethod(kRuntimeISA, type), type);
+        }
+      }
+    }
+  }
+
+
+  size_t Invoke3(size_t arg0, size_t arg1, size_t arg2, uintptr_t code, Thread* self) {
+    // Push a transition back into managed code onto the linked list in thread.
+    ManagedStack fragment;
+    self->PushManagedStackFragment(&fragment);
+
+    size_t result;
+#if defined(__i386__)
+    // TODO: Set the thread?
+    __asm__ __volatile__(
+        "pushl $0\n\t"               // Push nullptr to terminate quick stack
+        "call *%%edi\n\t"           // Call the stub
+        "addl $4, %%esp"               // Pop nullptr
+        : "=a" (result)
+          // Use the result from eax
+        : "a"(arg0), "c"(arg1), "d"(arg2), "D"(code)
+          // This places code into edi, arg0 into eax, arg1 into ecx, and arg2 into edx
+        : );  // clobber.
+    // TODO: Should we clobber the other registers? EBX gets clobbered by some of the stubs,
+    //       but compilation fails when declaring that.
+#elif defined(__arm__)
+    __asm__ __volatile__(
+        "push {r1-r2,r9, lr}\n\t"   // Save the link and thread register
+        ".cfi_adjust_cfa_offset 16\n\t"
+        "mov r0, %[arg0]\n\t"       // Set arg0-arg2
+        "mov r1, %[arg1]\n\t"       // TODO: Any way to use constraints like on x86?
+        "mov r2, %[arg2]\n\t"
+        // Use r9 last as we don't know whether it was used for arg0-arg2
+        "mov r9, #0\n\t"            // Push nullptr to terminate stack
+        "push {r9}\n\t"
+        ".cfi_adjust_cfa_offset 4\n\t"
+        "mov r9, %[self]\n\t"       // Set the thread
+        "blx %[code]\n\t"           // Call the stub
+        "pop {r1}\n\t"              // Pop nullptr
+        ".cfi_adjust_cfa_offset -4\n\t"
+        "pop {r1-r2,r9, lr}\n\t"    // Restore the link and thread register
+        ".cfi_adjust_cfa_offset -16\n\t"
+        "mov %[result], r0\n\t"     // Save the result
+        : [result] "=r" (result)
+          // Use the result from r0
+        : [arg0] "0"(arg0), [arg1] "r"(arg1), [arg2] "r"(arg2), [code] "r"(code), [self] "r"(self)
+        : );  // clobber.
+#elif defined(__aarch64__)
+    __asm__ __volatile__(
+        "sub sp, sp, #48\n\t"          // Reserve stack space, 16B aligned
+        "stp xzr, x1, [sp]\n\t"        // nullptr(end of quick stack), x1
+        "stp x2, x18, [sp, #16]\n\t"   // Save x2, x18(xSELF)
+        "str x30, [sp, #32]\n\t"       // Save xLR
+        "mov x0, %[arg0]\n\t"          // Set arg0-arg2
+        "mov x1, %[arg1]\n\t"          // TODO: Any way to use constraints like on x86?
+        "mov x2, %[arg2]\n\t"
+        // Use r18 last as we don't know whether it was used for arg0-arg2
+        "mov x18, %[self]\n\t"         // Set the thread
+        "blr %[code]\n\t"              // Call the stub
+        "ldp x1, x2, [sp, #8]\n\t"     // Restore x1, x2
+        "ldp x18, x30, [sp, #24]\n\t"  // Restore xSELF, xLR
+        "add sp, sp, #48\n\t"          // Free stack space
+        "mov %[result], x0\n\t"        // Save the result
+        : [result] "=r" (result)
+          // Use the result from r0
+        : [arg0] "0"(arg0), [arg1] "r"(arg1), [arg2] "r"(arg2), [code] "r"(code), [self] "r"(self)
+        : "x8", "x9", "x10", "x11", "x12", "x13", "x14", "x15", "x16", "x17");  // clobber.
+#elif defined(__x86_64__)
+    // Note: Uses the native convention
+    // TODO: Set the thread?
+    __asm__ __volatile__(
+        "pushq $0\n\t"                 // Push nullptr to terminate quick stack
+        "pushq $0\n\t"                 // 16B alignment padding
+        "call *%%rax\n\t"              // Call the stub
+        "addq $16, %%rsp"              // Pop nullptr and padding
+        : "=a" (result)
+          // Use the result from rax
+        : "D"(arg0), "S"(arg1), "d"(arg2), "a"(code)
+          // This places arg0 into rdi, arg1 into rsi, arg2 into rdx, and code into rax
+        : "rcx", "rbp", "r8", "r9", "r10", "r11", "r12", "r13", "r14", "r15");  // clobber all
+    // TODO: Should we clobber the other registers?
+    result = 0;
+#else
+    LOG(WARNING) << "Was asked to invoke for an architecture I do not understand.";
+    result = 0;
+#endif
+    // Pop transition.
+    self->PopManagedStackFragment(fragment);
+    return result;
+  }
+};
+
+
+#if defined(__i386__) || defined(__x86_64__)
+extern "C" void art_quick_memcpy(void);
+#endif
+
+TEST_F(StubTest, Memcpy) {
+#if defined(__i386__) || defined(__x86_64__)
+  Thread* self = Thread::Current();
+
+  uint32_t orig[20];
+  uint32_t trg[20];
+  for (size_t i = 0; i < 20; ++i) {
+    orig[i] = i;
+    trg[i] = 0;
+  }
+
+  Invoke3(reinterpret_cast<size_t>(&trg[4]), reinterpret_cast<size_t>(&orig[4]),
+          10 * sizeof(uint32_t), reinterpret_cast<uintptr_t>(&art_quick_memcpy), self);
+
+  EXPECT_EQ(orig[0], trg[0]);
+
+  for (size_t i = 1; i < 4; ++i) {
+    EXPECT_NE(orig[i], trg[i]);
+  }
+
+  for (size_t i = 4; i < 14; ++i) {
+    EXPECT_EQ(orig[i], trg[i]);
+  }
+
+  for (size_t i = 14; i < 20; ++i) {
+    EXPECT_NE(orig[i], trg[i]);
+  }
+
+  // TODO: Test overlapping?
+
+#else
+  LOG(INFO) << "Skipping memcpy as I don't know how to do that on " << kRuntimeISA;
+  // Force-print to std::cout so it's also outside the logcat.
+  std::cout << "Skipping memcpy as I don't know how to do that on " << kRuntimeISA << std::endl;
+#endif
+}
+
+
+#if defined(__i386__) || defined(__arm__)
+extern "C" void art_quick_lock_object(void);
+#endif
+
+TEST_F(StubTest, LockObject) {
+#if defined(__i386__) || defined(__arm__)
+  Thread* self = Thread::Current();
+  // Create an object
+  ScopedObjectAccess soa(self);
+  // garbage is created during ClassLinker::Init
+
+  SirtRef<mirror::String> obj(soa.Self(),
+                              mirror::String::AllocFromModifiedUtf8(soa.Self(), "hello, world!"));
+  LockWord lock = obj->GetLockWord(false);
+  LockWord::LockState old_state = lock.GetState();
+  EXPECT_EQ(LockWord::LockState::kUnlocked, old_state);
+
+  Invoke3(reinterpret_cast<size_t>(obj.get()), 0U, 0U,
+          reinterpret_cast<uintptr_t>(&art_quick_lock_object), self);
+
+  LockWord lock_after = obj->GetLockWord(false);
+  LockWord::LockState new_state = lock_after.GetState();
+  EXPECT_EQ(LockWord::LockState::kThinLocked, new_state);
+
+  Invoke3(reinterpret_cast<size_t>(obj.get()), 0U, 0U,
+          reinterpret_cast<uintptr_t>(&art_quick_lock_object), self);
+
+  LockWord lock_after2 = obj->GetLockWord(false);
+  LockWord::LockState new_state2 = lock_after2.GetState();
+  EXPECT_EQ(LockWord::LockState::kThinLocked, new_state2);
+
+  // TODO: Improve this test. Somehow force it to go to fat locked. But that needs another thread.
+
+#else
+  LOG(INFO) << "Skipping lock_object as I don't know how to do that on " << kRuntimeISA;
+  // Force-print to std::cout so it's also outside the logcat.
+  std::cout << "Skipping lock_object as I don't know how to do that on " << kRuntimeISA << std::endl;
+#endif
+}
+
+
+#if defined(__i386__) || defined(__arm__) || defined(__aarch64__) || defined(__x86_64__)
+extern "C" void art_quick_check_cast(void);
+#endif
+
+TEST_F(StubTest, CheckCast) {
+#if defined(__i386__) || defined(__arm__) || defined(__aarch64__) || defined(__x86_64__)
+  Thread* self = Thread::Current();
+  // Find some classes.
+  ScopedObjectAccess soa(self);
+  // garbage is created during ClassLinker::Init
+
+  SirtRef<mirror::Class> c(soa.Self(), class_linker_->FindSystemClass(soa.Self(),
+                                                                          "[Ljava/lang/Object;"));
+  SirtRef<mirror::Class> c2(soa.Self(), class_linker_->FindSystemClass(soa.Self(),
+                                                                            "[Ljava/lang/String;"));
+
+  EXPECT_FALSE(self->IsExceptionPending());
+
+  Invoke3(reinterpret_cast<size_t>(c.get()), reinterpret_cast<size_t>(c.get()), 0U,
+          reinterpret_cast<uintptr_t>(&art_quick_check_cast), self);
+
+  EXPECT_FALSE(self->IsExceptionPending());
+
+  Invoke3(reinterpret_cast<size_t>(c2.get()), reinterpret_cast<size_t>(c2.get()), 0U,
+          reinterpret_cast<uintptr_t>(&art_quick_check_cast), self);
+
+  EXPECT_FALSE(self->IsExceptionPending());
+
+  Invoke3(reinterpret_cast<size_t>(c.get()), reinterpret_cast<size_t>(c2.get()), 0U,
+          reinterpret_cast<uintptr_t>(&art_quick_check_cast), self);
+
+  EXPECT_FALSE(self->IsExceptionPending());
+
+  // TODO: Make the following work. But that would require correct managed frames.
+
+  Invoke3(reinterpret_cast<size_t>(c2.get()), reinterpret_cast<size_t>(c.get()), 0U,
+          reinterpret_cast<uintptr_t>(&art_quick_check_cast), self);
+
+  EXPECT_TRUE(self->IsExceptionPending());
+  self->ClearException();
+
+#else
+  LOG(INFO) << "Skipping check_cast as I don't know how to do that on " << kRuntimeISA;
+  // Force-print to std::cout so it's also outside the logcat.
+  std::cout << "Skipping check_cast as I don't know how to do that on " << kRuntimeISA << std::endl;
+#endif
+}
+
+
+#if defined(__i386__) || defined(__arm__)
+extern "C" void art_quick_aput_obj_with_null_and_bound_check(void);
+// Do not check non-checked ones, we'd need handlers and stuff...
+#endif
+
+TEST_F(StubTest, APutObj) {
+#if defined(__i386__) || defined(__arm__)
+  Thread* self = Thread::Current();
+  // Create an object
+  ScopedObjectAccess soa(self);
+  // garbage is created during ClassLinker::Init
+
+  SirtRef<mirror::Class> c(soa.Self(), class_linker_->FindSystemClass(soa.Self(),
+                                                                            "Ljava/lang/Object;"));
+  SirtRef<mirror::Class> c2(soa.Self(), class_linker_->FindSystemClass(soa.Self(),
+                                                                            "Ljava/lang/String;"));
+  SirtRef<mirror::Class> ca(soa.Self(), class_linker_->FindSystemClass(soa.Self(),
+                                                                            "[Ljava/lang/String;"));
+
+  // Build a string array of size 1
+  SirtRef<mirror::ObjectArray<mirror::Object> > array(soa.Self(),
+            mirror::ObjectArray<mirror::Object>::Alloc(soa.Self(), ca.get(), 1));
+
+  // Build a string -> should be assignable
+  SirtRef<mirror::Object> str_obj(soa.Self(),
+                                  mirror::String::AllocFromModifiedUtf8(soa.Self(), "hello, world!"));
+
+  // Build a generic object -> should fail assigning
+  SirtRef<mirror::Object> obj_obj(soa.Self(), c->AllocObject(soa.Self()));
+
+  // Play with it...
+
+  // 1) Success cases
+  // 1.1) Assign str_obj to array[0]
+
+  EXPECT_FALSE(self->IsExceptionPending());
+
+  Invoke3(reinterpret_cast<size_t>(array.get()), 0U, reinterpret_cast<size_t>(str_obj.get()),
+          reinterpret_cast<uintptr_t>(&art_quick_aput_obj_with_null_and_bound_check), self);
+
+  EXPECT_FALSE(self->IsExceptionPending());
+
+  // 1.2) Assign null to array[0]
+
+  Invoke3(reinterpret_cast<size_t>(array.get()), 0U, reinterpret_cast<size_t>(nullptr),
+          reinterpret_cast<uintptr_t>(&art_quick_aput_obj_with_null_and_bound_check), self);
+
+  EXPECT_FALSE(self->IsExceptionPending());
+
+  // TODO: Check _which_ exception is thrown. Then make 3) check that it's the right check order.
+
+  // 2) Failure cases (str into str[])
+  // 2.1) Array = null
+  // TODO: Throwing NPE needs actual DEX code
+
+//  Invoke3(reinterpret_cast<size_t>(nullptr), 0U, reinterpret_cast<size_t>(str_obj.get()),
+//          reinterpret_cast<uintptr_t>(&art_quick_aput_obj_with_null_and_bound_check), self);
+//
+//  EXPECT_TRUE(self->IsExceptionPending());
+//  self->ClearException();
+
+  // 2.2) Index < 0
+
+  Invoke3(reinterpret_cast<size_t>(array.get()), static_cast<size_t>(-1),
+          reinterpret_cast<size_t>(str_obj.get()),
+          reinterpret_cast<uintptr_t>(&art_quick_aput_obj_with_null_and_bound_check), self);
+
+  EXPECT_TRUE(self->IsExceptionPending());
+  self->ClearException();
+
+  // 2.3) Index > 0
+
+  Invoke3(reinterpret_cast<size_t>(array.get()), 1U, reinterpret_cast<size_t>(str_obj.get()),
+          reinterpret_cast<uintptr_t>(&art_quick_aput_obj_with_null_and_bound_check), self);
+
+  EXPECT_TRUE(self->IsExceptionPending());
+  self->ClearException();
+
+  // 3) Failure cases (obj into str[])
+
+  Invoke3(reinterpret_cast<size_t>(array.get()), 0U, reinterpret_cast<size_t>(obj_obj.get()),
+          reinterpret_cast<uintptr_t>(&art_quick_aput_obj_with_null_and_bound_check), self);
+
+  EXPECT_TRUE(self->IsExceptionPending());
+  self->ClearException();
+
+  // Tests done.
+#else
+  LOG(INFO) << "Skipping aput_obj as I don't know how to do that on " << kRuntimeISA;
+  // Force-print to std::cout so it's also outside the logcat.
+  std::cout << "Skipping aput_obj as I don't know how to do that on " << kRuntimeISA << std::endl;
+#endif
+}
+
+}  // namespace art
diff --git a/runtime/arch/x86/asm_support_x86.S b/runtime/arch/x86/asm_support_x86.S
index e329530..642d9a3 100644
--- a/runtime/arch/x86/asm_support_x86.S
+++ b/runtime/arch/x86/asm_support_x86.S
@@ -19,8 +19,8 @@
 
 #include "asm_support_x86.h"
 
-#if defined(__clang__)
-    // Clang's as(1) doesn't let you name macro parameters.
+#if defined(__clang__) && (__clang_major__ < 4) && (__clang_minor__ < 5)
+    // Clang's as(1) doesn't let you name macro parameters prior to 3.5.
     #define MACRO0(macro_name) .macro macro_name
     #define MACRO1(macro_name, macro_arg1) .macro macro_name
     #define MACRO2(macro_name, macro_arg1, macro_args2) .macro macro_name
diff --git a/runtime/arch/x86/asm_support_x86.h b/runtime/arch/x86/asm_support_x86.h
index e986c41..fd5ed5a 100644
--- a/runtime/arch/x86/asm_support_x86.h
+++ b/runtime/arch/x86/asm_support_x86.h
@@ -28,4 +28,8 @@
 // Offset of field Thread::thin_lock_thread_id_ verified in InitCpu
 #define THREAD_ID_OFFSET 12
 
+#define FRAME_SIZE_SAVE_ALL_CALLEE_SAVE 32
+#define FRAME_SIZE_REFS_ONLY_CALLEE_SAVE 32
+#define FRAME_SIZE_REFS_AND_ARGS_CALLEE_SAVE 32
+
 #endif  // ART_RUNTIME_ARCH_X86_ASM_SUPPORT_X86_H_
diff --git a/runtime/arch/x86/quick_entrypoints_x86.S b/runtime/arch/x86/quick_entrypoints_x86.S
index 12460b9..339ed2e 100644
--- a/runtime/arch/x86/quick_entrypoints_x86.S
+++ b/runtime/arch/x86/quick_entrypoints_x86.S
@@ -28,6 +28,11 @@
     PUSH ebp
     subl  MACRO_LITERAL(16), %esp  // Grow stack by 4 words, bottom word will hold Method*
     CFI_ADJUST_CFA_OFFSET(16)
+    // Ugly compile-time check, but we only have the preprocessor.
+    // Last +4: implicit return address pushed on stack when caller made call.
+#if (FRAME_SIZE_SAVE_ALL_CALLEE_SAVE != 3*4 + 16 + 4)
+#error "SAVE_ALL_CALLEE_SAVE_FRAME(X86) size not as expected."
+#endif
 END_MACRO
 
     /*
@@ -40,6 +45,12 @@
     PUSH ebp
     subl  MACRO_LITERAL(16), %esp  // Grow stack by 4 words, bottom word will hold Method*
     CFI_ADJUST_CFA_OFFSET(16)
+
+    // Ugly compile-time check, but we only have the preprocessor.
+    // Last +4: implicit return address pushed on stack when caller made call.
+#if (FRAME_SIZE_REFS_ONLY_CALLEE_SAVE != 3*4 + 16 + 4)
+#error "REFS_ONLY_CALLEE_SAVE_FRAME(X86) size not as expected."
+#endif
 END_MACRO
 
 MACRO0(RESTORE_REF_ONLY_CALLEE_SAVE_FRAME)
@@ -62,6 +73,12 @@
     PUSH edx
     PUSH ecx
     PUSH eax   // Align stack, eax will be clobbered by Method*
+
+    // Ugly compile-time check, but we only have the preprocessor.
+    // Last +4: implicit return address pushed on stack when caller made call.
+#if (FRAME_SIZE_REFS_AND_ARGS_CALLEE_SAVE != 7*4 + 4)
+#error "REFS_AND_ARGS_CALLEE_SAVE_FRAME(X86) size not as expected."
+#endif
 END_MACRO
 
 MACRO0(RESTORE_REF_AND_ARGS_CALLEE_SAVE_FRAME)
diff --git a/runtime/arch/x86_64/asm_support_x86_64.S b/runtime/arch/x86_64/asm_support_x86_64.S
index a9f69f5..ad65033 100644
--- a/runtime/arch/x86_64/asm_support_x86_64.S
+++ b/runtime/arch/x86_64/asm_support_x86_64.S
@@ -19,15 +19,15 @@
 
 #include "asm_support_x86_64.h"
 
-#if defined(__clang__)
-    // Clang's as(1) doesn't let you name macro parameters.
+#if defined(__clang__) && (__clang_major__ < 4) && (__clang_minor__ < 5)
+    // Clang's as(1) doesn't let you name macro parameters prior to 3.5.
     #define MACRO0(macro_name) .macro macro_name
     #define MACRO1(macro_name, macro_arg1) .macro macro_name
     #define MACRO2(macro_name, macro_arg1, macro_args2) .macro macro_name
     #define MACRO3(macro_name, macro_arg1, macro_args2, macro_args3) .macro macro_name
     #define END_MACRO .endmacro
 
-    // Clang's as(1) uses $0, $1, and so on for macro arguments.
+    // Clang's as(1) uses $0, $1, and so on for macro arguments prior to 3.5.
     #define VAR(name,index) SYMBOL($index)
     #define PLT_VAR(name, index) SYMBOL($index)@PLT
     #define REG_VAR(name,index) %$index
diff --git a/runtime/arch/x86_64/asm_support_x86_64.h b/runtime/arch/x86_64/asm_support_x86_64.h
index 70ef3ef..109533b 100644
--- a/runtime/arch/x86_64/asm_support_x86_64.h
+++ b/runtime/arch/x86_64/asm_support_x86_64.h
@@ -35,4 +35,8 @@
 // Offset of field Thread::thin_lock_thread_id_ verified in InitCpu
 #define THREAD_ID_OFFSET 12
 
+#define FRAME_SIZE_SAVE_ALL_CALLEE_SAVE 64
+#define FRAME_SIZE_REFS_ONLY_CALLEE_SAVE 64
+#define FRAME_SIZE_REFS_AND_ARGS_CALLEE_SAVE 176
+
 #endif  // ART_RUNTIME_ARCH_X86_64_ASM_SUPPORT_X86_64_H_
diff --git a/runtime/arch/x86_64/quick_entrypoints_x86_64.S b/runtime/arch/x86_64/quick_entrypoints_x86_64.S
index 6509a9b..a31ea58 100644
--- a/runtime/arch/x86_64/quick_entrypoints_x86_64.S
+++ b/runtime/arch/x86_64/quick_entrypoints_x86_64.S
@@ -39,6 +39,12 @@
     movq RUNTIME_SAVE_ALL_CALLEE_SAVE_FRAME_OFFSET(%r10), %r10
     // Store ArtMethod* to bottom of stack.
     movq %r10, 0(%rsp)
+
+    // Ugly compile-time check, but we only have the preprocessor.
+    // Last +8: implicit return address pushed on stack when caller made call.
+#if (FRAME_SIZE_SAVE_ALL_CALLEE_SAVE != 6*8 + 8 + 8)
+#error "SAVE_ALL_CALLEE_SAVE_FRAME(X86_64) size not as expected."
+#endif
 END_MACRO
 
     /*
@@ -63,6 +69,12 @@
     movq RUNTIME_REFS_ONLY_CALLEE_SAVE_FRAME_OFFSET(%r10), %r10
     // Store ArtMethod* to bottom of stack.
     movq %r10, 0(%rsp)
+
+    // Ugly compile-time check, but we only have the preprocessor.
+    // Last +8: implicit return address pushed on stack when caller made call.
+#if (FRAME_SIZE_REFS_ONLY_CALLEE_SAVE != 6*8 + 8 + 8)
+#error "REFS_ONLY_CALLEE_SAVE_FRAME(X86_64) size not as expected."
+#endif
 END_MACRO
 
 MACRO0(RESTORE_REF_ONLY_CALLEE_SAVE_FRAME)
@@ -114,6 +126,12 @@
     movq %xmm7, 72(%rsp)
     // Store ArtMethod* to bottom of stack.
     movq %r10, 0(%rsp)
+
+    // Ugly compile-time check, but we only have the preprocessor.
+    // Last +8: implicit return address pushed on stack when caller made call.
+#if (FRAME_SIZE_REFS_AND_ARGS_CALLEE_SAVE != 11*8 + 80 + 8)
+#error "REFS_AND_ARGS_CALLEE_SAVE_FRAME(X86_64) size not as expected."
+#endif
 END_MACRO
 
 MACRO0(RESTORE_REF_AND_ARGS_CALLEE_SAVE_FRAME)
@@ -666,8 +684,22 @@
 END_FUNCTION art_quick_is_assignable
 
 DEFINE_FUNCTION art_quick_check_cast
-    int3
-    int3
+    PUSH rdi                          // Save args for exc
+    PUSH rsi
+    call PLT_SYMBOL(artIsAssignableFromCode)  // (Class* klass, Class* ref_klass)
+    testq %rax, %rax
+    jz 1f                             // jump forward if not assignable
+    addq LITERAL(16), %rsp            // pop arguments
+    CFI_ADJUST_CFA_OFFSET(-16)
+    ret
+1:
+    POP rsi                           // Pop arguments
+    POP rdi
+    SETUP_SAVE_ALL_CALLEE_SAVE_FRAME  // save all registers as basis for long jump context
+    mov %rsp, %rcx                    // pass SP
+    mov %gs:THREAD_SELF_OFFSET, %rdx  // pass Thread::Current()
+    call PLT_SYMBOL(artThrowClassCastException) // (Class* a, Class* b, Thread*, SP)
+    int3                              // unreached
 END_FUNCTION art_quick_check_cast
 
     /*
@@ -678,7 +710,12 @@
 UNIMPLEMENTED art_quick_aput_obj_with_null_and_bound_check
 UNIMPLEMENTED art_quick_aput_obj_with_bound_check
 UNIMPLEMENTED art_quick_aput_obj
-UNIMPLEMENTED art_quick_memcpy
+
+// TODO: This is quite silly on X86_64 now.
+DEFINE_FUNCTION art_quick_memcpy
+    call PLT_SYMBOL(memcpy)       // (void*, const void*, size_t)
+    ret
+END_FUNCTION art_quick_memcpy
 
 NO_ARG_DOWNCALL art_quick_test_suspend, artTestSuspendFromCode, ret
 
diff --git a/runtime/base/mutex.cc b/runtime/base/mutex.cc
index fdd0249..2bc17bf 100644
--- a/runtime/base/mutex.cc
+++ b/runtime/base/mutex.cc
@@ -206,16 +206,16 @@
       os << "never contended";
     } else {
       os << "contended " << contention_count
-         << " times, average wait of contender " << PrettyDuration(wait_time / contention_count);
+         << " total wait of contender " << PrettyDuration(wait_time)
+         << " average " << PrettyDuration(wait_time / contention_count);
       SafeMap<uint64_t, size_t> most_common_blocker;
       SafeMap<uint64_t, size_t> most_common_blocked;
-      typedef SafeMap<uint64_t, size_t>::const_iterator It;
       for (size_t i = 0; i < kContentionLogSize; ++i) {
         uint64_t blocked_tid = log[i].blocked_tid;
         uint64_t owner_tid = log[i].owner_tid;
         uint32_t count = log[i].count;
         if (count > 0) {
-          It it = most_common_blocked.find(blocked_tid);
+          auto it = most_common_blocked.find(blocked_tid);
           if (it != most_common_blocked.end()) {
             most_common_blocked.Overwrite(blocked_tid, it->second + count);
           } else {
@@ -231,10 +231,10 @@
       }
       uint64_t max_tid = 0;
       size_t max_tid_count = 0;
-      for (It it = most_common_blocked.begin(); it != most_common_blocked.end(); ++it) {
-        if (it->second > max_tid_count) {
-          max_tid = it->first;
-          max_tid_count = it->second;
+      for (const auto& pair : most_common_blocked) {
+        if (pair.second > max_tid_count) {
+          max_tid = pair.first;
+          max_tid_count = pair.second;
         }
       }
       if (max_tid != 0) {
@@ -242,10 +242,10 @@
       }
       max_tid = 0;
       max_tid_count = 0;
-      for (It it = most_common_blocker.begin(); it != most_common_blocker.end(); ++it) {
-        if (it->second > max_tid_count) {
-          max_tid = it->first;
-          max_tid_count = it->second;
+      for (const auto& pair : most_common_blocker) {
+        if (pair.second > max_tid_count) {
+          max_tid = pair.first;
+          max_tid_count = pair.second;
         }
       }
       if (max_tid != 0) {
diff --git a/runtime/catch_block_stack_visitor.cc b/runtime/catch_block_stack_visitor.cc
index 410fff9..8d10a97 100644
--- a/runtime/catch_block_stack_visitor.cc
+++ b/runtime/catch_block_stack_visitor.cc
@@ -17,27 +17,26 @@
 #include "catch_block_stack_visitor.h"
 
 #include "dex_instruction.h"
-#include "catch_finder.h"
+#include "mirror/art_method-inl.h"
+#include "quick_exception_handler.h"
 #include "sirt_ref.h"
 #include "verifier/method_verifier.h"
 
 namespace art {
 
 bool CatchBlockStackVisitor::VisitFrame() {
-  catch_finder_->SetHandlerFrameId(GetFrameId());
+  exception_handler_->SetHandlerFrameId(GetFrameId());
   mirror::ArtMethod* method = GetMethod();
   if (method == nullptr) {
     // This is the upcall, we remember the frame and last pc so that we may long jump to them.
-    catch_finder_->SetHandlerQuickFramePc(GetCurrentQuickFramePc());
-    catch_finder_->SetHandlerQuickFrame(GetCurrentQuickFrame());
+    exception_handler_->SetHandlerQuickFramePc(GetCurrentQuickFramePc());
+    exception_handler_->SetHandlerQuickFrame(GetCurrentQuickFrame());
     return false;  // End stack walk.
   } else {
     if (method->IsRuntimeMethod()) {
       // Ignore callee save method.
       DCHECK(method->IsCalleeSaveMethod());
       return true;
-    } else if (is_deoptimization_) {
-      return HandleDeoptimization(method);
     } else {
       return HandleTryItems(method);
     }
@@ -46,68 +45,21 @@
 
 bool CatchBlockStackVisitor::HandleTryItems(mirror::ArtMethod* method) {
   uint32_t dex_pc = DexFile::kDexNoIndex;
-  if (method->IsNative()) {
-    ++native_method_count_;
-  } else {
+  if (!method->IsNative()) {
     dex_pc = GetDexPc();
   }
   if (dex_pc != DexFile::kDexNoIndex) {
     bool clear_exception = false;
-    SirtRef<mirror::Class> sirt_method_to_find(Thread::Current(), to_find_);
-    uint32_t found_dex_pc = method->FindCatchBlock(sirt_method_to_find, dex_pc, &clear_exception);
-    to_find_ = sirt_method_to_find.get();
-    catch_finder_->SetClearException(clear_exception);
+    uint32_t found_dex_pc = method->FindCatchBlock(to_find_, dex_pc, &clear_exception);
+    exception_handler_->SetClearException(clear_exception);
     if (found_dex_pc != DexFile::kDexNoIndex) {
-      catch_finder_->SetHandlerDexPc(found_dex_pc);
-      catch_finder_->SetHandlerQuickFramePc(method->ToNativePc(found_dex_pc));
-      catch_finder_->SetHandlerQuickFrame(GetCurrentQuickFrame());
+      exception_handler_->SetHandlerDexPc(found_dex_pc);
+      exception_handler_->SetHandlerQuickFramePc(method->ToNativePc(found_dex_pc));
+      exception_handler_->SetHandlerQuickFrame(GetCurrentQuickFrame());
       return false;  // End stack walk.
     }
   }
   return true;  // Continue stack walk.
 }
 
-bool CatchBlockStackVisitor::HandleDeoptimization(mirror::ArtMethod* m) {
-  MethodHelper mh(m);
-  const DexFile::CodeItem* code_item = mh.GetCodeItem();
-  CHECK(code_item != nullptr);
-  uint16_t num_regs = code_item->registers_size_;
-  uint32_t dex_pc = GetDexPc();
-  const Instruction* inst = Instruction::At(code_item->insns_ + dex_pc);
-  uint32_t new_dex_pc = dex_pc + inst->SizeInCodeUnits();
-  ShadowFrame* new_frame = ShadowFrame::Create(num_regs, nullptr, m, new_dex_pc);
-  SirtRef<mirror::DexCache> dex_cache(self_, mh.GetDexCache());
-  SirtRef<mirror::ClassLoader> class_loader(self_, mh.GetClassLoader());
-  verifier::MethodVerifier verifier(&mh.GetDexFile(), &dex_cache, &class_loader,
-                                    &mh.GetClassDef(), code_item, m->GetDexMethodIndex(), m,
-                                    m->GetAccessFlags(), false, true);
-  verifier.Verify();
-  std::vector<int32_t> kinds = verifier.DescribeVRegs(dex_pc);
-  for (uint16_t reg = 0; reg < num_regs; ++reg) {
-    VRegKind kind = static_cast<VRegKind>(kinds.at(reg * 2));
-    switch (kind) {
-      case kUndefined:
-        new_frame->SetVReg(reg, 0xEBADDE09);
-        break;
-      case kConstant:
-        new_frame->SetVReg(reg, kinds.at((reg * 2) + 1));
-        break;
-      case kReferenceVReg:
-        new_frame->SetVRegReference(reg,
-                                    reinterpret_cast<mirror::Object*>(GetVReg(m, reg, kind)));
-        break;
-      default:
-        new_frame->SetVReg(reg, GetVReg(m, reg, kind));
-        break;
-    }
-  }
-  if (prev_shadow_frame_ != nullptr) {
-    prev_shadow_frame_->SetLink(new_frame);
-  } else {
-    catch_finder_->SetTopShadowFrame(new_frame);
-  }
-  prev_shadow_frame_ = new_frame;
-  return true;
-}
-
 }  // namespace art
diff --git a/runtime/catch_block_stack_visitor.h b/runtime/catch_block_stack_visitor.h
index ce67e27..6f0fe11 100644
--- a/runtime/catch_block_stack_visitor.h
+++ b/runtime/catch_block_stack_visitor.h
@@ -17,39 +17,39 @@
 #ifndef ART_RUNTIME_CATCH_BLOCK_STACK_VISITOR_H_
 #define ART_RUNTIME_CATCH_BLOCK_STACK_VISITOR_H_
 
-#include "mirror/throwable.h"
-#include "thread.h"
+#include "mirror/object-inl.h"
+#include "stack.h"
+#include "sirt_ref-inl.h"
 
 namespace art {
-class CatchFinder;
+
+namespace mirror {
+class Throwable;
+}  // namespace mirror
+class Context;
+class QuickExceptionHandler;
+class Thread;
 class ThrowLocation;
 
 // Finds catch handler or prepares deoptimization.
-class CatchBlockStackVisitor : public StackVisitor {
+class CatchBlockStackVisitor FINAL : public StackVisitor {
  public:
-  CatchBlockStackVisitor(Thread* self, Context* context, mirror::Throwable* exception,
-                         bool is_deoptimization, CatchFinder* catch_finder)
+  CatchBlockStackVisitor(Thread* self, Context* context, SirtRef<mirror::Throwable>& exception,
+                         QuickExceptionHandler* exception_handler)
       SHARED_LOCKS_REQUIRED(Locks::mutator_lock_)
-      : StackVisitor(self, context),
-        self_(self), is_deoptimization_(is_deoptimization),
-        to_find_(is_deoptimization ? nullptr : exception->GetClass()),
-        catch_finder_(catch_finder), native_method_count_(0), prev_shadow_frame_(nullptr) {
+      : StackVisitor(self, context), self_(self), to_find_(self, exception->GetClass()),
+        exception_handler_(exception_handler) {
   }
 
-  bool VisitFrame() SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
+  bool VisitFrame() OVERRIDE SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
 
  private:
   bool HandleTryItems(mirror::ArtMethod* method) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
-  bool HandleDeoptimization(mirror::ArtMethod* m) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
 
   Thread* const self_;
-  const bool is_deoptimization_;
   // The type of the exception catch block to find.
-  mirror::Class* to_find_;
-  CatchFinder* const catch_finder_;
-  // Number of native methods passed in crawl (equates to number of SIRTs to pop)
-  uint32_t native_method_count_;
-  ShadowFrame* prev_shadow_frame_;
+  SirtRef<mirror::Class> to_find_;
+  QuickExceptionHandler* const exception_handler_;
 
   DISALLOW_COPY_AND_ASSIGN(CatchBlockStackVisitor);
 };
diff --git a/runtime/class_linker.cc b/runtime/class_linker.cc
index 58b82f0..338133c 100644
--- a/runtime/class_linker.cc
+++ b/runtime/class_linker.cc
@@ -185,7 +185,8 @@
       quick_resolution_trampoline_(nullptr),
       portable_imt_conflict_trampoline_(nullptr),
       quick_imt_conflict_trampoline_(nullptr),
-      quick_generic_jni_trampoline_(nullptr) {
+      quick_generic_jni_trampoline_(nullptr),
+      quick_to_interpreter_bridge_trampoline_(nullptr) {
   CHECK_EQ(arraysize(class_roots_descriptors_), size_t(kClassRootsMax));
   memset(find_array_class_cache_, 0, kFindArrayCacheSize * sizeof(mirror::Class*));
 }
@@ -1002,6 +1003,7 @@
   portable_imt_conflict_trampoline_ = oat_file.GetOatHeader().GetPortableImtConflictTrampoline();
   quick_imt_conflict_trampoline_ = oat_file.GetOatHeader().GetQuickImtConflictTrampoline();
   quick_generic_jni_trampoline_ = oat_file.GetOatHeader().GetQuickGenericJniTrampoline();
+  quick_to_interpreter_bridge_trampoline_ = oat_file.GetOatHeader().GetQuickToInterpreterBridge();
   mirror::Object* dex_caches_object = space->GetImageHeader().GetImageRoot(ImageHeader::kDexCaches);
   mirror::ObjectArray<mirror::DexCache>* dex_caches =
       dex_caches_object->AsObjectArray<mirror::DexCache>();
diff --git a/runtime/class_linker.h b/runtime/class_linker.h
index a14d1d1..9771318 100644
--- a/runtime/class_linker.h
+++ b/runtime/class_linker.h
@@ -369,6 +369,10 @@
     return quick_imt_conflict_trampoline_;
   }
 
+  const void* GetQuickToInterpreterBridgeTrampoline() const {
+    return quick_to_interpreter_bridge_trampoline_;
+  }
+
   InternTable* GetInternTable() const {
     return intern_table_;
   }
@@ -658,6 +662,7 @@
   const void* portable_imt_conflict_trampoline_;
   const void* quick_imt_conflict_trampoline_;
   const void* quick_generic_jni_trampoline_;
+  const void* quick_to_interpreter_bridge_trampoline_;
 
   friend class ImageWriter;  // for GetClassRoots
   FRIEND_TEST(ClassLinkerTest, ClassRootDescriptors);
diff --git a/runtime/class_linker_test.cc b/runtime/class_linker_test.cc
index 5b72a44..1218357 100644
--- a/runtime/class_linker_test.cc
+++ b/runtime/class_linker_test.cc
@@ -485,8 +485,6 @@
     offsets.push_back(CheckOffset(OFFSETOF_MEMBER(mirror::ArtMethod, entry_point_from_portable_compiled_code_), "entryPointFromPortableCompiledCode"));
     offsets.push_back(CheckOffset(OFFSETOF_MEMBER(mirror::ArtMethod, entry_point_from_quick_compiled_code_),    "entryPointFromQuickCompiledCode"));
     offsets.push_back(CheckOffset(OFFSETOF_MEMBER(mirror::ArtMethod, gc_map_),                                  "gcMap"));
-    offsets.push_back(CheckOffset(OFFSETOF_MEMBER(mirror::ArtMethod, quick_mapping_table_),                     "quickMappingTable"));
-    offsets.push_back(CheckOffset(OFFSETOF_MEMBER(mirror::ArtMethod, quick_vmap_table_),                        "quickVmapTable"));
 
     // alphabetical 32-bit
     offsets.push_back(CheckOffset(OFFSETOF_MEMBER(mirror::ArtMethod, access_flags_),                   "accessFlags"));
diff --git a/runtime/deoptimize_stack_visitor.cc b/runtime/deoptimize_stack_visitor.cc
new file mode 100644
index 0000000..f2eaf00
--- /dev/null
+++ b/runtime/deoptimize_stack_visitor.cc
@@ -0,0 +1,87 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "deoptimize_stack_visitor.h"
+
+#include "mirror/art_method-inl.h"
+#include "object_utils.h"
+#include "quick_exception_handler.h"
+#include "sirt_ref-inl.h"
+#include "verifier/method_verifier.h"
+
+namespace art {
+
+bool DeoptimizeStackVisitor::VisitFrame() {
+  exception_handler_->SetHandlerFrameId(GetFrameId());
+  mirror::ArtMethod* method = GetMethod();
+  if (method == nullptr) {
+    // This is the upcall, we remember the frame and last pc so that we may long jump to them.
+    exception_handler_->SetHandlerQuickFramePc(GetCurrentQuickFramePc());
+    exception_handler_->SetHandlerQuickFrame(GetCurrentQuickFrame());
+    return false;  // End stack walk.
+  } else if (method->IsRuntimeMethod()) {
+    // Ignore callee save method.
+    DCHECK(method->IsCalleeSaveMethod());
+    return true;
+  } else {
+    return HandleDeoptimization(method);
+  }
+}
+
+bool DeoptimizeStackVisitor::HandleDeoptimization(mirror::ArtMethod* m) {
+  MethodHelper mh(m);
+  const DexFile::CodeItem* code_item = mh.GetCodeItem();
+  CHECK(code_item != nullptr);
+  uint16_t num_regs = code_item->registers_size_;
+  uint32_t dex_pc = GetDexPc();
+  const Instruction* inst = Instruction::At(code_item->insns_ + dex_pc);
+  uint32_t new_dex_pc = dex_pc + inst->SizeInCodeUnits();
+  ShadowFrame* new_frame = ShadowFrame::Create(num_regs, nullptr, m, new_dex_pc);
+  SirtRef<mirror::DexCache> dex_cache(self_, mh.GetDexCache());
+  SirtRef<mirror::ClassLoader> class_loader(self_, mh.GetClassLoader());
+  verifier::MethodVerifier verifier(&mh.GetDexFile(), &dex_cache, &class_loader,
+                                    &mh.GetClassDef(), code_item, m->GetDexMethodIndex(), m,
+                                    m->GetAccessFlags(), false, true);
+  verifier.Verify();
+  std::vector<int32_t> kinds = verifier.DescribeVRegs(dex_pc);
+  for (uint16_t reg = 0; reg < num_regs; ++reg) {
+    VRegKind kind = static_cast<VRegKind>(kinds.at(reg * 2));
+    switch (kind) {
+      case kUndefined:
+        new_frame->SetVReg(reg, 0xEBADDE09);
+        break;
+      case kConstant:
+        new_frame->SetVReg(reg, kinds.at((reg * 2) + 1));
+        break;
+      case kReferenceVReg:
+        new_frame->SetVRegReference(reg,
+                                    reinterpret_cast<mirror::Object*>(GetVReg(m, reg, kind)));
+        break;
+      default:
+        new_frame->SetVReg(reg, GetVReg(m, reg, kind));
+        break;
+    }
+  }
+  if (prev_shadow_frame_ != nullptr) {
+    prev_shadow_frame_->SetLink(new_frame);
+  } else {
+    exception_handler_->SetTopShadowFrame(new_frame);
+  }
+  prev_shadow_frame_ = new_frame;
+  return true;
+}
+
+}  // namespace art
diff --git a/runtime/deoptimize_stack_visitor.h b/runtime/deoptimize_stack_visitor.h
new file mode 100644
index 0000000..c898e7d
--- /dev/null
+++ b/runtime/deoptimize_stack_visitor.h
@@ -0,0 +1,53 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef ART_RUNTIME_DEOPTIMIZE_STACK_VISITOR_H_
+#define ART_RUNTIME_DEOPTIMIZE_STACK_VISITOR_H_
+
+#include "base/mutex.h"
+#include "stack.h"
+
+namespace art {
+
+namespace mirror {
+class ArtMethod;
+}  // namespace mirror
+class QuickExceptionHandler;
+class Thread;
+
+// Prepares deoptimization.
+class DeoptimizeStackVisitor FINAL : public StackVisitor {
+ public:
+  DeoptimizeStackVisitor(Thread* self, Context* context, QuickExceptionHandler* exception_handler)
+      SHARED_LOCKS_REQUIRED(Locks::mutator_lock_)
+      : StackVisitor(self, context), self_(self), exception_handler_(exception_handler),
+        prev_shadow_frame_(nullptr) {
+  }
+
+  bool VisitFrame() OVERRIDE SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
+
+ private:
+  bool HandleDeoptimization(mirror::ArtMethod* m) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
+
+  Thread* const self_;
+  QuickExceptionHandler* const exception_handler_;
+  ShadowFrame* prev_shadow_frame_;
+
+  DISALLOW_COPY_AND_ASSIGN(DeoptimizeStackVisitor);
+};
+
+}  // namespace art
+#endif  // ART_RUNTIME_DEOPTIMIZE_STACK_VISITOR_H_
diff --git a/runtime/entrypoints/entrypoint_utils.h b/runtime/entrypoints/entrypoint_utils.h
index 8b48b36..05912bf 100644
--- a/runtime/entrypoints/entrypoint_utils.h
+++ b/runtime/entrypoints/entrypoint_utils.h
@@ -761,6 +761,10 @@
   return class_linker->GetQuickGenericJniTrampoline();
 }
 
+static inline const void* GetQuickToInterpreterBridgeTrampoline(ClassLinker* class_linker) {
+  return class_linker->GetQuickToInterpreterBridgeTrampoline();
+}
+
 extern "C" void art_portable_proxy_invoke_handler();
 static inline const void* GetPortableProxyInvokeHandler() {
   return reinterpret_cast<void*>(art_portable_proxy_invoke_handler);
diff --git a/runtime/entrypoints/quick/quick_deoptimization_entrypoints.cc b/runtime/entrypoints/quick/quick_deoptimization_entrypoints.cc
index 51c647a..6448045 100644
--- a/runtime/entrypoints/quick/quick_deoptimization_entrypoints.cc
+++ b/runtime/entrypoints/quick/quick_deoptimization_entrypoints.cc
@@ -31,7 +31,7 @@
 extern "C" void artDeoptimize(Thread* self, mirror::ArtMethod** sp)
     SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
   FinishCalleeSaveFrameSetup(self, sp, Runtime::kSaveAll);
-  self->SetException(ThrowLocation(), reinterpret_cast<mirror::Throwable*>(-1));
+  self->SetException(ThrowLocation(), Thread::GetDeoptimizationException());
   self->QuickDeliverException();
 }
 
diff --git a/runtime/entrypoints/quick/quick_instrumentation_entrypoints.cc b/runtime/entrypoints/quick/quick_instrumentation_entrypoints.cc
index 633f580..60c5377 100644
--- a/runtime/entrypoints/quick/quick_instrumentation_entrypoints.cc
+++ b/runtime/entrypoints/quick/quick_instrumentation_entrypoints.cc
@@ -32,6 +32,7 @@
   FinishCalleeSaveFrameSetup(self, sp, Runtime::kRefsAndArgs);
   instrumentation::Instrumentation* instrumentation = Runtime::Current()->GetInstrumentation();
   const void* result = instrumentation->GetQuickCodeFor(method);
+  DCHECK(result != GetQuickToInterpreterBridgeTrampoline(Runtime::Current()->GetClassLinker()));
   bool interpreter_entry = (result == GetQuickToInterpreterBridge());
   instrumentation->PushInstrumentationStackFrame(self, method->IsStatic() ? NULL : this_object,
                                                  method, lr, interpreter_entry);
diff --git a/runtime/exception_test.cc b/runtime/exception_test.cc
index 208eb74..97a8367 100644
--- a/runtime/exception_test.cc
+++ b/runtime/exception_test.cc
@@ -49,10 +49,6 @@
     dex_ = my_klass_->GetDexCache()->GetDexFile();
 
     uint32_t code_size = 12;
-    fake_code_.push_back((code_size >> 24) & 0xFF);
-    fake_code_.push_back((code_size >> 16) & 0xFF);
-    fake_code_.push_back((code_size >>  8) & 0xFF);
-    fake_code_.push_back((code_size >>  0) & 0xFF);
     for (size_t i = 0 ; i < code_size; i++) {
       fake_code_.push_back(0x70 | i);
     }
@@ -74,20 +70,35 @@
     fake_gc_map_.push_back(0);  // 0 entries.
     fake_gc_map_.push_back(0);
 
+    const std::vector<uint8_t>& fake_vmap_table_data = fake_vmap_table_data_.GetData();
+    const std::vector<uint8_t>& fake_mapping_data = fake_mapping_data_.GetData();
+    uint32_t vmap_table_offset = sizeof(OatMethodHeader) + fake_vmap_table_data.size();
+    uint32_t mapping_table_offset = vmap_table_offset + fake_mapping_data.size();
+    OatMethodHeader method_header(vmap_table_offset, mapping_table_offset, code_size);
+    fake_header_code_and_maps_.resize(sizeof(method_header));
+    memcpy(&fake_header_code_and_maps_[0], &method_header, sizeof(method_header));
+    fake_header_code_and_maps_.insert(fake_header_code_and_maps_.begin(),
+                                      fake_vmap_table_data.begin(), fake_vmap_table_data.end());
+    fake_header_code_and_maps_.insert(fake_header_code_and_maps_.begin(),
+                                      fake_mapping_data.begin(), fake_mapping_data.end());
+    fake_header_code_and_maps_.insert(fake_header_code_and_maps_.end(),
+                                      fake_code_.begin(), fake_code_.end());
+
+    // NOTE: Don't align the code (it will not be executed) but check that the Thumb2
+    // adjustment will be a NOP, see ArtMethod::EntryPointToCodePointer().
+    CHECK_EQ(mapping_table_offset & 1u, 0u);
+    const uint8_t* code_ptr = &fake_header_code_and_maps_[mapping_table_offset];
+
     method_f_ = my_klass_->FindVirtualMethod("f", "()I");
     ASSERT_TRUE(method_f_ != NULL);
     method_f_->SetFrameSizeInBytes(4 * kPointerSize);
-    method_f_->SetEntryPointFromQuickCompiledCode(&fake_code_[sizeof(code_size)]);
-    method_f_->SetMappingTable(&fake_mapping_data_.GetData()[0]);
-    method_f_->SetVmapTable(&fake_vmap_table_data_.GetData()[0]);
+    method_f_->SetEntryPointFromQuickCompiledCode(code_ptr);
     method_f_->SetNativeGcMap(&fake_gc_map_[0]);
 
     method_g_ = my_klass_->FindVirtualMethod("g", "(I)V");
     ASSERT_TRUE(method_g_ != NULL);
     method_g_->SetFrameSizeInBytes(4 * kPointerSize);
-    method_g_->SetEntryPointFromQuickCompiledCode(&fake_code_[sizeof(code_size)]);
-    method_g_->SetMappingTable(&fake_mapping_data_.GetData()[0]);
-    method_g_->SetVmapTable(&fake_vmap_table_data_.GetData()[0]);
+    method_g_->SetEntryPointFromQuickCompiledCode(code_ptr);
     method_g_->SetNativeGcMap(&fake_gc_map_[0]);
   }
 
@@ -97,6 +108,7 @@
   Leb128EncodingVector fake_mapping_data_;
   Leb128EncodingVector fake_vmap_table_data_;
   std::vector<uint8_t> fake_gc_map_;
+  std::vector<uint8_t> fake_header_code_and_maps_;
 
   mirror::ArtMethod* method_f_;
   mirror::ArtMethod* method_g_;
diff --git a/runtime/gc/accounting/space_bitmap.cc b/runtime/gc/accounting/space_bitmap.cc
index 31a1537..66f9a3a 100644
--- a/runtime/gc/accounting/space_bitmap.cc
+++ b/runtime/gc/accounting/space_bitmap.cc
@@ -21,13 +21,17 @@
 namespace accounting {
 
 template<size_t kAlignment>
+size_t SpaceBitmap<kAlignment>::ComputeBitmapSize(uint64_t capacity) {
+  const uint64_t kBytesCoveredPerWord = kAlignment * kBitsPerWord;
+  return (RoundUp(capacity, kBytesCoveredPerWord) / kBytesCoveredPerWord) * kWordSize;
+}
+
+template<size_t kAlignment>
 SpaceBitmap<kAlignment>* SpaceBitmap<kAlignment>::CreateFromMemMap(
     const std::string& name, MemMap* mem_map, byte* heap_begin, size_t heap_capacity) {
   CHECK(mem_map != nullptr);
   uword* bitmap_begin = reinterpret_cast<uword*>(mem_map->Begin());
-  const uint64_t kBytesCoveredPerWord = kAlignment * kBitsPerWord;
-  size_t bitmap_size = (RoundUp(static_cast<uint64_t>(heap_capacity), kBytesCoveredPerWord) /
-      kBytesCoveredPerWord) * kWordSize;
+  const size_t bitmap_size = ComputeBitmapSize(heap_capacity);
   return new SpaceBitmap(name, mem_map, bitmap_begin, bitmap_size, heap_begin);
 }
 
@@ -45,9 +49,7 @@
 SpaceBitmap<kAlignment>* SpaceBitmap<kAlignment>::Create(
     const std::string& name, byte* heap_begin, size_t heap_capacity) {
   // Round up since heap_capacity is not necessarily a multiple of kAlignment * kBitsPerWord.
-  const uint64_t kBytesCoveredPerWord = kAlignment * kBitsPerWord;
-  size_t bitmap_size = (RoundUp(static_cast<uint64_t>(heap_capacity), kBytesCoveredPerWord) /
-      kBytesCoveredPerWord) * kWordSize;
+  const size_t bitmap_size = ComputeBitmapSize(heap_capacity);
   std::string error_msg;
   UniquePtr<MemMap> mem_map(MemMap::MapAnonymous(name.c_str(), nullptr, bitmap_size,
                                                  PROT_READ | PROT_WRITE, false, &error_msg));
diff --git a/runtime/gc/accounting/space_bitmap.h b/runtime/gc/accounting/space_bitmap.h
index df3fd37..5c7cce2 100644
--- a/runtime/gc/accounting/space_bitmap.h
+++ b/runtime/gc/accounting/space_bitmap.h
@@ -200,6 +200,9 @@
   SpaceBitmap(const std::string& name, MemMap* mem_map, uword* bitmap_begin, size_t bitmap_size,
               const void* heap_begin);
 
+  // Helper function for computing bitmap size based on a 64 bit capacity.
+  static size_t ComputeBitmapSize(uint64_t capacity);
+
   template<bool kSetBit>
   bool Modify(const mirror::Object* obj);
 
diff --git a/runtime/gc/allocator/rosalloc-inl.h b/runtime/gc/allocator/rosalloc-inl.h
index f395314..ac0f67b 100644
--- a/runtime/gc/allocator/rosalloc-inl.h
+++ b/runtime/gc/allocator/rosalloc-inl.h
@@ -29,7 +29,7 @@
   }
   void* m = AllocFromRun(self, size, bytes_allocated);
   // Check if the returned memory is really all zero.
-  if (kCheckZeroMemory && m != NULL) {
+  if (kCheckZeroMemory && m != nullptr) {
     byte* bytes = reinterpret_cast<byte*>(m);
     for (size_t i = 0; i < size; ++i) {
       DCHECK_EQ(bytes[i], 0);
diff --git a/runtime/gc/allocator/rosalloc.cc b/runtime/gc/allocator/rosalloc.cc
index 0f2d6a9..821aa2d 100644
--- a/runtime/gc/allocator/rosalloc.cc
+++ b/runtime/gc/allocator/rosalloc.cc
@@ -32,6 +32,10 @@
 
 extern "C" void* art_heap_rosalloc_morecore(RosAlloc* rosalloc, intptr_t increment);
 
+static constexpr bool kUsePrefetchDuringAllocRun = true;
+static constexpr bool kPrefetchNewRunDataByZeroing = false;
+static constexpr size_t kPrefetchStride = 64;
+
 size_t RosAlloc::bracketSizes[kNumOfSizeBrackets];
 size_t RosAlloc::numOfPages[kNumOfSizeBrackets];
 size_t RosAlloc::numOfSlots[kNumOfSizeBrackets];
@@ -39,6 +43,9 @@
 size_t RosAlloc::bulkFreeBitMapOffsets[kNumOfSizeBrackets];
 size_t RosAlloc::threadLocalFreeBitMapOffsets[kNumOfSizeBrackets];
 bool RosAlloc::initialized_ = false;
+size_t RosAlloc::dedicated_full_run_storage_[kPageSize / sizeof(size_t)] = { 0 };
+RosAlloc::Run* RosAlloc::dedicated_full_run_ =
+    reinterpret_cast<RosAlloc::Run*>(dedicated_full_run_storage_);
 
 RosAlloc::RosAlloc(void* base, size_t capacity, size_t max_capacity,
                    PageReleaseMode page_release_mode, size_t page_release_size_threshold)
@@ -62,8 +69,9 @@
              << ", max_capacity=" << std::dec << max_capacity_;
   memset(current_runs_, 0, sizeof(current_runs_));
   for (size_t i = 0; i < kNumOfSizeBrackets; i++) {
-    size_bracket_locks_[i] = new Mutex("an rosalloc size bracket lock",
-                                       kRosAllocBracketLock);
+    size_bracket_lock_names[i] =
+        StringPrintf("an rosalloc size bracket %d lock", static_cast<int>(i));
+    size_bracket_locks_[i] = new Mutex(size_bracket_lock_names[i].c_str(), kRosAllocBracketLock);
   }
   DCHECK_EQ(footprint_, capacity_);
   size_t num_of_pages = footprint_ / kPageSize;
@@ -71,7 +79,7 @@
   std::string error_msg;
   page_map_mem_map_.reset(MemMap::MapAnonymous("rosalloc page map", NULL, RoundUp(max_num_of_pages, kPageSize),
                                                PROT_READ | PROT_WRITE, false, &error_msg));
-  CHECK(page_map_mem_map_.get() != NULL) << "Couldn't allocate the page map : " << error_msg;
+  CHECK(page_map_mem_map_.get() != nullptr) << "Couldn't allocate the page map : " << error_msg;
   page_map_ = page_map_mem_map_->Begin();
   page_map_size_ = num_of_pages;
   max_page_map_size_ = max_num_of_pages;
@@ -103,7 +111,7 @@
   lock_.AssertHeld(self);
   DCHECK(page_map_type == kPageMapRun || page_map_type == kPageMapLargeObject);
   FreePageRun* res = NULL;
-  size_t req_byte_size = num_pages * kPageSize;
+  const size_t req_byte_size = num_pages * kPageSize;
   // Find the lowest address free page run that's large enough.
   for (auto it = free_page_runs_.begin(); it != free_page_runs_.end(); ) {
     FreePageRun* fpr = *it;
@@ -260,8 +268,7 @@
       break;
     }
     if (kIsDebugBuild) {
-      // Clear the first page which isn't madvised away in the debug
-      // build for the magic number.
+      // Clear the first page since it is not madvised due to the magic number.
       memset(res, 0, kPageSize);
     }
     if (kTraceRosAlloc) {
@@ -279,7 +286,7 @@
   return nullptr;
 }
 
-size_t RosAlloc::FreePages(Thread* self, void* ptr) {
+size_t RosAlloc::FreePages(Thread* self, void* ptr, bool already_zero) {
   lock_.AssertHeld(self);
   size_t pm_idx = ToPageMapIndex(ptr);
   DCHECK_LT(pm_idx, page_map_size_);
@@ -310,10 +317,21 @@
     num_pages++;
     idx++;
   }
+  const size_t byte_size = num_pages * kPageSize;
+  if (already_zero) {
+    if (kCheckZeroMemory) {
+      const uword* word_ptr = reinterpret_cast<uword*>(ptr);
+      for (size_t i = 0; i < byte_size / sizeof(uword); ++i) {
+        CHECK_EQ(word_ptr[i], 0U) << "words don't match at index " << i;
+      }
+    }
+  } else if (!DoesReleaseAllPages()) {
+    memset(ptr, 0, byte_size);
+  }
 
   if (kTraceRosAlloc) {
     LOG(INFO) << "RosAlloc::FreePages() : 0x" << std::hex << reinterpret_cast<intptr_t>(ptr)
-              << "-0x" << (reinterpret_cast<intptr_t>(ptr) + num_pages * kPageSize)
+              << "-0x" << (reinterpret_cast<intptr_t>(ptr) + byte_size)
               << "(" << std::dec << (num_pages * kPageSize) << ")";
   }
 
@@ -322,8 +340,8 @@
   if (kIsDebugBuild) {
     fpr->magic_num_ = kMagicNumFree;
   }
-  fpr->SetByteSize(this, num_pages * kPageSize);
-  DCHECK_EQ(fpr->ByteSize(this) % kPageSize, static_cast<size_t>(0));
+  fpr->SetByteSize(this, byte_size);
+  DCHECK(IsAligned<kPageSize>(fpr->ByteSize(this)));
 
   DCHECK(free_page_runs_.find(fpr) == free_page_runs_.end());
   if (!free_page_runs_.empty()) {
@@ -349,6 +367,10 @@
           if (kTraceRosAlloc) {
             LOG(INFO) << "Success";
           }
+          // Clear magic num since this is no longer the start of a free page run.
+          if (kIsDebugBuild) {
+            h->magic_num_ = 0;
+          }
           free_page_runs_.erase(it++);
           if (kTraceRosAlloc) {
             LOG(INFO) << "RosAlloc::FreePages() : (coalesce) Erased run 0x" << std::hex
@@ -395,6 +417,10 @@
           }
           l->SetByteSize(this, l->ByteSize(this) + fpr->ByteSize(this));
           DCHECK_EQ(l->ByteSize(this) % kPageSize, static_cast<size_t>(0));
+          // Clear magic num since this is no longer the start of a free page run.
+          if (kIsDebugBuild) {
+            fpr->magic_num_ = 0;
+          }
           fpr = l;
         } else {
           // Not adjacent. Stop.
@@ -422,7 +448,7 @@
     LOG(INFO) << "RosAlloc::FreePages() : Inserted run 0x" << std::hex << reinterpret_cast<intptr_t>(fpr)
               << " into free_page_runs_";
   }
-  return num_pages;
+  return byte_size;
 }
 
 void* RosAlloc::AllocLargeObject(Thread* self, size_t size, size_t* bytes_allocated) {
@@ -439,23 +465,19 @@
     }
     return nullptr;
   }
-  if (bytes_allocated != NULL) {
-    *bytes_allocated = num_pages * kPageSize;
-  }
+  const size_t total_bytes = num_pages * kPageSize;
+  *bytes_allocated = total_bytes;
   if (kTraceRosAlloc) {
     LOG(INFO) << "RosAlloc::AllocLargeObject() : 0x" << std::hex << reinterpret_cast<intptr_t>(r)
               << "-0x" << (reinterpret_cast<intptr_t>(r) + num_pages * kPageSize)
               << "(" << std::dec << (num_pages * kPageSize) << ")";
   }
-  if (!DoesReleaseAllPages()) {
-    // If it does not release all pages, pages may not be zeroed out.
-    memset(r, 0, size);
-  }
   // Check if the returned memory is really all zero.
   if (kCheckZeroMemory) {
-    byte* bytes = reinterpret_cast<byte*>(r);
-    for (size_t i = 0; i < size; ++i) {
-      DCHECK_EQ(bytes[i], 0);
+    CHECK_EQ(total_bytes % sizeof(uword), 0U);
+    const uword* words = reinterpret_cast<uword*>(r);
+    for (size_t i = 0; i < total_bytes / sizeof(uword); ++i) {
+      CHECK_EQ(words[i], 0U);
     }
   }
   return r;
@@ -479,7 +501,7 @@
         LOG(FATAL) << "Unreachable - page map type: " << page_map_[pm_idx];
         return 0;
       case kPageMapLargeObject:
-        return FreePages(self, ptr) * kPageSize;
+        return FreePages(self, ptr, false);
       case kPageMapLargeObjectPart:
         LOG(FATAL) << "Unreachable - page map type: " << page_map_[pm_idx];
         return 0;
@@ -503,9 +525,7 @@
     }
   }
   DCHECK(run != nullptr);
-  const size_t size = IndexToBracketSize(run->size_bracket_idx_);
-  FreeFromRun(self, ptr, run);
-  return size;
+  return FreeFromRun(self, ptr, run);
 }
 
 size_t RosAlloc::Free(Thread* self, void* ptr) {
@@ -513,42 +533,57 @@
   return FreeInternal(self, ptr);
 }
 
-RosAlloc::Run* RosAlloc::RefillRun(Thread* self, size_t idx) {
-  Run* new_run;
-  size_t num_pages = numOfPages[idx];
-  // Get the lowest address non-full run from the binary tree.
-  Run* temp = NULL;
-  std::set<Run*>* bt = &non_full_runs_[idx];
-  std::set<Run*>::iterator found = bt->lower_bound(temp);
-  if (found != bt->end()) {
-    // If there's one, use it as the current run.
-    Run* non_full_run = *found;
-    DCHECK(non_full_run != NULL);
-    new_run = non_full_run;
-    DCHECK_EQ(new_run->is_thread_local_, 0);
-    bt->erase(found);
-    DCHECK_EQ(non_full_run->is_thread_local_, 0);
-  } else {
-    // If there's none, allocate a new run and use it as the
-    // current run.
-    {
-      MutexLock mu(self, lock_);
-      new_run = reinterpret_cast<Run*>(AllocPages(self, num_pages, kPageMapRun));
-    }
-    if (new_run == NULL) {
-      return NULL;
-    }
+RosAlloc::Run* RosAlloc::AllocRun(Thread* self, size_t idx) {
+  RosAlloc::Run* new_run = nullptr;
+  {
+    MutexLock mu(self, lock_);
+    new_run = reinterpret_cast<Run*>(AllocPages(self, numOfPages[idx], kPageMapRun));
+  }
+  if (LIKELY(new_run != nullptr)) {
     if (kIsDebugBuild) {
       new_run->magic_num_ = kMagicNum;
     }
     new_run->size_bracket_idx_ = idx;
-    new_run->top_slot_idx_ = 0;
-    new_run->ClearBitMaps();
-    new_run->to_be_bulk_freed_ = false;
+    new_run->SetAllocBitMapBitsForInvalidSlots();
+    DCHECK(!new_run->IsThreadLocal());
+    DCHECK_EQ(new_run->first_search_vec_idx_, 0U);
+    DCHECK(!new_run->to_be_bulk_freed_);
+    if (kUsePrefetchDuringAllocRun && idx <= kMaxThreadLocalSizeBracketIdx) {
+      // Take ownership of the cache lines if we are likely to be thread local run.
+      if (kPrefetchNewRunDataByZeroing) {
+        // Zeroing the data is sometimes faster than prefetching but it increases memory usage
+        // since we end up dirtying zero pages which may have been madvised.
+        new_run->ZeroData();
+      } else {
+        const size_t num_of_slots = numOfSlots[idx];
+        const size_t bracket_size = bracketSizes[idx];
+        const size_t num_of_bytes = num_of_slots * bracket_size;
+        byte* begin = reinterpret_cast<byte*>(new_run) + headerSizes[idx];
+        for (size_t i = 0; i < num_of_bytes; i += kPrefetchStride) {
+          __builtin_prefetch(begin + i);
+        }
+      }
+    }
   }
   return new_run;
 }
 
+RosAlloc::Run* RosAlloc::RefillRun(Thread* self, size_t idx) {
+  // Get the lowest address non-full run from the binary tree.
+  std::set<Run*>* const bt = &non_full_runs_[idx];
+  if (!bt->empty()) {
+    // If there's one, use it as the current run.
+    auto it = bt->begin();
+    Run* non_full_run = *it;
+    DCHECK(non_full_run != nullptr);
+    DCHECK(!non_full_run->IsThreadLocal());
+    bt->erase(it);
+    return non_full_run;
+  }
+  // If there's none, allocate a new run and use it as the current run.
+  return AllocRun(self, idx);
+}
+
 void* RosAlloc::AllocFromRun(Thread* self, size_t size, size_t* bytes_allocated) {
   DCHECK_LE(size, kLargeSizeThreshold);
   size_t bracket_size;
@@ -564,66 +599,62 @@
   if (LIKELY(idx <= kMaxThreadLocalSizeBracketIdx)) {
     // Use a thread-local run.
     Run* thread_local_run = reinterpret_cast<Run*>(self->GetRosAllocRun(idx));
-    if (UNLIKELY(thread_local_run == NULL)) {
-      MutexLock mu(self, *size_bracket_locks_[idx]);
-      thread_local_run = RefillRun(self, idx);
-      if (UNLIKELY(thread_local_run == NULL)) {
-        return NULL;
-      }
-      DCHECK(non_full_runs_[idx].find(thread_local_run) == non_full_runs_[idx].end());
-      DCHECK(full_runs_[idx].find(thread_local_run) == full_runs_[idx].end());
-      thread_local_run->is_thread_local_ = 1;
-      self->SetRosAllocRun(idx, thread_local_run);
-      DCHECK(!thread_local_run->IsFull());
-    }
-
-    DCHECK(thread_local_run != NULL);
-    DCHECK_NE(thread_local_run->is_thread_local_, 0);
+    // Allow invalid since this will always fail the allocation.
+    DCHECK(non_full_runs_[idx].find(thread_local_run) == non_full_runs_[idx].end());
+    DCHECK(full_runs_[idx].find(thread_local_run) == full_runs_[idx].end());
+    DCHECK(thread_local_run != nullptr);
+    DCHECK(thread_local_run->IsThreadLocal() || thread_local_run == dedicated_full_run_);
     slot_addr = thread_local_run->AllocSlot();
-
-    if (UNLIKELY(slot_addr == NULL)) {
+    // The allocation must fail if the run is invalid.
+    DCHECK(thread_local_run != dedicated_full_run_ || slot_addr == nullptr)
+        << "allocated from an invalid run";
+    if (UNLIKELY(slot_addr == nullptr)) {
       // The run got full. Try to free slots.
       DCHECK(thread_local_run->IsFull());
       MutexLock mu(self, *size_bracket_locks_[idx]);
       bool is_all_free_after_merge;
+      // This is safe to do for the dedicated_full_run_ since the bitmaps are empty.
       if (thread_local_run->MergeThreadLocalFreeBitMapToAllocBitMap(&is_all_free_after_merge)) {
+        DCHECK_NE(thread_local_run, dedicated_full_run_);
         // Some slot got freed. Keep it.
         DCHECK(!thread_local_run->IsFull());
         DCHECK_EQ(is_all_free_after_merge, thread_local_run->IsAllFree());
         if (is_all_free_after_merge) {
-          // Reinstate the bump index mode if it's all free.
-          DCHECK_EQ(thread_local_run->top_slot_idx_, numOfSlots[idx]);
-          thread_local_run->top_slot_idx_ = 0;
+          // Check that the bitmap idx is back at 0 if it's all free.
+          DCHECK_EQ(thread_local_run->first_search_vec_idx_, 0U);
         }
       } else {
         // No slots got freed. Try to refill the thread-local run.
         DCHECK(thread_local_run->IsFull());
-        self->SetRosAllocRun(idx, nullptr);
-        thread_local_run->is_thread_local_ = 0;
-        if (kIsDebugBuild) {
-          full_runs_[idx].insert(thread_local_run);
-          if (kTraceRosAlloc) {
-            LOG(INFO) << "RosAlloc::AllocFromRun() : Inserted run 0x" << std::hex
-                      << reinterpret_cast<intptr_t>(thread_local_run)
-                      << " into full_runs_[" << std::dec << idx << "]";
+        if (thread_local_run != dedicated_full_run_) {
+          self->SetRosAllocRun(idx, dedicated_full_run_);
+          thread_local_run->SetIsThreadLocal(false);
+          if (kIsDebugBuild) {
+            full_runs_[idx].insert(thread_local_run);
+            if (kTraceRosAlloc) {
+              LOG(INFO) << "RosAlloc::AllocFromRun() : Inserted run 0x" << std::hex
+                        << reinterpret_cast<intptr_t>(thread_local_run)
+                        << " into full_runs_[" << std::dec << idx << "]";
+            }
           }
+          DCHECK(non_full_runs_[idx].find(thread_local_run) == non_full_runs_[idx].end());
+          DCHECK(full_runs_[idx].find(thread_local_run) != full_runs_[idx].end());
         }
-        DCHECK(non_full_runs_[idx].find(thread_local_run) == non_full_runs_[idx].end());
-        DCHECK(full_runs_[idx].find(thread_local_run) != full_runs_[idx].end());
+
         thread_local_run = RefillRun(self, idx);
         if (UNLIKELY(thread_local_run == NULL)) {
           return NULL;
         }
         DCHECK(non_full_runs_[idx].find(thread_local_run) == non_full_runs_[idx].end());
         DCHECK(full_runs_[idx].find(thread_local_run) == full_runs_[idx].end());
-        thread_local_run->is_thread_local_ = 1;
+        thread_local_run->SetIsThreadLocal(true);
         self->SetRosAllocRun(idx, thread_local_run);
         DCHECK(!thread_local_run->IsFull());
       }
 
       DCHECK(thread_local_run != NULL);
       DCHECK(!thread_local_run->IsFull());
-      DCHECK_NE(thread_local_run->is_thread_local_, 0);
+      DCHECK(thread_local_run->IsThreadLocal());
       slot_addr = thread_local_run->AllocSlot();
       // Must succeed now with a new run.
       DCHECK(slot_addr != NULL);
@@ -644,7 +675,7 @@
       }
       DCHECK(non_full_runs_[idx].find(current_run) == non_full_runs_[idx].end());
       DCHECK(full_runs_[idx].find(current_run) == full_runs_[idx].end());
-      current_run->is_thread_local_ = 0;
+      current_run->SetIsThreadLocal(false);
       current_runs_[idx] = current_run;
       DCHECK(!current_run->IsFull());
     }
@@ -671,7 +702,7 @@
       DCHECK(current_run != NULL);
       DCHECK(non_full_runs_[idx].find(current_run) == non_full_runs_[idx].end());
       DCHECK(full_runs_[idx].find(current_run) == full_runs_[idx].end());
-      current_run->is_thread_local_ = 0;
+      current_run->SetIsThreadLocal(false);
       current_runs_[idx] = current_run;
       DCHECK(!current_run->IsFull());
       slot_addr = current_run->AllocSlot();
@@ -684,27 +715,27 @@
                 << "(" << std::dec << (bracket_size) << ")";
     }
   }
-  if (LIKELY(bytes_allocated != NULL)) {
-    *bytes_allocated = bracket_size;
-  }
-  memset(slot_addr, 0, size);
+  DCHECK(bytes_allocated != nullptr);
+  *bytes_allocated = bracket_size;
+  // Caller verifies that it is all 0.
   return slot_addr;
 }
 
-void RosAlloc::FreeFromRun(Thread* self, void* ptr, Run* run) {
+size_t RosAlloc::FreeFromRun(Thread* self, void* ptr, Run* run) {
   DCHECK_EQ(run->magic_num_, kMagicNum);
   DCHECK_LT(run, ptr);
   DCHECK_LT(ptr, run->End());
-  size_t idx = run->size_bracket_idx_;
-  MutexLock mu(self, *size_bracket_locks_[idx]);
+  const size_t idx = run->size_bracket_idx_;
+  const size_t bracket_size = bracketSizes[idx];
   bool run_was_full = false;
+  MutexLock mu(self, *size_bracket_locks_[idx]);
   if (kIsDebugBuild) {
     run_was_full = run->IsFull();
   }
   if (kTraceRosAlloc) {
     LOG(INFO) << "RosAlloc::FreeFromRun() : 0x" << std::hex << reinterpret_cast<intptr_t>(ptr);
   }
-  if (LIKELY(run->is_thread_local_ != 0)) {
+  if (LIKELY(run->IsThreadLocal())) {
     // It's a thread-local run. Just mark the thread-local free bit map and return.
     DCHECK_LE(run->size_bracket_idx_, kMaxThreadLocalSizeBracketIdx);
     DCHECK(non_full_runs_[idx].find(run) == non_full_runs_[idx].end());
@@ -715,7 +746,7 @@
                 << reinterpret_cast<intptr_t>(run);
     }
     // A thread local run will be kept as a thread local even if it's become all free.
-    return;
+    return bracket_size;
   }
   // Free the slot in the run.
   run->FreeSlot(ptr);
@@ -735,9 +766,10 @@
     }
     DCHECK(non_full_runs_[idx].find(run) == non_full_runs_[idx].end());
     DCHECK(full_runs_[idx].find(run) == full_runs_[idx].end());
+    run->ZeroHeader();
     {
       MutexLock mu(self, lock_);
-      FreePages(self, run);
+      FreePages(self, run, true);
     }
   } else {
     // It is not completely free. If it wasn't the current run or
@@ -767,6 +799,7 @@
       }
     }
   }
+  return bracket_size;
 }
 
 std::string RosAlloc::Run::BitMapToStr(uint32_t* bit_map_base, size_t num_vec) {
@@ -792,7 +825,7 @@
          << " size_bracket_idx=" << idx
          << " is_thread_local=" << static_cast<int>(is_thread_local_)
          << " to_be_bulk_freed=" << static_cast<int>(to_be_bulk_freed_)
-         << " top_slot_idx=" << top_slot_idx_
+         << " first_search_vec_idx=" << first_search_vec_idx_
          << " alloc_bit_map=" << BitMapToStr(alloc_bit_map_, num_vec)
          << " bulk_free_bit_map=" << BitMapToStr(BulkFreeBitMap(), num_vec)
          << " thread_local_bit_map=" << BitMapToStr(ThreadLocalFreeBitMap(), num_vec)
@@ -800,64 +833,52 @@
   return stream.str();
 }
 
-void* RosAlloc::Run::AllocSlot() {
-  size_t idx = size_bracket_idx_;
-  size_t num_slots = numOfSlots[idx];
-  DCHECK_LE(top_slot_idx_, num_slots);
-  if (LIKELY(top_slot_idx_ < num_slots)) {
-    // If it's in bump index mode, grab the top slot and increment the top index.
-    size_t slot_idx = top_slot_idx_;
-    byte* slot_addr = reinterpret_cast<byte*>(this) + headerSizes[idx] + slot_idx * bracketSizes[idx];
-    if (kTraceRosAlloc) {
-      LOG(INFO) << "RosAlloc::Run::AllocSlot() : 0x" << std::hex << reinterpret_cast<intptr_t>(slot_addr)
-                << ", bracket_size=" << std::dec << bracketSizes[idx] << ", slot_idx=" << slot_idx;
+inline void* RosAlloc::Run::AllocSlot() {
+  const size_t idx = size_bracket_idx_;
+  while (true) {
+    if (kIsDebugBuild) {
+      // Make sure that no slots leaked, the bitmap should be full for all previous vectors.
+      for (size_t i = 0; i < first_search_vec_idx_; ++i) {
+        CHECK_EQ(~alloc_bit_map_[i], 0U);
+      }
     }
-    top_slot_idx_++;
-    size_t vec_idx = slot_idx / 32;
-    size_t vec_off = slot_idx % 32;
-    uint32_t* vec = &alloc_bit_map_[vec_idx];
-    DCHECK_EQ((*vec & (1 << vec_off)), static_cast<uint32_t>(0));
-    *vec |= 1 << vec_off;
-    DCHECK_NE((*vec & (1 << vec_off)), static_cast<uint32_t>(0));
-    return slot_addr;
-  }
-  // Not in bump index mode. Search the alloc bit map for an empty slot.
-  size_t num_vec = RoundUp(num_slots, 32) / 32;
-  size_t slot_idx = 0;
-  bool found_slot = false;
-  for (size_t v = 0; v < num_vec; v++) {
-    uint32_t *vecp = &alloc_bit_map_[v];
-    uint32_t ffz1 = __builtin_ffs(~*vecp);
-    uint32_t ffz;
-    // TODO: Use LIKELY or UNLIKELY here?
-    if (LIKELY(ffz1 > 0 && (ffz = ffz1 - 1) + v * 32 < num_slots)) {
+    uint32_t* const alloc_bitmap_ptr = &alloc_bit_map_[first_search_vec_idx_];
+    uint32_t ffz1 = __builtin_ffs(~*alloc_bitmap_ptr);
+    if (LIKELY(ffz1 != 0)) {
+      const uint32_t ffz = ffz1 - 1;
+      const uint32_t slot_idx = ffz + first_search_vec_idx_ * sizeof(*alloc_bitmap_ptr) * kBitsPerByte;
+      const uint32_t mask = 1U << ffz;
+      DCHECK_LT(slot_idx, numOfSlots[idx]) << "out of range";
       // Found an empty slot. Set the bit.
-      DCHECK_EQ((*vecp & (1 << ffz)), static_cast<uint32_t>(0));
-      *vecp |= (1 << ffz);
-      DCHECK_NE((*vecp & (1 << ffz)), static_cast<uint32_t>(0));
-      slot_idx = ffz + v * 32;
-      found_slot = true;
-      break;
+      DCHECK_EQ(*alloc_bitmap_ptr & mask, 0U);
+      *alloc_bitmap_ptr |= mask;
+      DCHECK_NE(*alloc_bitmap_ptr & mask, 0U);
+      byte* slot_addr = reinterpret_cast<byte*>(this) + headerSizes[idx] + slot_idx * bracketSizes[idx];
+      if (kTraceRosAlloc) {
+        LOG(INFO) << "RosAlloc::Run::AllocSlot() : 0x" << std::hex << reinterpret_cast<intptr_t>(slot_addr)
+                  << ", bracket_size=" << std::dec << bracketSizes[idx] << ", slot_idx=" << slot_idx;
+      }
+      return slot_addr;
     }
-  }
-  if (LIKELY(found_slot)) {
-    byte* slot_addr = reinterpret_cast<byte*>(this) + headerSizes[idx] + slot_idx * bracketSizes[idx];
-    if (kTraceRosAlloc) {
-      LOG(INFO) << "RosAlloc::Run::AllocSlot() : 0x" << std::hex << reinterpret_cast<intptr_t>(slot_addr)
-                << ", bracket_size=" << std::dec << bracketSizes[idx] << ", slot_idx=" << slot_idx;
+    const size_t num_words = RoundUp(numOfSlots[idx], 32) / 32;
+    if (first_search_vec_idx_ + 1 >= num_words) {
+      DCHECK(IsFull());
+      // Already at the last word, return null.
+      return nullptr;
     }
-    return slot_addr;
+    // Increase the index to the next word and try again.
+    ++first_search_vec_idx_;
   }
-  return NULL;
 }
 
-inline void RosAlloc::Run::FreeSlot(void* ptr) {
-  DCHECK_EQ(is_thread_local_, 0);
-  byte idx = size_bracket_idx_;
-  size_t offset_from_slot_base = reinterpret_cast<byte*>(ptr)
+void RosAlloc::Run::FreeSlot(void* ptr) {
+  DCHECK(!IsThreadLocal());
+  const byte idx = size_bracket_idx_;
+  const size_t bracket_size = bracketSizes[idx];
+  const size_t offset_from_slot_base = reinterpret_cast<byte*>(ptr)
       - (reinterpret_cast<byte*>(this) + headerSizes[idx]);
-  DCHECK_EQ(offset_from_slot_base % bracketSizes[idx], static_cast<size_t>(0));
-  size_t slot_idx = offset_from_slot_base / bracketSizes[idx];
+  DCHECK_EQ(offset_from_slot_base % bracket_size, static_cast<size_t>(0));
+  size_t slot_idx = offset_from_slot_base / bracket_size;
   DCHECK_LT(slot_idx, numOfSlots[idx]);
   size_t vec_idx = slot_idx / 32;
   if (kIsDebugBuild) {
@@ -866,9 +887,14 @@
   }
   size_t vec_off = slot_idx % 32;
   uint32_t* vec = &alloc_bit_map_[vec_idx];
-  DCHECK_NE((*vec & (1 << vec_off)), static_cast<uint32_t>(0));
-  *vec &= ~(1 << vec_off);
-  DCHECK_EQ((*vec & (1 << vec_off)), static_cast<uint32_t>(0));
+  first_search_vec_idx_ = std::min(first_search_vec_idx_, static_cast<uint32_t>(vec_idx));
+  const uint32_t mask = 1U << vec_off;
+  DCHECK_NE(*vec & mask, 0U);
+  *vec &= ~mask;
+  DCHECK_EQ(*vec & mask, 0U);
+  // Zero out the memory.
+  // TODO: Investigate alternate memset since ptr is guaranteed to be aligned to 16.
+  memset(ptr, 0, bracket_size);
   if (kTraceRosAlloc) {
     LOG(INFO) << "RosAlloc::Run::FreeSlot() : 0x" << std::hex << reinterpret_cast<intptr_t>(ptr)
               << ", bracket_size=" << std::dec << bracketSizes[idx] << ", slot_idx=" << slot_idx;
@@ -876,11 +902,11 @@
 }
 
 inline bool RosAlloc::Run::MergeThreadLocalFreeBitMapToAllocBitMap(bool* is_all_free_after_out) {
-  DCHECK_NE(is_thread_local_, 0);
+  DCHECK(IsThreadLocal());
   // Free slots in the alloc bit map based on the thread local free bit map.
-  byte idx = size_bracket_idx_;
-  size_t num_slots = numOfSlots[idx];
-  size_t num_vec = RoundUp(num_slots, 32) / 32;
+  const size_t idx = size_bracket_idx_;
+  const size_t num_of_slots = numOfSlots[idx];
+  const size_t num_vec = RoundUp(num_of_slots, 32) / 32;
   bool changed = false;
   uint32_t* vecp = &alloc_bit_map_[0];
   uint32_t* tl_free_vecp = &ThreadLocalFreeBitMap()[0];
@@ -890,6 +916,7 @@
     uint32_t vec_before = *vecp;
     uint32_t vec_after;
     if (tl_free_vec != 0) {
+      first_search_vec_idx_ = std::min(first_search_vec_idx_, static_cast<uint32_t>(v));
       vec_after = vec_before & ~tl_free_vec;
       *vecp = vec_after;
       changed = true;
@@ -898,7 +925,13 @@
       vec_after = vec_before;
     }
     if (vec_after != 0) {
-      is_all_free_after = false;
+      if (v == num_vec - 1) {
+        // Only not all free if a bit other than the mask bits are set.
+        is_all_free_after =
+            is_all_free_after && GetBitmapLastVectorMask(num_of_slots, num_vec) == vec_after;
+      } else {
+        is_all_free_after = false;
+      }
     }
     DCHECK_EQ(*tl_free_vecp, static_cast<uint32_t>(0));
   }
@@ -909,16 +942,15 @@
 }
 
 inline void RosAlloc::Run::MergeBulkFreeBitMapIntoAllocBitMap() {
-  DCHECK_EQ(is_thread_local_, 0);
+  DCHECK(!IsThreadLocal());
   // Free slots in the alloc bit map based on the bulk free bit map.
-  byte idx = size_bracket_idx_;
-  size_t num_slots = numOfSlots[idx];
-  size_t num_vec = RoundUp(num_slots, 32) / 32;
+  const size_t num_vec = NumberOfBitmapVectors();
   uint32_t* vecp = &alloc_bit_map_[0];
   uint32_t* free_vecp = &BulkFreeBitMap()[0];
   for (size_t v = 0; v < num_vec; v++, vecp++, free_vecp++) {
     uint32_t free_vec = *free_vecp;
     if (free_vec != 0) {
+      first_search_vec_idx_ = std::min(first_search_vec_idx_, static_cast<uint32_t>(v));
       *vecp &= ~free_vec;
       *free_vecp = 0;  // clear the bulk free bit map.
     }
@@ -927,11 +959,9 @@
 }
 
 inline void RosAlloc::Run::UnionBulkFreeBitMapToThreadLocalFreeBitMap() {
-  DCHECK_NE(is_thread_local_, 0);
+  DCHECK(IsThreadLocal());
   // Union the thread local bit map with the bulk free bit map.
-  byte idx = size_bracket_idx_;
-  size_t num_slots = numOfSlots[idx];
-  size_t num_vec = RoundUp(num_slots, 32) / 32;
+  size_t num_vec = NumberOfBitmapVectors();
   uint32_t* to_vecp = &ThreadLocalFreeBitMap()[0];
   uint32_t* from_vecp = &BulkFreeBitMap()[0];
   for (size_t v = 0; v < num_vec; v++, to_vecp++, from_vecp++) {
@@ -945,66 +975,71 @@
 }
 
 inline void RosAlloc::Run::MarkThreadLocalFreeBitMap(void* ptr) {
-  DCHECK_NE(is_thread_local_, 0);
+  DCHECK(IsThreadLocal());
   MarkFreeBitMapShared(ptr, ThreadLocalFreeBitMap(), "MarkThreadLocalFreeBitMap");
 }
 
-inline void RosAlloc::Run::MarkBulkFreeBitMap(void* ptr) {
-  MarkFreeBitMapShared(ptr, BulkFreeBitMap(), "MarkFreeBitMap");
+inline size_t RosAlloc::Run::MarkBulkFreeBitMap(void* ptr) {
+  return MarkFreeBitMapShared(ptr, BulkFreeBitMap(), "MarkFreeBitMap");
 }
 
-inline void RosAlloc::Run::MarkFreeBitMapShared(void* ptr, uint32_t* free_bit_map_base,
-                                              const char* caller_name) {
-  byte idx = size_bracket_idx_;
-  size_t offset_from_slot_base = reinterpret_cast<byte*>(ptr)
+inline size_t RosAlloc::Run::MarkFreeBitMapShared(void* ptr, uint32_t* free_bit_map_base,
+                                                  const char* caller_name) {
+  const byte idx = size_bracket_idx_;
+  const size_t offset_from_slot_base = reinterpret_cast<byte*>(ptr)
       - (reinterpret_cast<byte*>(this) + headerSizes[idx]);
-  DCHECK_EQ(offset_from_slot_base % bracketSizes[idx], static_cast<size_t>(0));
-  size_t slot_idx = offset_from_slot_base / bracketSizes[idx];
+  const size_t bracket_size = bracketSizes[idx];
+  memset(ptr, 0, bracket_size);
+  DCHECK_EQ(offset_from_slot_base % bracket_size, static_cast<size_t>(0));
+  size_t slot_idx = offset_from_slot_base / bracket_size;
   DCHECK_LT(slot_idx, numOfSlots[idx]);
   size_t vec_idx = slot_idx / 32;
   if (kIsDebugBuild) {
-    size_t num_vec = RoundUp(numOfSlots[idx], 32) / 32;
+    size_t num_vec = NumberOfBitmapVectors();
     DCHECK_LT(vec_idx, num_vec);
   }
   size_t vec_off = slot_idx % 32;
   uint32_t* vec = &free_bit_map_base[vec_idx];
-  DCHECK_EQ((*vec & (1 << vec_off)), static_cast<uint32_t>(0));
-  *vec |= 1 << vec_off;
-  DCHECK_NE((*vec & (1 << vec_off)), static_cast<uint32_t>(0));
+  const uint32_t mask = 1U << vec_off;
+  DCHECK_EQ(*vec & mask, 0U);
+  *vec |= mask;
+  DCHECK_NE(*vec & mask, 0U);
   if (kTraceRosAlloc) {
     LOG(INFO) << "RosAlloc::Run::" << caller_name << "() : 0x" << std::hex
               << reinterpret_cast<intptr_t>(ptr)
               << ", bracket_size=" << std::dec << bracketSizes[idx] << ", slot_idx=" << slot_idx;
   }
+  return bracket_size;
+}
+
+inline uint32_t RosAlloc::Run::GetBitmapLastVectorMask(size_t num_slots, size_t num_vec) {
+  const size_t kBitsPerVec = 32;
+  DCHECK_GE(num_slots * kBitsPerVec, num_vec);
+  size_t remain = num_vec * kBitsPerVec - num_slots;
+  DCHECK_NE(remain, kBitsPerVec);
+  return ((1U << remain) - 1) << (kBitsPerVec - remain);
 }
 
 inline bool RosAlloc::Run::IsAllFree() {
-  byte idx = size_bracket_idx_;
-  size_t num_slots = numOfSlots[idx];
-  size_t num_vec = RoundUp(num_slots, 32) / 32;
-  for (size_t v = 0; v < num_vec; v++) {
+  const byte idx = size_bracket_idx_;
+  const size_t num_slots = numOfSlots[idx];
+  const size_t num_vec = NumberOfBitmapVectors();
+  DCHECK_NE(num_vec, 0U);
+  // Check the last vector after the loop since it uses a special case for the masked bits.
+  for (size_t v = 0; v < num_vec - 1; v++) {
     uint32_t vec = alloc_bit_map_[v];
     if (vec != 0) {
       return false;
     }
   }
-  return true;
+  // Make sure the last word is equal to the mask, all other bits must be 0.
+  return alloc_bit_map_[num_vec - 1] == GetBitmapLastVectorMask(num_slots, num_vec);
 }
 
 inline bool RosAlloc::Run::IsFull() {
-  byte idx = size_bracket_idx_;
-  size_t num_slots = numOfSlots[idx];
-  size_t num_vec = RoundUp(num_slots, 32) / 32;
-  size_t slots = 0;
-  for (size_t v = 0; v < num_vec; v++, slots += 32) {
-    DCHECK_GE(num_slots, slots);
-    uint32_t vec = alloc_bit_map_[v];
-    uint32_t mask = (num_slots - slots >= 32) ? static_cast<uint32_t>(-1)
-        : (1 << (num_slots - slots)) - 1;
-    if ((num_slots - slots) >= 32) {
-      DCHECK_EQ(mask, static_cast<uint32_t>(-1));
-    }
-    if (vec != mask) {
+  const size_t num_vec = NumberOfBitmapVectors();
+  for (size_t v = 0; v < num_vec; ++v) {
+    if (~alloc_bit_map_[v] != 0) {
       return false;
     }
   }
@@ -1012,9 +1047,7 @@
 }
 
 inline bool RosAlloc::Run::IsBulkFreeBitmapClean() {
-  byte idx = size_bracket_idx_;
-  size_t num_slots = numOfSlots[idx];
-  size_t num_vec = RoundUp(num_slots, 32) / 32;
+  const size_t num_vec = NumberOfBitmapVectors();
   for (size_t v = 0; v < num_vec; v++) {
     uint32_t vec = BulkFreeBitMap()[v];
     if (vec != 0) {
@@ -1025,9 +1058,7 @@
 }
 
 inline bool RosAlloc::Run::IsThreadLocalFreeBitmapClean() {
-  byte idx = size_bracket_idx_;
-  size_t num_slots = numOfSlots[idx];
-  size_t num_vec = RoundUp(num_slots, 32) / 32;
+  const size_t num_vec = NumberOfBitmapVectors();
   for (size_t v = 0; v < num_vec; v++) {
     uint32_t vec = ThreadLocalFreeBitMap()[v];
     if (vec != 0) {
@@ -1037,11 +1068,31 @@
   return true;
 }
 
-inline void RosAlloc::Run::ClearBitMaps() {
-  byte idx = size_bracket_idx_;
-  size_t num_slots = numOfSlots[idx];
-  size_t num_vec = RoundUp(num_slots, 32) / 32;
-  memset(alloc_bit_map_, 0, sizeof(uint32_t) * num_vec * 3);
+inline void RosAlloc::Run::SetAllocBitMapBitsForInvalidSlots() {
+  const size_t idx = size_bracket_idx_;
+  const size_t num_slots = numOfSlots[idx];
+  const size_t num_vec = RoundUp(num_slots, 32) / 32;
+  DCHECK_NE(num_vec, 0U);
+  // Make sure to set the bits at the end of the bitmap so that we don't allocate there since they
+  // don't represent valid slots.
+  alloc_bit_map_[num_vec - 1] |= GetBitmapLastVectorMask(num_slots, num_vec);
+}
+
+inline void RosAlloc::Run::ZeroHeader() {
+  const byte idx = size_bracket_idx_;
+  memset(this, 0, headerSizes[idx]);
+}
+
+inline void RosAlloc::Run::ZeroData() {
+  const byte idx = size_bracket_idx_;
+  byte* slot_begin = reinterpret_cast<byte*>(this) + headerSizes[idx];
+  memset(slot_begin, 0, numOfSlots[idx] * bracketSizes[idx]);
+}
+
+inline void RosAlloc::Run::FillAllocBitMap() {
+  size_t num_vec = NumberOfBitmapVectors();
+  memset(alloc_bit_map_, 0xFF, sizeof(uint32_t) * num_vec);
+  first_search_vec_idx_ = num_vec - 1;  // No free bits in any of the bitmap words.
 }
 
 void RosAlloc::Run::InspectAllSlots(void (*handler)(void* start, void* end, size_t used_bytes, void* callback_arg),
@@ -1073,7 +1124,7 @@
 // lock for better performance, assuming that the existence of an
 // allocated chunk/pointer being freed in BulkFree() guarantees that
 // the page map entry won't change. Disabled for now.
-static constexpr bool kReadPageMapEntryWithoutLockInBulkFree = false;
+static constexpr bool kReadPageMapEntryWithoutLockInBulkFree = true;
 
 size_t RosAlloc::BulkFree(Thread* self, void** ptrs, size_t num_ptrs) {
   size_t freed_bytes = 0;
@@ -1096,11 +1147,10 @@
 #endif
   for (size_t i = 0; i < num_ptrs; i++) {
     void* ptr = ptrs[i];
-    ptrs[i] = NULL;
     DCHECK_LE(base_, ptr);
     DCHECK_LT(ptr, base_ + footprint_);
     size_t pm_idx = RoundDownToPageMapIndex(ptr);
-    Run* run = NULL;
+    Run* run = nullptr;
     if (kReadPageMapEntryWithoutLockInBulkFree) {
       // Read the page map entries without locking the lock.
       byte page_map_entry = page_map_[pm_idx];
@@ -1111,106 +1161,74 @@
       }
       if (LIKELY(page_map_entry == kPageMapRun)) {
         run = reinterpret_cast<Run*>(base_ + pm_idx * kPageSize);
-        DCHECK_EQ(run->magic_num_, kMagicNum);
       } else if (LIKELY(page_map_entry == kPageMapRunPart)) {
         size_t pi = pm_idx;
-        DCHECK(page_map_[pi] == kPageMapRun || page_map_[pi] == kPageMapRunPart);
         // Find the beginning of the run.
-        while (page_map_[pi] != kPageMapRun) {
-          pi--;
+        do {
+          --pi;
           DCHECK_LT(pi, capacity_ / kPageSize);
-        }
-        DCHECK_EQ(page_map_[pi], kPageMapRun);
+        } while (page_map_[pi] != kPageMapRun);
         run = reinterpret_cast<Run*>(base_ + pi * kPageSize);
-        DCHECK_EQ(run->magic_num_, kMagicNum);
       } else if (page_map_entry == kPageMapLargeObject) {
         MutexLock mu(self, lock_);
-        freed_bytes += FreePages(self, ptr) * kPageSize;
+        freed_bytes += FreePages(self, ptr, false);
         continue;
       } else {
         LOG(FATAL) << "Unreachable - page map type: " << page_map_entry;
       }
-      DCHECK(run != nullptr);
-      // Set the bit in the bulk free bit map.
-      run->MarkBulkFreeBitMap(ptr);
-      freed_bytes += IndexToBracketSize(run->size_bracket_idx_);
-#ifdef HAVE_ANDROID_OS
-      if (!run->to_be_bulk_freed_) {
-        run->to_be_bulk_freed_ = true;
-        runs.push_back(run);
-      }
-#else
-      runs.insert(run);
-#endif
     } else {
       // Read the page map entries with a lock.
-      bool free_from_run = false;
-      {
-        MutexLock mu(self, lock_);
-        DCHECK_LT(pm_idx, page_map_size_);
-        byte page_map_entry = page_map_[pm_idx];
-        if (kTraceRosAlloc) {
-          LOG(INFO) << "RosAlloc::BulkFree() : " << std::hex << ptr << ", pm_idx="
-                    << std::dec << pm_idx
-                    << ", page_map_entry=" << static_cast<int>(page_map_entry);
-        }
-        if (LIKELY(page_map_entry == kPageMapRun)) {
-          free_from_run = true;
-          run = reinterpret_cast<Run*>(base_ + pm_idx * kPageSize);
-          DCHECK_EQ(run->magic_num_, kMagicNum);
-        } else if (LIKELY(page_map_entry == kPageMapRunPart)) {
-          free_from_run = true;
-          size_t pi = pm_idx;
-          DCHECK(page_map_[pi] == kPageMapRun || page_map_[pi] == kPageMapRunPart);
-          // Find the beginning of the run.
-          while (page_map_[pi] != kPageMapRun) {
-            pi--;
-            DCHECK_LT(pi, capacity_ / kPageSize);
-          }
-          DCHECK_EQ(page_map_[pi], kPageMapRun);
-          run = reinterpret_cast<Run*>(base_ + pi * kPageSize);
-          DCHECK_EQ(run->magic_num_, kMagicNum);
-        } else if (page_map_entry == kPageMapLargeObject) {
-          freed_bytes += FreePages(self, ptr) * kPageSize;
-        } else {
-          LOG(FATAL) << "Unreachable - page map type: " << page_map_entry;
-        }
+      MutexLock mu(self, lock_);
+      DCHECK_LT(pm_idx, page_map_size_);
+      byte page_map_entry = page_map_[pm_idx];
+      if (kTraceRosAlloc) {
+        LOG(INFO) << "RosAlloc::BulkFree() : " << std::hex << ptr << ", pm_idx="
+                  << std::dec << pm_idx
+                  << ", page_map_entry=" << static_cast<int>(page_map_entry);
       }
-      if (LIKELY(free_from_run)) {
-        DCHECK(run != NULL);
-        // Set the bit in the bulk free bit map.
-        run->MarkBulkFreeBitMap(ptr);
-        freed_bytes += IndexToBracketSize(run->size_bracket_idx_);
-#ifdef HAVE_ANDROID_OS
-        if (!run->to_be_bulk_freed_) {
-          run->to_be_bulk_freed_ = true;
-          runs.push_back(run);
-        }
-#else
-        runs.insert(run);
-#endif
+      if (LIKELY(page_map_entry == kPageMapRun)) {
+        run = reinterpret_cast<Run*>(base_ + pm_idx * kPageSize);
+      } else if (LIKELY(page_map_entry == kPageMapRunPart)) {
+        size_t pi = pm_idx;
+        // Find the beginning of the run.
+        do {
+          --pi;
+          DCHECK_LT(pi, capacity_ / kPageSize);
+        } while (page_map_[pi] != kPageMapRun);
+        run = reinterpret_cast<Run*>(base_ + pi * kPageSize);
+      } else if (page_map_entry == kPageMapLargeObject) {
+        freed_bytes += FreePages(self, ptr, false);
+        continue;
+      } else {
+        LOG(FATAL) << "Unreachable - page map type: " << page_map_entry;
       }
     }
+    DCHECK(run != nullptr);
+    DCHECK_EQ(run->magic_num_, kMagicNum);
+    // Set the bit in the bulk free bit map.
+    freed_bytes += run->MarkBulkFreeBitMap(ptr);
+#ifdef HAVE_ANDROID_OS
+    if (!run->to_be_bulk_freed_) {
+      run->to_be_bulk_freed_ = true;
+      runs.push_back(run);
+    }
+#else
+    runs.insert(run);
+#endif
   }
 
   // Now, iterate over the affected runs and update the alloc bit map
   // based on the bulk free bit map (for non-thread-local runs) and
   // union the bulk free bit map into the thread-local free bit map
   // (for thread-local runs.)
-#ifdef HAVE_ANDROID_OS
-  typedef std::vector<Run*>::iterator It;
-#else
-  typedef hash_set<Run*, hash_run, eq_run>::iterator It;
-#endif
-  for (It it = runs.begin(); it != runs.end(); ++it) {
-    Run* run = *it;
+  for (Run* run : runs) {
 #ifdef HAVE_ANDROID_OS
     DCHECK(run->to_be_bulk_freed_);
     run->to_be_bulk_freed_ = false;
 #endif
     size_t idx = run->size_bracket_idx_;
     MutexLock mu(self, *size_bracket_locks_[idx]);
-    if (run->is_thread_local_ != 0) {
+    if (run->IsThreadLocal()) {
       DCHECK_LE(run->size_bracket_idx_, kMaxThreadLocalSizeBracketIdx);
       DCHECK(non_full_runs_[idx].find(run) == non_full_runs_[idx].end());
       DCHECK(full_runs_[idx].find(run) == full_runs_[idx].end());
@@ -1219,7 +1237,7 @@
         LOG(INFO) << "RosAlloc::BulkFree() : Freed slot(s) in a thread local run 0x"
                   << std::hex << reinterpret_cast<intptr_t>(run);
       }
-      DCHECK_NE(run->is_thread_local_, 0);
+      DCHECK(run->IsThreadLocal());
       // A thread local run will be kept as a thread local even if
       // it's become all free.
     } else {
@@ -1269,8 +1287,9 @@
           DCHECK(non_full_runs->find(run) == non_full_runs->end());
         }
         if (!run_was_current) {
+          run->ZeroHeader();
           MutexLock mu(self, lock_);
-          FreePages(self, run);
+          FreePages(self, run, true);
         }
       } else {
         // It is not completely free. If it wasn't the current run or
@@ -1381,7 +1400,7 @@
         stream << "[" << i << "]=Run (start)"
                << " idx=" << idx
                << " numOfPages=" << numOfPages[idx]
-               << " thread_local=" << static_cast<int>(run->is_thread_local_)
+               << " is_thread_local=" << run->is_thread_local_
                << " is_all_free=" << (run->IsAllFree() ? 1 : 0)
                << std::endl;
         break;
@@ -1556,6 +1575,8 @@
         // The start of a run.
         Run* run = reinterpret_cast<Run*>(base_ + i * kPageSize);
         DCHECK_EQ(run->magic_num_, kMagicNum);
+        // The dedicated full run doesn't contain any real allocations, don't visit the slots in
+        // there.
         run->InspectAllSlots(handler, arg);
         size_t num_pages = numOfPages[run->size_bracket_idx_];
         if (kIsDebugBuild) {
@@ -1605,14 +1626,16 @@
   for (size_t idx = 0; idx < kNumOfSizeBrackets; idx++) {
     MutexLock mu(self, *size_bracket_locks_[idx]);
     Run* thread_local_run = reinterpret_cast<Run*>(thread->GetRosAllocRun(idx));
-    if (thread_local_run != NULL) {
+    CHECK(thread_local_run != nullptr);
+    // Invalid means already revoked.
+    DCHECK(thread_local_run->IsThreadLocal());
+    if (thread_local_run != dedicated_full_run_) {
+      thread->SetRosAllocRun(idx, dedicated_full_run_);
       DCHECK_EQ(thread_local_run->magic_num_, kMagicNum);
-      DCHECK_NE(thread_local_run->is_thread_local_, 0);
-      thread->SetRosAllocRun(idx, nullptr);
       // Note the thread local run may not be full here.
       bool dont_care;
       thread_local_run->MergeThreadLocalFreeBitMapToAllocBitMap(&dont_care);
-      thread_local_run->is_thread_local_ = 0;
+      thread_local_run->SetIsThreadLocal(false);
       thread_local_run->MergeBulkFreeBitMapIntoAllocBitMap();
       DCHECK(non_full_runs_[idx].find(thread_local_run) == non_full_runs_[idx].end());
       DCHECK(full_runs_[idx].find(thread_local_run) == full_runs_[idx].end());
@@ -1628,7 +1651,8 @@
         }
       } else if (thread_local_run->IsAllFree()) {
         MutexLock mu(self, lock_);
-        FreePages(self, thread_local_run);
+        thread_local_run->ZeroHeader();
+        FreePages(self, thread_local_run, true);
       } else {
         non_full_runs_[idx].insert(thread_local_run);
         DCHECK(non_full_runs_[idx].find(thread_local_run) != non_full_runs_[idx].end());
@@ -1648,9 +1672,8 @@
   MutexLock mu(Thread::Current(), *Locks::runtime_shutdown_lock_);
   MutexLock mu2(Thread::Current(), *Locks::thread_list_lock_);
   std::list<Thread*> thread_list = Runtime::Current()->GetThreadList()->GetList();
-  for (auto it = thread_list.begin(); it != thread_list.end(); ++it) {
-    Thread* t = *it;
-    RevokeThreadLocalRuns(t);
+  for (Thread* thread : thread_list) {
+    RevokeThreadLocalRuns(thread);
   }
 }
 
@@ -1662,7 +1685,7 @@
     for (size_t idx = 0; idx < kNumOfSizeBrackets; idx++) {
       MutexLock mu(self, *size_bracket_locks_[idx]);
       Run* thread_local_run = reinterpret_cast<Run*>(thread->GetRosAllocRun(idx));
-      DCHECK(thread_local_run == nullptr);
+      DCHECK(thread_local_run == nullptr || thread_local_run == dedicated_full_run_);
     }
   }
 }
@@ -1770,6 +1793,15 @@
                 << ", threadLocalFreeBitMapOffsets[" << i << "]=" << threadLocalFreeBitMapOffsets[i];;
     }
   }
+  // Fill the alloc bitmap so nobody can successfully allocate from it.
+  if (kIsDebugBuild) {
+    dedicated_full_run_->magic_num_ = kMagicNum;
+  }
+  // It doesn't matter which size bracket we use since the main goal is to have the allocation
+  // fail 100% of the time you attempt to allocate into the dedicated full run.
+  dedicated_full_run_->size_bracket_idx_ = 0;
+  dedicated_full_run_->FillAllocBitMap();
+  dedicated_full_run_->SetIsThreadLocal(true);
 }
 
 void RosAlloc::BytesAllocatedCallback(void* start, void* end, size_t used_bytes, void* arg) {
@@ -1867,6 +1899,7 @@
                 << " and the run size : page index range " << i << " to " << (i + num_pages)
                 << std::endl << DumpPageMap();
           }
+          // Don't verify the dedicated_full_run_ since it doesn't have any real allocations.
           runs.push_back(run);
           i += num_pages;
           CHECK_LE(i, pm_end) << "Page map index " << i << " out of range < " << pm_end
@@ -1891,34 +1924,25 @@
 
 void RosAlloc::Run::Verify(Thread* self, RosAlloc* rosalloc) {
   DCHECK_EQ(magic_num_, kMagicNum) << "Bad magic number : " << Dump();
-  size_t idx = size_bracket_idx_;
+  const size_t idx = size_bracket_idx_;
   CHECK_LT(idx, kNumOfSizeBrackets) << "Out of range size bracket index : " << Dump();
   byte* slot_base = reinterpret_cast<byte*>(this) + headerSizes[idx];
-  size_t num_slots = numOfSlots[idx];
+  const size_t num_slots = numOfSlots[idx];
+  const size_t num_vec = RoundUp(num_slots, 32) / 32;
+  CHECK_GT(num_vec, 0U);
   size_t bracket_size = IndexToBracketSize(idx);
   CHECK_EQ(slot_base + num_slots * bracket_size,
            reinterpret_cast<byte*>(this) + numOfPages[idx] * kPageSize)
       << "Mismatch in the end address of the run " << Dump();
   // Check that the bulk free bitmap is clean. It's only used during BulkFree().
   CHECK(IsBulkFreeBitmapClean()) << "The bulk free bit map isn't clean " << Dump();
-  // Check the bump index mode, if it's on.
-  if (top_slot_idx_ < num_slots) {
-    // If the bump index mode is on (top_slot_idx_ < num_slots), then
-    // all of the slots after the top index must be free.
-    for (size_t i = top_slot_idx_; i < num_slots; ++i) {
-      size_t vec_idx = i / 32;
-      size_t vec_off = i % 32;
-      uint32_t vec = alloc_bit_map_[vec_idx];
-      CHECK_EQ((vec & (1 << vec_off)), static_cast<uint32_t>(0))
-          << "A slot >= top_slot_idx_ isn't free " << Dump();
-    }
-  } else {
-    CHECK_EQ(top_slot_idx_, num_slots)
-        << "If the bump index mode is off, the top index == the number of slots "
-        << Dump();
-  }
+  uint32_t last_word_mask = GetBitmapLastVectorMask(num_slots, num_vec);
+  // Make sure all the bits at the end of the run are set so that we don't allocate there.
+  CHECK_EQ(alloc_bit_map_[num_vec - 1] & last_word_mask, last_word_mask);
+  // Ensure that the first bitmap index is valid.
+  CHECK_LT(first_search_vec_idx_, num_vec);
   // Check the thread local runs, the current runs, and the run sets.
-  if (is_thread_local_) {
+  if (IsThreadLocal()) {
     // If it's a thread local run, then it must be pointed to by an owner thread.
     bool owner_found = false;
     std::list<Thread*> thread_list = Runtime::Current()->GetThreadList()->GetList();
@@ -1980,7 +2004,6 @@
     }
   }
   // Check each slot.
-  size_t num_vec = RoundUp(num_slots, 32) / 32;
   size_t slots = 0;
   for (size_t v = 0; v < num_vec; v++, slots += 32) {
     DCHECK_GE(num_slots, slots) << "Out of bounds";
@@ -1991,7 +2014,7 @@
       bool is_allocated = ((vec >> i) & 0x1) != 0;
       // If a thread local run, slots may be marked freed in the
       // thread local free bitmap.
-      bool is_thread_local_freed = is_thread_local_ && ((thread_local_free_vec >> i) & 0x1) != 0;
+      bool is_thread_local_freed = IsThreadLocal() && ((thread_local_free_vec >> i) & 0x1) != 0;
       if (is_allocated && !is_thread_local_freed) {
         byte* slot_addr = slot_base + (slots + i) * bracket_size;
         mirror::Object* obj = reinterpret_cast<mirror::Object*>(slot_addr);
diff --git a/runtime/gc/allocator/rosalloc.h b/runtime/gc/allocator/rosalloc.h
index 0c508b7..f7fa2da 100644
--- a/runtime/gc/allocator/rosalloc.h
+++ b/runtime/gc/allocator/rosalloc.h
@@ -155,7 +155,7 @@
   // +-------------------+
   // | to_be_bulk_freed  |
   // +-------------------+
-  // | top_slot_idx      |
+  // | top_bitmap_idx    |
   // +-------------------+
   // |                   |
   // | alloc bit map     |
@@ -186,12 +186,12 @@
   //
   class Run {
    public:
-    byte magic_num_;             // The magic number used for debugging.
-    byte size_bracket_idx_;      // The index of the size bracket of this run.
-    byte is_thread_local_;       // True if this run is used as a thread-local run.
-    byte to_be_bulk_freed_;      // Used within BulkFree() to flag a run that's involved with a bulk free.
-    uint32_t top_slot_idx_;      // The top slot index when this run is in bump index mode.
-    uint32_t alloc_bit_map_[0];  // The bit map that allocates if each slot is in use.
+    byte magic_num_;                 // The magic number used for debugging.
+    byte size_bracket_idx_;          // The index of the size bracket of this run.
+    byte is_thread_local_;           // True if this run is used as a thread-local run.
+    byte to_be_bulk_freed_;          // Used within BulkFree() to flag a run that's involved with a bulk free.
+    uint32_t first_search_vec_idx_;  // The index of the first bitmap vector which may contain an available slot.
+    uint32_t alloc_bit_map_[0];      // The bit map that allocates if each slot is in use.
 
     // bulk_free_bit_map_[] : The bit map that is used for GC to
     // temporarily mark the slots to free without using a lock. After
@@ -225,6 +225,16 @@
     void* End() {
       return reinterpret_cast<byte*>(this) + kPageSize * numOfPages[size_bracket_idx_];
     }
+    // Returns the number of bitmap words per run.
+    size_t NumberOfBitmapVectors() const {
+      return RoundUp(numOfSlots[size_bracket_idx_], 32) / 32;
+    }
+    void SetIsThreadLocal(bool is_thread_local) {
+      is_thread_local_  = is_thread_local ? 1 : 0;
+    }
+    bool IsThreadLocal() const {
+      return is_thread_local_ != 0;
+    }
     // Frees slots in the allocation bit map with regard to the
     // thread-local free bit map. Used when a thread-local run becomes
     // full.
@@ -243,10 +253,13 @@
     void* AllocSlot();
     // Frees a slot in a run. This is used in a non-bulk free.
     void FreeSlot(void* ptr);
-    // Marks the slots to free in the bulk free bit map.
-    void MarkBulkFreeBitMap(void* ptr);
+    // Marks the slots to free in the bulk free bit map. Returns the bracket size.
+    size_t MarkBulkFreeBitMap(void* ptr);
     // Marks the slots to free in the thread-local free bit map.
     void MarkThreadLocalFreeBitMap(void* ptr);
+    // Last word mask, all of the bits in the last word which aren't valid slots are set to
+    // optimize allocation path.
+    static uint32_t GetBitmapLastVectorMask(size_t num_slots, size_t num_vec);
     // Returns true if all the slots in the run are not in use.
     bool IsAllFree();
     // Returns true if all the slots in the run are in use.
@@ -255,8 +268,14 @@
     bool IsBulkFreeBitmapClean();
     // Returns true if the thread local free bit map is clean.
     bool IsThreadLocalFreeBitmapClean();
-    // Clear all the bit maps.
-    void ClearBitMaps();
+    // Set the alloc_bit_map_ bits for slots that are past the end of the run.
+    void SetAllocBitMapBitsForInvalidSlots();
+    // Zero the run's data.
+    void ZeroData();
+    // Zero the run's header.
+    void ZeroHeader();
+    // Fill the alloc bitmap with 1s.
+    void FillAllocBitMap();
     // Iterate over all the slots and apply the given function.
     void InspectAllSlots(void (*handler)(void* start, void* end, size_t used_bytes, void* callback_arg), void* arg);
     // Dump the run metadata for debugging.
@@ -267,8 +286,9 @@
         EXCLUSIVE_LOCKS_REQUIRED(Locks::thread_list_lock_);
 
    private:
-    // The common part of MarkFreeBitMap() and MarkThreadLocalFreeBitMap().
-    void MarkFreeBitMapShared(void* ptr, uint32_t* free_bit_map_base, const char* caller_name);
+    // The common part of MarkFreeBitMap() and MarkThreadLocalFreeBitMap(). Returns the bracket
+    // size.
+    size_t MarkFreeBitMapShared(void* ptr, uint32_t* free_bit_map_base, const char* caller_name);
     // Turns the bit map into a string for debugging.
     static std::string BitMapToStr(uint32_t* bit_map_base, size_t num_vec);
   };
@@ -376,7 +396,7 @@
     return byte_offset / kPageSize;
   }
   // Returns the page map index from an address with rounding.
-  size_t RoundDownToPageMapIndex(void* addr) {
+  size_t RoundDownToPageMapIndex(void* addr) const {
     DCHECK(base_ <= addr && addr < reinterpret_cast<byte*>(base_) + capacity_);
     return (reinterpret_cast<uintptr_t>(addr) - reinterpret_cast<uintptr_t>(base_)) / kPageSize;
   }
@@ -446,12 +466,19 @@
   hash_set<Run*, hash_run, eq_run> full_runs_[kNumOfSizeBrackets];
   // The set of free pages.
   std::set<FreePageRun*> free_page_runs_ GUARDED_BY(lock_);
+  // The dedicated full run, it is always full and shared by all threads when revoking happens.
+  // This is an optimization since enables us to avoid a null check for revoked runs.
+  static Run* dedicated_full_run_;
+  // Using size_t to ensure that it is at least word aligned.
+  static size_t dedicated_full_run_storage_[];
   // The current runs where the allocations are first attempted for
   // the size brackes that do not use thread-local
   // runs. current_runs_[i] is guarded by size_bracket_locks_[i].
   Run* current_runs_[kNumOfSizeBrackets];
   // The mutexes, one per size bracket.
   Mutex* size_bracket_locks_[kNumOfSizeBrackets];
+  // Bracket lock names (since locks only have char* names).
+  std::string size_bracket_lock_names[kNumOfSizeBrackets];
   // The types of page map entries.
   enum {
     kPageMapEmpty           = 0,  // Not allocated.
@@ -493,15 +520,19 @@
   // Page-granularity alloc/free
   void* AllocPages(Thread* self, size_t num_pages, byte page_map_type)
       EXCLUSIVE_LOCKS_REQUIRED(lock_);
-  // Returns how many pages were freed.
-  size_t FreePages(Thread* self, void* ptr) EXCLUSIVE_LOCKS_REQUIRED(lock_);
+  // Returns how many bytes were freed.
+  size_t FreePages(Thread* self, void* ptr, bool already_zero) EXCLUSIVE_LOCKS_REQUIRED(lock_);
 
   // Allocate/free a run slot.
   void* AllocFromRun(Thread* self, size_t size, size_t* bytes_allocated)
       LOCKS_EXCLUDED(lock_);
-  void FreeFromRun(Thread* self, void* ptr, Run* run)
+  // Returns the bracket size.
+  size_t FreeFromRun(Thread* self, void* ptr, Run* run)
       LOCKS_EXCLUDED(lock_);
 
+  // Used to allocate a new thread local run for a size bracket.
+  Run* AllocRun(Thread* self, size_t idx) LOCKS_EXCLUDED(lock_);
+
   // Used to acquire a new/reused run for a size bracket. Used when a
   // thread-local or current run gets full.
   Run* RefillRun(Thread* self, size_t idx) LOCKS_EXCLUDED(lock_);
@@ -558,6 +589,9 @@
   void AssertAllThreadLocalRunsAreRevoked() LOCKS_EXCLUDED(Locks::thread_list_lock_);
   // Dumps the page map for debugging.
   std::string DumpPageMap() EXCLUSIVE_LOCKS_REQUIRED(lock_);
+  static Run* GetDedicatedFullRun() {
+    return dedicated_full_run_;
+  }
 
   // Callbacks for InspectAll that will count the number of bytes
   // allocated and objects allocated, respectively.
diff --git a/runtime/gc/heap.cc b/runtime/gc/heap.cc
index 502da12..5d72bc1 100644
--- a/runtime/gc/heap.cc
+++ b/runtime/gc/heap.cc
@@ -78,9 +78,9 @@
 static constexpr size_t kMinConcurrentRemainingBytes = 128 * KB;
 static constexpr size_t kMaxConcurrentRemainingBytes = 512 * KB;
 // Sticky GC throughput adjustment, divided by 4. Increasing this causes sticky GC to occur more
-// relative to partial/full GC. This is desirable since sticky GCs interfere less with mutator
+// relative to partial/full GC. This may be desirable since sticky GCs interfere less with mutator
 // threads (lower pauses, use less memory bandwidth).
-static constexpr double kStickyGcThroughputAdjustment = 1.25;
+static constexpr double kStickyGcThroughputAdjustment = 1.0;
 // Whether or not we use the free list large object space.
 static constexpr bool kUseFreeListSpaceForLOS = false;
 // Whtehr or not we compact the zygote in PreZygoteFork.
@@ -595,6 +595,11 @@
       if (continuous_space->IsDlMallocSpace()) {
         dlmalloc_space_ = continuous_space->AsDlMallocSpace();
       } else if (continuous_space->IsRosAllocSpace()) {
+        // Revoke before if we already have a rosalloc_space_ so that we don't end up with non full
+        // runs from the previous one during the revoke after.
+        if (rosalloc_space_ != nullptr) {
+          rosalloc_space_->RevokeAllThreadLocalBuffers();
+        }
         rosalloc_space_ = continuous_space->AsRosAllocSpace();
       }
     }
@@ -615,7 +620,7 @@
   }
 }
 
-void Heap::RemoveSpace(space::Space* space) {
+void Heap::RemoveSpace(space::Space* space, bool unset_as_default) {
   DCHECK(space != nullptr);
   WriterMutexLock mu(Thread::Current(), *Locks::heap_bitmap_lock_);
   if (space->IsContinuousSpace()) {
@@ -632,17 +637,19 @@
     auto it = std::find(continuous_spaces_.begin(), continuous_spaces_.end(), continuous_space);
     DCHECK(it != continuous_spaces_.end());
     continuous_spaces_.erase(it);
-    if (continuous_space == dlmalloc_space_) {
-      dlmalloc_space_ = nullptr;
-    } else if (continuous_space == rosalloc_space_) {
-      rosalloc_space_ = nullptr;
-    }
-    if (continuous_space == main_space_) {
-      main_space_ = nullptr;
-    } else if (continuous_space == bump_pointer_space_) {
-      bump_pointer_space_ = nullptr;
-    } else if (continuous_space == temp_space_) {
-      temp_space_ = nullptr;
+    if (unset_as_default) {
+      if (continuous_space == dlmalloc_space_) {
+        dlmalloc_space_ = nullptr;
+      } else if (continuous_space == rosalloc_space_) {
+        rosalloc_space_ = nullptr;
+      }
+      if (continuous_space == main_space_) {
+        main_space_ = nullptr;
+      } else if (continuous_space == bump_pointer_space_) {
+        bump_pointer_space_ = nullptr;
+      } else if (continuous_space == temp_space_) {
+        temp_space_ = nullptr;
+      }
     }
   } else {
     DCHECK(space->IsDiscontinuousSpace());
@@ -725,6 +732,7 @@
   os << "Total mutator paused time: " << PrettyDuration(total_paused_time) << "\n";
   os << "Total time waiting for GC to complete: " << PrettyDuration(total_wait_time_) << "\n";
   os << "Approximate GC data structures memory overhead: " << gc_memory_overhead_;
+  BaseMutex::DumpAll(os);
 }
 
 Heap::~Heap() {
@@ -1432,6 +1440,11 @@
       if (collector_type == collector_type_) {
         return;
       }
+      if (Runtime::Current()->IsShuttingDown(self)) {
+        // Don't allow heap transitions to happen if the runtime is shutting down since these can
+        // cause objects to get finalized.
+        return;
+      }
       // GC can be disabled if someone has a used GetPrimitiveArrayCritical but not yet released.
       if (!copying_transition || disable_moving_gc_count_ == 0) {
         // TODO: Not hard code in semi-space collector?
@@ -1452,6 +1465,10 @@
         // pointer space last transition it will be protected.
         bump_pointer_space_->GetMemMap()->Protect(PROT_READ | PROT_WRITE);
         Compact(bump_pointer_space_, main_space_);
+        // Remove the main space so that we don't try to trim it, this doens't work for debug
+        // builds since RosAlloc attempts to read the magic number from a protected page.
+        // TODO: Clean this up by getting rid of the remove_as_default parameter.
+        RemoveSpace(main_space_, false);
       }
       break;
     }
@@ -1460,6 +1477,7 @@
     case kCollectorTypeCMS: {
       if (IsMovingGc(collector_type_)) {
         // Compact to the main space from the bump pointer space, don't need to swap semispaces.
+        AddSpace(main_space_, false);
         main_space_->GetMemMap()->Protect(PROT_READ | PROT_WRITE);
         Compact(main_space_, bump_pointer_space_);
       }
diff --git a/runtime/gc/heap.h b/runtime/gc/heap.h
index ceba8b6..c37bb05 100644
--- a/runtime/gc/heap.h
+++ b/runtime/gc/heap.h
@@ -289,6 +289,12 @@
   void RegisterGCAllocation(size_t bytes);
   void RegisterGCDeAllocation(size_t bytes);
 
+  // Public due to usage by tests.
+  void AddSpace(space::Space* space, bool set_as_default = true)
+      LOCKS_EXCLUDED(Locks::heap_bitmap_lock_);
+  void RemoveSpace(space::Space* space, bool unset_as_default = true)
+      LOCKS_EXCLUDED(Locks::heap_bitmap_lock_);
+
   // Set target ideal heap utilization ratio, implements
   // dalvik.system.VMRuntime.setTargetHeapUtilization.
   void SetTargetHeapUtilization(float target);
@@ -684,10 +690,6 @@
 
   size_t GetPercentFree();
 
-  void AddSpace(space::Space* space, bool set_as_default = true)
-      LOCKS_EXCLUDED(Locks::heap_bitmap_lock_);
-  void RemoveSpace(space::Space* space) LOCKS_EXCLUDED(Locks::heap_bitmap_lock_);
-
   static void VerificationCallback(mirror::Object* obj, void* arg)
       SHARED_LOCKS_REQUIRED(Locks::heap_bitmap_lock_);
 
diff --git a/runtime/gc/space/rosalloc_space.cc b/runtime/gc/space/rosalloc_space.cc
index a5a6da0..f5c0e94 100644
--- a/runtime/gc/space/rosalloc_space.cc
+++ b/runtime/gc/space/rosalloc_space.cc
@@ -32,7 +32,7 @@
 namespace gc {
 namespace space {
 
-static constexpr bool kPrefetchDuringRosAllocFreeList = true;
+static constexpr bool kPrefetchDuringRosAllocFreeList = false;
 static constexpr size_t kPrefetchLookAhead = 8;
 // Use this only for verification, it is not safe to use since the class of the object may have
 // been freed.
diff --git a/runtime/gc/space/space_test.h b/runtime/gc/space/space_test.h
index 9896a48..28200dfb 100644
--- a/runtime/gc/space/space_test.h
+++ b/runtime/gc/space/space_test.h
@@ -39,10 +39,8 @@
   }
 
   void AddSpace(ContinuousSpace* space) {
-    // For RosAlloc, revoke the thread local runs before moving onto a
-    // new alloc space.
-    Runtime::Current()->GetHeap()->RevokeAllThreadLocalBuffers();
-    Runtime::Current()->GetHeap()->AddSpace(space);
+    // By passing true, AddSpace() does the revoke.
+    Runtime::Current()->GetHeap()->AddSpace(space, true);
   }
 
   mirror::Class* GetByteArrayClass(Thread* self) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
@@ -349,11 +347,8 @@
     EXPECT_EQ(usable_size, computed_usable_size);
   }
 
-  // Release memory and check pointers are nullptr.
+  // Release memory.
   space->FreeList(self, arraysize(lots_of_objects), lots_of_objects);
-  for (size_t i = 0; i < arraysize(lots_of_objects); i++) {
-    EXPECT_TRUE(lots_of_objects[i] == nullptr);
-  }
 
   // Succeeds, fits by adjusting the max allowed footprint.
   for (size_t i = 0; i < arraysize(lots_of_objects); i++) {
@@ -367,12 +362,8 @@
     EXPECT_EQ(usable_size, computed_usable_size);
   }
 
-  // Release memory and check pointers are nullptr
-  // TODO: This isn't compaction safe, fix.
+  // Release memory.
   space->FreeList(self, arraysize(lots_of_objects), lots_of_objects);
-  for (size_t i = 0; i < arraysize(lots_of_objects); i++) {
-    EXPECT_TRUE(lots_of_objects[i] == nullptr);
-  }
 }
 
 void SpaceTest::SizeFootPrintGrowthLimitAndTrimBody(MallocSpace* space, intptr_t object_size,
diff --git a/runtime/instrumentation.cc b/runtime/instrumentation.cc
index 2cd7f49..77d29dd 100644
--- a/runtime/instrumentation.cc
+++ b/runtime/instrumentation.cc
@@ -94,6 +94,7 @@
   }
   if (!method->IsResolutionMethod()) {
     if (quick_code == GetQuickToInterpreterBridge() ||
+        quick_code == GetQuickToInterpreterBridgeTrampoline(Runtime::Current()->GetClassLinker()) ||
         (quick_code == GetQuickResolutionTrampoline(Runtime::Current()->GetClassLinker()) &&
          Runtime::Current()->GetInstrumentation()->IsForcedInterpretOnly()
          && !method->IsNative() && !method->IsProxyMethod())) {
@@ -147,6 +148,7 @@
         // Do not overwrite interpreter to prevent from posting method entry/exit events twice.
         new_portable_code = class_linker->GetPortableOatCodeFor(method, &have_portable_code);
         new_quick_code = class_linker->GetQuickOatCodeFor(method);
+        DCHECK(new_quick_code != GetQuickToInterpreterBridgeTrampoline(class_linker));
         if (entry_exit_stubs_installed_ && new_quick_code != GetQuickToInterpreterBridge()) {
           DCHECK(new_portable_code != GetPortableToInterpreterBridge());
           new_portable_code = GetPortableToInterpreterBridge();
@@ -562,7 +564,8 @@
       new_quick_code = GetQuickToInterpreterBridge();
       new_have_portable_code = false;
     } else if (quick_code == GetQuickResolutionTrampoline(Runtime::Current()->GetClassLinker()) ||
-               quick_code == GetQuickToInterpreterBridge()) {
+        quick_code == GetQuickToInterpreterBridgeTrampoline(Runtime::Current()->GetClassLinker()) ||
+        quick_code == GetQuickToInterpreterBridge()) {
       DCHECK((portable_code == GetPortableResolutionTrampoline(Runtime::Current()->GetClassLinker())) ||
              (portable_code == GetPortableToInterpreterBridge()));
       new_portable_code = portable_code;
@@ -709,9 +712,10 @@
   Runtime* runtime = Runtime::Current();
   if (LIKELY(!instrumentation_stubs_installed_)) {
     const void* code = method->GetEntryPointFromQuickCompiledCode();
-    DCHECK(code != NULL);
-    if (LIKELY(code != GetQuickResolutionTrampoline(runtime->GetClassLinker()) &&
-               code != GetQuickToInterpreterBridge())) {
+    DCHECK(code != nullptr);
+    if (LIKELY(code != GetQuickResolutionTrampoline(runtime->GetClassLinker())) &&
+        LIKELY(code != GetQuickToInterpreterBridgeTrampoline(runtime->GetClassLinker())) &&
+        LIKELY(code != GetQuickToInterpreterBridge())) {
       return code;
     }
   }
diff --git a/runtime/interpreter/interpreter.cc b/runtime/interpreter/interpreter.cc
index 1bf0078..e3f3cd0 100644
--- a/runtime/interpreter/interpreter.cc
+++ b/runtime/interpreter/interpreter.cc
@@ -302,19 +302,19 @@
   exit(0);
 }
 // Explicit definitions of ExecuteGotoImpl.
-template SHARED_LOCKS_REQUIRED(Locks::mutator_lock_)
+template<> SHARED_LOCKS_REQUIRED(Locks::mutator_lock_)
 JValue ExecuteGotoImpl<true, false>(Thread* self, MethodHelper& mh,
                                     const DexFile::CodeItem* code_item,
                                     ShadowFrame& shadow_frame, JValue result_register);
-template SHARED_LOCKS_REQUIRED(Locks::mutator_lock_)
+template<> SHARED_LOCKS_REQUIRED(Locks::mutator_lock_)
 JValue ExecuteGotoImpl<false, false>(Thread* self, MethodHelper& mh,
                                      const DexFile::CodeItem* code_item,
                                      ShadowFrame& shadow_frame, JValue result_register);
-template SHARED_LOCKS_REQUIRED(Locks::mutator_lock_)
+template<> SHARED_LOCKS_REQUIRED(Locks::mutator_lock_)
 JValue ExecuteGotoImpl<true, true>(Thread* self, MethodHelper& mh,
                                     const DexFile::CodeItem* code_item,
                                     ShadowFrame& shadow_frame, JValue result_register);
-template SHARED_LOCKS_REQUIRED(Locks::mutator_lock_)
+template<> SHARED_LOCKS_REQUIRED(Locks::mutator_lock_)
 JValue ExecuteGotoImpl<false, true>(Thread* self, MethodHelper& mh,
                                      const DexFile::CodeItem* code_item,
                                      ShadowFrame& shadow_frame, JValue result_register);
diff --git a/runtime/interpreter/interpreter_common.h b/runtime/interpreter/interpreter_common.h
index 65bdf0e..cc1fa0c 100644
--- a/runtime/interpreter/interpreter_common.h
+++ b/runtime/interpreter/interpreter_common.h
@@ -169,6 +169,13 @@
       return false;
     }
   }
+  // Report this field access to instrumentation if needed.
+  instrumentation::Instrumentation* instrumentation = Runtime::Current()->GetInstrumentation();
+  if (UNLIKELY(instrumentation->HasFieldReadListeners())) {
+    Object* this_object = f->IsStatic() ? nullptr : obj;
+    instrumentation->FieldReadEvent(self, this_object, shadow_frame.GetMethod(),
+                                    shadow_frame.GetDexPC(), f);
+  }
   uint32_t vregA = is_static ? inst->VRegA_21c(inst_data) : inst->VRegA_22c(inst_data);
   switch (field_type) {
     case Primitive::kPrimBoolean:
@@ -210,6 +217,17 @@
     return false;
   }
   MemberOffset field_offset(inst->VRegC_22c());
+  // Report this field access to instrumentation if needed. Since we only have the offset of
+  // the field from the base of the object, we need to look for it first.
+  instrumentation::Instrumentation* instrumentation = Runtime::Current()->GetInstrumentation();
+  if (UNLIKELY(instrumentation->HasFieldReadListeners())) {
+    ArtField* f = ArtField::FindInstanceFieldWithOffset(obj->GetClass(),
+                                                        field_offset.Uint32Value());
+    DCHECK(f != nullptr);
+    DCHECK(!f->IsStatic());
+    instrumentation->FieldReadEvent(Thread::Current(), obj, shadow_frame.GetMethod(),
+                                    shadow_frame.GetDexPC(), f);
+  }
   const bool is_volatile = false;  // iget-x-quick only on non volatile fields.
   const uint32_t vregA = inst->VRegA_22c(inst_data);
   switch (field_type) {
@@ -228,6 +246,39 @@
   return true;
 }
 
+template<Primitive::Type field_type>
+static inline JValue GetFieldValue(const ShadowFrame& shadow_frame, uint32_t vreg)
+    SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
+  JValue field_value;
+  switch (field_type) {
+    case Primitive::kPrimBoolean:
+      field_value.SetZ(static_cast<uint8_t>(shadow_frame.GetVReg(vreg)));
+      break;
+    case Primitive::kPrimByte:
+      field_value.SetB(static_cast<int8_t>(shadow_frame.GetVReg(vreg)));
+      break;
+    case Primitive::kPrimChar:
+      field_value.SetC(static_cast<uint16_t>(shadow_frame.GetVReg(vreg)));
+      break;
+    case Primitive::kPrimShort:
+      field_value.SetS(static_cast<int16_t>(shadow_frame.GetVReg(vreg)));
+      break;
+    case Primitive::kPrimInt:
+      field_value.SetI(shadow_frame.GetVReg(vreg));
+      break;
+    case Primitive::kPrimLong:
+      field_value.SetJ(shadow_frame.GetVRegLong(vreg));
+      break;
+    case Primitive::kPrimNot:
+      field_value.SetL(shadow_frame.GetVRegReference(vreg));
+      break;
+    default:
+      LOG(FATAL) << "Unreachable: " << field_type;
+      break;
+  }
+  return field_value;
+}
+
 // Handles iput-XXX and sput-XXX instructions.
 // Returns true on success, otherwise throws an exception and returns false.
 template<FindFieldType find_type, Primitive::Type field_type, bool do_access_check, bool transaction_active>
@@ -254,6 +305,15 @@
     }
   }
   uint32_t vregA = is_static ? inst->VRegA_21c(inst_data) : inst->VRegA_22c(inst_data);
+  // Report this field access to instrumentation if needed. Since we only have the offset of
+  // the field from the base of the object, we need to look for it first.
+  instrumentation::Instrumentation* instrumentation = Runtime::Current()->GetInstrumentation();
+  if (UNLIKELY(instrumentation->HasFieldWriteListeners())) {
+    JValue field_value = GetFieldValue<field_type>(shadow_frame, vregA);
+    Object* this_object = f->IsStatic() ? nullptr : obj;
+    instrumentation->FieldWriteEvent(self, this_object, shadow_frame.GetMethod(),
+                                     shadow_frame.GetDexPC(), f, field_value);
+  }
   switch (field_type) {
     case Primitive::kPrimBoolean:
       f->SetBoolean<transaction_active>(obj, shadow_frame.GetVReg(vregA));
@@ -309,8 +369,20 @@
     return false;
   }
   MemberOffset field_offset(inst->VRegC_22c());
-  const bool is_volatile = false;  // iput-x-quick only on non volatile fields.
   const uint32_t vregA = inst->VRegA_22c(inst_data);
+  // Report this field modification to instrumentation if needed. Since we only have the offset of
+  // the field from the base of the object, we need to look for it first.
+  instrumentation::Instrumentation* instrumentation = Runtime::Current()->GetInstrumentation();
+  if (UNLIKELY(instrumentation->HasFieldWriteListeners())) {
+    ArtField* f = ArtField::FindInstanceFieldWithOffset(obj->GetClass(),
+                                                        field_offset.Uint32Value());
+    DCHECK(f != nullptr);
+    DCHECK(!f->IsStatic());
+    JValue field_value = GetFieldValue<field_type>(shadow_frame, vregA);
+    instrumentation->FieldWriteEvent(Thread::Current(), obj, shadow_frame.GetMethod(),
+                                     shadow_frame.GetDexPC(), f, field_value);
+  }
+  const bool is_volatile = false;  // iput-x-quick only on non volatile fields.
   switch (field_type) {
     case Primitive::kPrimInt:
       obj->SetField32<transaction_active>(field_offset, shadow_frame.GetVReg(vregA), is_volatile);
diff --git a/runtime/jdwp/jdwp_event.cc b/runtime/jdwp/jdwp_event.cc
index adc1074..223b7a1 100644
--- a/runtime/jdwp/jdwp_event.cc
+++ b/runtime/jdwp/jdwp_event.cc
@@ -108,7 +108,7 @@
  */
 struct ModBasket {
   ModBasket() : pLoc(NULL), threadId(0), classId(0), excepClassId(0),
-                caught(false), field(0), thisPtr(0) { }
+                caught(false), fieldTypeID(0), fieldId(0), thisPtr(0) { }
 
   const JdwpLocation* pLoc;           /* LocationOnly */
   std::string         className;      /* ClassMatch/ClassExclude */
@@ -116,7 +116,8 @@
   RefTypeId           classId;        /* ClassOnly */
   RefTypeId           excepClassId;   /* ExceptionOnly */
   bool                caught;         /* ExceptionOnly */
-  FieldId             field;          /* FieldOnly */
+  RefTypeId           fieldTypeID;    /* FieldOnly */
+  FieldId             fieldId;        /* FieldOnly */
   ObjectId            thisPtr;        /* InstanceOnly */
   /* nothing for StepOnly -- handled differently */
 };
@@ -457,7 +458,10 @@
       }
       break;
     case MK_FIELD_ONLY:
-      if (!Dbg::MatchType(basket->classId, pMod->fieldOnly.refTypeId) || pMod->fieldOnly.fieldId != basket->field) {
+      if (pMod->fieldOnly.fieldId != basket->fieldId) {
+        return false;
+      }
+      if (!Dbg::MatchType(basket->fieldTypeID, pMod->fieldOnly.refTypeId)) {
         return false;
       }
       break;
@@ -848,7 +852,8 @@
   basket.thisPtr = thisPtr;
   basket.threadId = Dbg::GetThreadSelfId();
   basket.className = Dbg::GetClassName(pLoc->class_id);
-  basket.field = fieldId;
+  basket.fieldTypeID = typeId;
+  basket.fieldId = fieldId;
 
   if (InvokeInProgress()) {
     VLOG(jdwp) << "Not posting field event during invoke";
diff --git a/runtime/jdwp/jdwp_handler.cc b/runtime/jdwp/jdwp_handler.cc
index 8ef375b..4843c2b 100644
--- a/runtime/jdwp/jdwp_handler.cc
+++ b/runtime/jdwp/jdwp_handler.cc
@@ -354,8 +354,8 @@
 
 static JdwpError VM_Capabilities(JdwpState*, Request&, ExpandBuf* reply)
     SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
-  expandBufAdd1(reply, false);   // canWatchFieldModification
-  expandBufAdd1(reply, false);   // canWatchFieldAccess
+  expandBufAdd1(reply, true);    // canWatchFieldModification
+  expandBufAdd1(reply, true);    // canWatchFieldAccess
   expandBufAdd1(reply, true);    // canGetBytecodes
   expandBufAdd1(reply, true);    // canGetSyntheticAttribute
   expandBufAdd1(reply, true);    // canGetOwnedMonitorInfo
diff --git a/runtime/jni_internal.cc b/runtime/jni_internal.cc
index c04aabf..fd9c40b 100644
--- a/runtime/jni_internal.cc
+++ b/runtime/jni_internal.cc
@@ -513,14 +513,16 @@
   SafeMap<std::string, SharedLibrary*> libraries_;
 };
 
-#define CHECK_NON_NULL_ARGUMENT(fn, value) \
+#define CHECK_NON_NULL_ARGUMENT(value) CHECK_NON_NULL_ARGUMENT_FN_NAME(__FUNCTION__, value)
+
+#define CHECK_NON_NULL_ARGUMENT_FN_NAME(name, value) \
   if (UNLIKELY(value == nullptr)) { \
-    JniAbortF(#fn, #value " == null"); \
+    JniAbortF(name, #value " == null"); \
   }
 
-#define CHECK_NON_NULL_MEMCPY_ARGUMENT(fn, length, value) \
+#define CHECK_NON_NULL_MEMCPY_ARGUMENT(length, value) \
   if (UNLIKELY(length != 0 && value == nullptr)) { \
-    JniAbortF(#fn, #value " == null"); \
+    JniAbortF(__FUNCTION__, #value " == null"); \
   }
 
 class JNI {
@@ -535,7 +537,7 @@
   }
 
   static jclass FindClass(JNIEnv* env, const char* name) {
-    CHECK_NON_NULL_ARGUMENT(FindClass, name);
+    CHECK_NON_NULL_ARGUMENT(name);
     Runtime* runtime = Runtime::Current();
     ClassLinker* class_linker = runtime->GetClassLinker();
     std::string descriptor(NormalizeJniClassDescriptor(name));
@@ -551,19 +553,19 @@
   }
 
   static jmethodID FromReflectedMethod(JNIEnv* env, jobject jlr_method) {
-    CHECK_NON_NULL_ARGUMENT(FromReflectedMethod, jlr_method);
+    CHECK_NON_NULL_ARGUMENT(jlr_method);
     ScopedObjectAccess soa(env);
     return soa.EncodeMethod(mirror::ArtMethod::FromReflectedMethod(soa, jlr_method));
   }
 
   static jfieldID FromReflectedField(JNIEnv* env, jobject jlr_field) {
-    CHECK_NON_NULL_ARGUMENT(FromReflectedField, jlr_field);
+    CHECK_NON_NULL_ARGUMENT(jlr_field);
     ScopedObjectAccess soa(env);
     return soa.EncodeField(mirror::ArtField::FromReflectedField(soa, jlr_field));
   }
 
   static jobject ToReflectedMethod(JNIEnv* env, jclass, jmethodID mid, jboolean) {
-    CHECK_NON_NULL_ARGUMENT(ToReflectedMethod, mid);
+    CHECK_NON_NULL_ARGUMENT(mid);
     ScopedObjectAccess soa(env);
     mirror::ArtMethod* m = soa.DecodeMethod(mid);
     CHECK(!kMovingMethods);
@@ -578,7 +580,7 @@
   }
 
   static jobject ToReflectedField(JNIEnv* env, jclass, jfieldID fid, jboolean) {
-    CHECK_NON_NULL_ARGUMENT(ToReflectedField, fid);
+    CHECK_NON_NULL_ARGUMENT(fid);
     ScopedObjectAccess soa(env);
     mirror::ArtField* f = soa.DecodeField(fid);
     jobject art_field = soa.AddLocalReference<jobject>(f);
@@ -592,22 +594,22 @@
   }
 
   static jclass GetObjectClass(JNIEnv* env, jobject java_object) {
-    CHECK_NON_NULL_ARGUMENT(GetObjectClass, java_object);
+    CHECK_NON_NULL_ARGUMENT(java_object);
     ScopedObjectAccess soa(env);
     mirror::Object* o = soa.Decode<mirror::Object*>(java_object);
     return soa.AddLocalReference<jclass>(o->GetClass());
   }
 
   static jclass GetSuperclass(JNIEnv* env, jclass java_class) {
-    CHECK_NON_NULL_ARGUMENT(GetSuperclass, java_class);
+    CHECK_NON_NULL_ARGUMENT(java_class);
     ScopedObjectAccess soa(env);
     mirror::Class* c = soa.Decode<mirror::Class*>(java_class);
     return soa.AddLocalReference<jclass>(c->GetSuperClass());
   }
 
   static jboolean IsAssignableFrom(JNIEnv* env, jclass java_class1, jclass java_class2) {
-    CHECK_NON_NULL_ARGUMENT(IsAssignableFrom, java_class1);
-    CHECK_NON_NULL_ARGUMENT(IsAssignableFrom, java_class2);
+    CHECK_NON_NULL_ARGUMENT(java_class1);
+    CHECK_NON_NULL_ARGUMENT(java_class2);
     ScopedObjectAccess soa(env);
     mirror::Class* c1 = soa.Decode<mirror::Class*>(java_class1);
     mirror::Class* c2 = soa.Decode<mirror::Class*>(java_class2);
@@ -615,7 +617,7 @@
   }
 
   static jboolean IsInstanceOf(JNIEnv* env, jobject jobj, jclass java_class) {
-    CHECK_NON_NULL_ARGUMENT(IsInstanceOf, java_class);
+    CHECK_NON_NULL_ARGUMENT(java_class);
     if (jobj == nullptr) {
       // Note: JNI is different from regular Java instanceof in this respect
       return JNI_TRUE;
@@ -639,7 +641,7 @@
   }
 
   static jint ThrowNew(JNIEnv* env, jclass c, const char* msg) {
-    CHECK_NON_NULL_ARGUMENT(ThrowNew, c);
+    CHECK_NON_NULL_ARGUMENT(c);
     return ThrowNewException(env, c, msg, nullptr);
   }
 
@@ -797,7 +799,7 @@
   }
 
   static jobject AllocObject(JNIEnv* env, jclass java_class) {
-    CHECK_NON_NULL_ARGUMENT(AllocObject, java_class);
+    CHECK_NON_NULL_ARGUMENT(java_class);
     ScopedObjectAccess soa(env);
     mirror::Class* c = EnsureInitialized(soa.Self(), soa.Decode<mirror::Class*>(java_class));
     if (c == nullptr) {
@@ -809,16 +811,16 @@
   static jobject NewObject(JNIEnv* env, jclass java_class, jmethodID mid, ...) {
     va_list args;
     va_start(args, mid);
-    CHECK_NON_NULL_ARGUMENT(NewObject, java_class);
-    CHECK_NON_NULL_ARGUMENT(NewObject, mid);
+    CHECK_NON_NULL_ARGUMENT(java_class);
+    CHECK_NON_NULL_ARGUMENT(mid);
     jobject result = NewObjectV(env, java_class, mid, args);
     va_end(args);
     return result;
   }
 
   static jobject NewObjectV(JNIEnv* env, jclass java_class, jmethodID mid, va_list args) {
-    CHECK_NON_NULL_ARGUMENT(NewObjectV, java_class);
-    CHECK_NON_NULL_ARGUMENT(NewObjectV, mid);
+    CHECK_NON_NULL_ARGUMENT(java_class);
+    CHECK_NON_NULL_ARGUMENT(mid);
     ScopedObjectAccess soa(env);
     mirror::Class* c = EnsureInitialized(soa.Self(), soa.Decode<mirror::Class*>(java_class));
     if (c == nullptr) {
@@ -837,8 +839,8 @@
   }
 
   static jobject NewObjectA(JNIEnv* env, jclass java_class, jmethodID mid, jvalue* args) {
-    CHECK_NON_NULL_ARGUMENT(NewObjectA, java_class);
-    CHECK_NON_NULL_ARGUMENT(NewObjectA, mid);
+    CHECK_NON_NULL_ARGUMENT(java_class);
+    CHECK_NON_NULL_ARGUMENT(mid);
     ScopedObjectAccess soa(env);
     mirror::Class* c = EnsureInitialized(soa.Self(), soa.Decode<mirror::Class*>(java_class));
     if (c == nullptr) {
@@ -857,18 +859,18 @@
   }
 
   static jmethodID GetMethodID(JNIEnv* env, jclass java_class, const char* name, const char* sig) {
-    CHECK_NON_NULL_ARGUMENT(GetMethodID, java_class);
-    CHECK_NON_NULL_ARGUMENT(GetMethodID, name);
-    CHECK_NON_NULL_ARGUMENT(GetMethodID, sig);
+    CHECK_NON_NULL_ARGUMENT(java_class);
+    CHECK_NON_NULL_ARGUMENT(name);
+    CHECK_NON_NULL_ARGUMENT(sig);
     ScopedObjectAccess soa(env);
     return FindMethodID(soa, java_class, name, sig, false);
   }
 
   static jmethodID GetStaticMethodID(JNIEnv* env, jclass java_class, const char* name,
                                      const char* sig) {
-    CHECK_NON_NULL_ARGUMENT(GetStaticMethodID, java_class);
-    CHECK_NON_NULL_ARGUMENT(GetStaticMethodID, name);
-    CHECK_NON_NULL_ARGUMENT(GetStaticMethodID, sig);
+    CHECK_NON_NULL_ARGUMENT(java_class);
+    CHECK_NON_NULL_ARGUMENT(name);
+    CHECK_NON_NULL_ARGUMENT(sig);
     ScopedObjectAccess soa(env);
     return FindMethodID(soa, java_class, name, sig, true);
   }
@@ -876,8 +878,8 @@
   static jobject CallObjectMethod(JNIEnv* env, jobject obj, jmethodID mid, ...) {
     va_list ap;
     va_start(ap, mid);
-    CHECK_NON_NULL_ARGUMENT(CallObjectMethod, obj);
-    CHECK_NON_NULL_ARGUMENT(CallObjectMethod, mid);
+    CHECK_NON_NULL_ARGUMENT(obj);
+    CHECK_NON_NULL_ARGUMENT(mid);
     ScopedObjectAccess soa(env);
     JValue result(InvokeVirtualOrInterfaceWithVarArgs(soa, obj, mid, ap));
     va_end(ap);
@@ -885,16 +887,16 @@
   }
 
   static jobject CallObjectMethodV(JNIEnv* env, jobject obj, jmethodID mid, va_list args) {
-    CHECK_NON_NULL_ARGUMENT(CallObjectMethodV, obj);
-    CHECK_NON_NULL_ARGUMENT(CallObjectMethodV, mid);
+    CHECK_NON_NULL_ARGUMENT(obj);
+    CHECK_NON_NULL_ARGUMENT(mid);
     ScopedObjectAccess soa(env);
     JValue result(InvokeVirtualOrInterfaceWithVarArgs(soa, obj, mid, args));
     return soa.AddLocalReference<jobject>(result.GetL());
   }
 
   static jobject CallObjectMethodA(JNIEnv* env, jobject obj, jmethodID mid, jvalue* args) {
-    CHECK_NON_NULL_ARGUMENT(CallObjectMethodA, obj);
-    CHECK_NON_NULL_ARGUMENT(CallObjectMethodA, mid);
+    CHECK_NON_NULL_ARGUMENT(obj);
+    CHECK_NON_NULL_ARGUMENT(mid);
     ScopedObjectAccess soa(env);
     JValue result(InvokeVirtualOrInterfaceWithJValues(soa, soa.Decode<mirror::Object*>(obj), mid,
                                                       args));
@@ -904,8 +906,8 @@
   static jboolean CallBooleanMethod(JNIEnv* env, jobject obj, jmethodID mid, ...) {
     va_list ap;
     va_start(ap, mid);
-    CHECK_NON_NULL_ARGUMENT(CallBooleanMethod, obj);
-    CHECK_NON_NULL_ARGUMENT(CallBooleanMethod, mid);
+    CHECK_NON_NULL_ARGUMENT(obj);
+    CHECK_NON_NULL_ARGUMENT(mid);
     ScopedObjectAccess soa(env);
     JValue result(InvokeVirtualOrInterfaceWithVarArgs(soa, obj, mid, ap));
     va_end(ap);
@@ -913,15 +915,15 @@
   }
 
   static jboolean CallBooleanMethodV(JNIEnv* env, jobject obj, jmethodID mid, va_list args) {
-    CHECK_NON_NULL_ARGUMENT(CallBooleanMethodV, obj);
-    CHECK_NON_NULL_ARGUMENT(CallBooleanMethodV, mid);
+    CHECK_NON_NULL_ARGUMENT(obj);
+    CHECK_NON_NULL_ARGUMENT(mid);
     ScopedObjectAccess soa(env);
     return InvokeVirtualOrInterfaceWithVarArgs(soa, obj, mid, args).GetZ();
   }
 
   static jboolean CallBooleanMethodA(JNIEnv* env, jobject obj, jmethodID mid, jvalue* args) {
-    CHECK_NON_NULL_ARGUMENT(CallBooleanMethodA, obj);
-    CHECK_NON_NULL_ARGUMENT(CallBooleanMethodA, mid);
+    CHECK_NON_NULL_ARGUMENT(obj);
+    CHECK_NON_NULL_ARGUMENT(mid);
     ScopedObjectAccess soa(env);
     return InvokeVirtualOrInterfaceWithJValues(soa, soa.Decode<mirror::Object*>(obj), mid,
                                                args).GetZ();
@@ -930,8 +932,8 @@
   static jbyte CallByteMethod(JNIEnv* env, jobject obj, jmethodID mid, ...) {
     va_list ap;
     va_start(ap, mid);
-    CHECK_NON_NULL_ARGUMENT(CallByteMethod, obj);
-    CHECK_NON_NULL_ARGUMENT(CallByteMethod, mid);
+    CHECK_NON_NULL_ARGUMENT(obj);
+    CHECK_NON_NULL_ARGUMENT(mid);
     ScopedObjectAccess soa(env);
     JValue result(InvokeVirtualOrInterfaceWithVarArgs(soa, obj, mid, ap));
     va_end(ap);
@@ -939,15 +941,15 @@
   }
 
   static jbyte CallByteMethodV(JNIEnv* env, jobject obj, jmethodID mid, va_list args) {
-    CHECK_NON_NULL_ARGUMENT(CallByteMethodV, obj);
-    CHECK_NON_NULL_ARGUMENT(CallByteMethodV, mid);
+    CHECK_NON_NULL_ARGUMENT(obj);
+    CHECK_NON_NULL_ARGUMENT(mid);
     ScopedObjectAccess soa(env);
     return InvokeVirtualOrInterfaceWithVarArgs(soa, obj, mid, args).GetB();
   }
 
   static jbyte CallByteMethodA(JNIEnv* env, jobject obj, jmethodID mid, jvalue* args) {
-    CHECK_NON_NULL_ARGUMENT(CallByteMethodA, obj);
-    CHECK_NON_NULL_ARGUMENT(CallByteMethodA, mid);
+    CHECK_NON_NULL_ARGUMENT(obj);
+    CHECK_NON_NULL_ARGUMENT(mid);
     ScopedObjectAccess soa(env);
     return InvokeVirtualOrInterfaceWithJValues(soa, soa.Decode<mirror::Object*>(obj), mid,
                                                args).GetB();
@@ -956,8 +958,8 @@
   static jchar CallCharMethod(JNIEnv* env, jobject obj, jmethodID mid, ...) {
     va_list ap;
     va_start(ap, mid);
-    CHECK_NON_NULL_ARGUMENT(CallCharMethod, obj);
-    CHECK_NON_NULL_ARGUMENT(CallCharMethod, mid);
+    CHECK_NON_NULL_ARGUMENT(obj);
+    CHECK_NON_NULL_ARGUMENT(mid);
     ScopedObjectAccess soa(env);
     JValue result(InvokeVirtualOrInterfaceWithVarArgs(soa, obj, mid, ap));
     va_end(ap);
@@ -965,15 +967,15 @@
   }
 
   static jchar CallCharMethodV(JNIEnv* env, jobject obj, jmethodID mid, va_list args) {
-    CHECK_NON_NULL_ARGUMENT(CallCharMethodV, obj);
-    CHECK_NON_NULL_ARGUMENT(CallCharMethodV, mid);
+    CHECK_NON_NULL_ARGUMENT(obj);
+    CHECK_NON_NULL_ARGUMENT(mid);
     ScopedObjectAccess soa(env);
     return InvokeVirtualOrInterfaceWithVarArgs(soa, obj, mid, args).GetC();
   }
 
   static jchar CallCharMethodA(JNIEnv* env, jobject obj, jmethodID mid, jvalue* args) {
-    CHECK_NON_NULL_ARGUMENT(CallCharMethodA, obj);
-    CHECK_NON_NULL_ARGUMENT(CallCharMethodA, mid);
+    CHECK_NON_NULL_ARGUMENT(obj);
+    CHECK_NON_NULL_ARGUMENT(mid);
     ScopedObjectAccess soa(env);
     return InvokeVirtualOrInterfaceWithJValues(soa, soa.Decode<mirror::Object*>(obj), mid,
                                                args).GetC();
@@ -982,8 +984,8 @@
   static jdouble CallDoubleMethod(JNIEnv* env, jobject obj, jmethodID mid, ...) {
     va_list ap;
     va_start(ap, mid);
-    CHECK_NON_NULL_ARGUMENT(CallDoubleMethod, obj);
-    CHECK_NON_NULL_ARGUMENT(CallDoubleMethod, mid);
+    CHECK_NON_NULL_ARGUMENT(obj);
+    CHECK_NON_NULL_ARGUMENT(mid);
     ScopedObjectAccess soa(env);
     JValue result(InvokeVirtualOrInterfaceWithVarArgs(soa, obj, mid, ap));
     va_end(ap);
@@ -991,15 +993,15 @@
   }
 
   static jdouble CallDoubleMethodV(JNIEnv* env, jobject obj, jmethodID mid, va_list args) {
-    CHECK_NON_NULL_ARGUMENT(CallDoubleMethodV, obj);
-    CHECK_NON_NULL_ARGUMENT(CallDoubleMethodV, mid);
+    CHECK_NON_NULL_ARGUMENT(obj);
+    CHECK_NON_NULL_ARGUMENT(mid);
     ScopedObjectAccess soa(env);
     return InvokeVirtualOrInterfaceWithVarArgs(soa, obj, mid, args).GetD();
   }
 
   static jdouble CallDoubleMethodA(JNIEnv* env, jobject obj, jmethodID mid, jvalue* args) {
-    CHECK_NON_NULL_ARGUMENT(CallDoubleMethodA, obj);
-    CHECK_NON_NULL_ARGUMENT(CallDoubleMethodA, mid);
+    CHECK_NON_NULL_ARGUMENT(obj);
+    CHECK_NON_NULL_ARGUMENT(mid);
     ScopedObjectAccess soa(env);
     return InvokeVirtualOrInterfaceWithJValues(soa, soa.Decode<mirror::Object*>(obj), mid,
                                                args).GetD();
@@ -1008,8 +1010,8 @@
   static jfloat CallFloatMethod(JNIEnv* env, jobject obj, jmethodID mid, ...) {
     va_list ap;
     va_start(ap, mid);
-    CHECK_NON_NULL_ARGUMENT(CallFloatMethod, obj);
-    CHECK_NON_NULL_ARGUMENT(CallFloatMethod, mid);
+    CHECK_NON_NULL_ARGUMENT(obj);
+    CHECK_NON_NULL_ARGUMENT(mid);
     ScopedObjectAccess soa(env);
     JValue result(InvokeVirtualOrInterfaceWithVarArgs(soa, obj, mid, ap));
     va_end(ap);
@@ -1017,15 +1019,15 @@
   }
 
   static jfloat CallFloatMethodV(JNIEnv* env, jobject obj, jmethodID mid, va_list args) {
-    CHECK_NON_NULL_ARGUMENT(CallFloatMethodV, obj);
-    CHECK_NON_NULL_ARGUMENT(CallFloatMethodV, mid);
+    CHECK_NON_NULL_ARGUMENT(obj);
+    CHECK_NON_NULL_ARGUMENT(mid);
     ScopedObjectAccess soa(env);
     return InvokeVirtualOrInterfaceWithVarArgs(soa, obj, mid, args).GetF();
   }
 
   static jfloat CallFloatMethodA(JNIEnv* env, jobject obj, jmethodID mid, jvalue* args) {
-    CHECK_NON_NULL_ARGUMENT(CallFloatMethodA, obj);
-    CHECK_NON_NULL_ARGUMENT(CallFloatMethodA, mid);
+    CHECK_NON_NULL_ARGUMENT(obj);
+    CHECK_NON_NULL_ARGUMENT(mid);
     ScopedObjectAccess soa(env);
     return InvokeVirtualOrInterfaceWithJValues(soa, soa.Decode<mirror::Object*>(obj), mid,
                                                args).GetF();
@@ -1034,8 +1036,8 @@
   static jint CallIntMethod(JNIEnv* env, jobject obj, jmethodID mid, ...) {
     va_list ap;
     va_start(ap, mid);
-    CHECK_NON_NULL_ARGUMENT(CallIntMethod, obj);
-    CHECK_NON_NULL_ARGUMENT(CallIntMethod, mid);
+    CHECK_NON_NULL_ARGUMENT(obj);
+    CHECK_NON_NULL_ARGUMENT(mid);
     ScopedObjectAccess soa(env);
     JValue result(InvokeVirtualOrInterfaceWithVarArgs(soa, obj, mid, ap));
     va_end(ap);
@@ -1043,15 +1045,15 @@
   }
 
   static jint CallIntMethodV(JNIEnv* env, jobject obj, jmethodID mid, va_list args) {
-    CHECK_NON_NULL_ARGUMENT(CallIntMethodV, obj);
-    CHECK_NON_NULL_ARGUMENT(CallIntMethodV, mid);
+    CHECK_NON_NULL_ARGUMENT(obj);
+    CHECK_NON_NULL_ARGUMENT(mid);
     ScopedObjectAccess soa(env);
     return InvokeVirtualOrInterfaceWithVarArgs(soa, obj, mid, args).GetI();
   }
 
   static jint CallIntMethodA(JNIEnv* env, jobject obj, jmethodID mid, jvalue* args) {
-    CHECK_NON_NULL_ARGUMENT(CallIntMethodA, obj);
-    CHECK_NON_NULL_ARGUMENT(CallIntMethodA, mid);
+    CHECK_NON_NULL_ARGUMENT(obj);
+    CHECK_NON_NULL_ARGUMENT(mid);
     ScopedObjectAccess soa(env);
     return InvokeVirtualOrInterfaceWithJValues(soa, soa.Decode<mirror::Object*>(obj), mid,
                                                args).GetI();
@@ -1060,8 +1062,8 @@
   static jlong CallLongMethod(JNIEnv* env, jobject obj, jmethodID mid, ...) {
     va_list ap;
     va_start(ap, mid);
-    CHECK_NON_NULL_ARGUMENT(CallLongMethod, obj);
-    CHECK_NON_NULL_ARGUMENT(CallLongMethod, mid);
+    CHECK_NON_NULL_ARGUMENT(obj);
+    CHECK_NON_NULL_ARGUMENT(mid);
     ScopedObjectAccess soa(env);
     JValue result(InvokeVirtualOrInterfaceWithVarArgs(soa, obj, mid, ap));
     va_end(ap);
@@ -1069,15 +1071,15 @@
   }
 
   static jlong CallLongMethodV(JNIEnv* env, jobject obj, jmethodID mid, va_list args) {
-    CHECK_NON_NULL_ARGUMENT(CallLongMethodV, obj);
-    CHECK_NON_NULL_ARGUMENT(CallLongMethodV, mid);
+    CHECK_NON_NULL_ARGUMENT(obj);
+    CHECK_NON_NULL_ARGUMENT(mid);
     ScopedObjectAccess soa(env);
     return InvokeVirtualOrInterfaceWithVarArgs(soa, obj, mid, args).GetJ();
   }
 
   static jlong CallLongMethodA(JNIEnv* env, jobject obj, jmethodID mid, jvalue* args) {
-    CHECK_NON_NULL_ARGUMENT(CallLongMethodA, obj);
-    CHECK_NON_NULL_ARGUMENT(CallLongMethodA, mid);
+    CHECK_NON_NULL_ARGUMENT(obj);
+    CHECK_NON_NULL_ARGUMENT(mid);
     ScopedObjectAccess soa(env);
     return InvokeVirtualOrInterfaceWithJValues(soa, soa.Decode<mirror::Object*>(obj), mid,
                                                args).GetJ();
@@ -1086,8 +1088,8 @@
   static jshort CallShortMethod(JNIEnv* env, jobject obj, jmethodID mid, ...) {
     va_list ap;
     va_start(ap, mid);
-    CHECK_NON_NULL_ARGUMENT(CallShortMethod, obj);
-    CHECK_NON_NULL_ARGUMENT(CallShortMethod, mid);
+    CHECK_NON_NULL_ARGUMENT(obj);
+    CHECK_NON_NULL_ARGUMENT(mid);
     ScopedObjectAccess soa(env);
     JValue result(InvokeVirtualOrInterfaceWithVarArgs(soa, obj, mid, ap));
     va_end(ap);
@@ -1095,15 +1097,15 @@
   }
 
   static jshort CallShortMethodV(JNIEnv* env, jobject obj, jmethodID mid, va_list args) {
-    CHECK_NON_NULL_ARGUMENT(CallShortMethodV, obj);
-    CHECK_NON_NULL_ARGUMENT(CallShortMethodV, mid);
+    CHECK_NON_NULL_ARGUMENT(obj);
+    CHECK_NON_NULL_ARGUMENT(mid);
     ScopedObjectAccess soa(env);
     return InvokeVirtualOrInterfaceWithVarArgs(soa, obj, mid, args).GetS();
   }
 
   static jshort CallShortMethodA(JNIEnv* env, jobject obj, jmethodID mid, jvalue* args) {
-    CHECK_NON_NULL_ARGUMENT(CallShortMethodA, obj);
-    CHECK_NON_NULL_ARGUMENT(CallShortMethodA, mid);
+    CHECK_NON_NULL_ARGUMENT(obj);
+    CHECK_NON_NULL_ARGUMENT(mid);
     ScopedObjectAccess soa(env);
     return InvokeVirtualOrInterfaceWithJValues(soa, soa.Decode<mirror::Object*>(obj), mid,
                                                args).GetS();
@@ -1112,23 +1114,23 @@
   static void CallVoidMethod(JNIEnv* env, jobject obj, jmethodID mid, ...) {
     va_list ap;
     va_start(ap, mid);
-    CHECK_NON_NULL_ARGUMENT(CallVoidMethod, obj);
-    CHECK_NON_NULL_ARGUMENT(CallVoidMethod, mid);
+    CHECK_NON_NULL_ARGUMENT(obj);
+    CHECK_NON_NULL_ARGUMENT(mid);
     ScopedObjectAccess soa(env);
     InvokeVirtualOrInterfaceWithVarArgs(soa, obj, mid, ap);
     va_end(ap);
   }
 
   static void CallVoidMethodV(JNIEnv* env, jobject obj, jmethodID mid, va_list args) {
-    CHECK_NON_NULL_ARGUMENT(CallVoidMethodV, obj);
-    CHECK_NON_NULL_ARGUMENT(CallVoidMethodV, mid);
+    CHECK_NON_NULL_ARGUMENT(obj);
+    CHECK_NON_NULL_ARGUMENT(mid);
     ScopedObjectAccess soa(env);
     InvokeVirtualOrInterfaceWithVarArgs(soa, obj, mid, args);
   }
 
   static void CallVoidMethodA(JNIEnv* env, jobject obj, jmethodID mid, jvalue* args) {
-    CHECK_NON_NULL_ARGUMENT(CallVoidMethodA, obj);
-    CHECK_NON_NULL_ARGUMENT(CallVoidMethodA, mid);
+    CHECK_NON_NULL_ARGUMENT(obj);
+    CHECK_NON_NULL_ARGUMENT(mid);
     ScopedObjectAccess soa(env);
     InvokeVirtualOrInterfaceWithJValues(soa, soa.Decode<mirror::Object*>(obj), mid, args);
   }
@@ -1136,8 +1138,8 @@
   static jobject CallNonvirtualObjectMethod(JNIEnv* env, jobject obj, jclass, jmethodID mid, ...) {
     va_list ap;
     va_start(ap, mid);
-    CHECK_NON_NULL_ARGUMENT(CallNonvirtualObjectMethod, obj);
-    CHECK_NON_NULL_ARGUMENT(CallNonvirtualObjectMethod, mid);
+    CHECK_NON_NULL_ARGUMENT(obj);
+    CHECK_NON_NULL_ARGUMENT(mid);
     ScopedObjectAccess soa(env);
     JValue result(InvokeWithVarArgs(soa, obj, mid, ap));
     jobject local_result = soa.AddLocalReference<jobject>(result.GetL());
@@ -1147,8 +1149,8 @@
 
   static jobject CallNonvirtualObjectMethodV(JNIEnv* env, jobject obj, jclass, jmethodID mid,
                                              va_list args) {
-    CHECK_NON_NULL_ARGUMENT(CallNonvirtualObjectMethodV, obj);
-    CHECK_NON_NULL_ARGUMENT(CallNonvirtualObjectMethodV, mid);
+    CHECK_NON_NULL_ARGUMENT(obj);
+    CHECK_NON_NULL_ARGUMENT(mid);
     ScopedObjectAccess soa(env);
     JValue result(InvokeWithVarArgs(soa, obj, mid, args));
     return soa.AddLocalReference<jobject>(result.GetL());
@@ -1156,8 +1158,8 @@
 
   static jobject CallNonvirtualObjectMethodA(JNIEnv* env, jobject obj, jclass, jmethodID mid,
                                              jvalue* args) {
-    CHECK_NON_NULL_ARGUMENT(CallNonvirtualObjectMethodA, obj);
-    CHECK_NON_NULL_ARGUMENT(CallNonvirtualObjectMethodA, mid);
+    CHECK_NON_NULL_ARGUMENT(obj);
+    CHECK_NON_NULL_ARGUMENT(mid);
     ScopedObjectAccess soa(env);
     JValue result(InvokeWithJValues(soa, soa.Decode<mirror::Object*>(obj), mid, args));
     return soa.AddLocalReference<jobject>(result.GetL());
@@ -1167,8 +1169,8 @@
                                               ...) {
     va_list ap;
     va_start(ap, mid);
-    CHECK_NON_NULL_ARGUMENT(CallNonvirtualBooleanMethod, obj);
-    CHECK_NON_NULL_ARGUMENT(CallNonvirtualBooleanMethod, mid);
+    CHECK_NON_NULL_ARGUMENT(obj);
+    CHECK_NON_NULL_ARGUMENT(mid);
     ScopedObjectAccess soa(env);
     JValue result(InvokeWithVarArgs(soa, obj, mid, ap));
     va_end(ap);
@@ -1177,16 +1179,16 @@
 
   static jboolean CallNonvirtualBooleanMethodV(JNIEnv* env, jobject obj, jclass, jmethodID mid,
                                                va_list args) {
-    CHECK_NON_NULL_ARGUMENT(CallNonvirtualBooleanMethodV, obj);
-    CHECK_NON_NULL_ARGUMENT(CallNonvirtualBooleanMethodV, mid);
+    CHECK_NON_NULL_ARGUMENT(obj);
+    CHECK_NON_NULL_ARGUMENT(mid);
     ScopedObjectAccess soa(env);
     return InvokeWithVarArgs(soa, obj, mid, args).GetZ();
   }
 
   static jboolean CallNonvirtualBooleanMethodA(JNIEnv* env, jobject obj, jclass, jmethodID mid,
                                                jvalue* args) {
-    CHECK_NON_NULL_ARGUMENT(CallNonvirtualBooleanMethodA, obj);
-    CHECK_NON_NULL_ARGUMENT(CallNonvirtualBooleanMethodA, mid);
+    CHECK_NON_NULL_ARGUMENT(obj);
+    CHECK_NON_NULL_ARGUMENT(mid);
     ScopedObjectAccess soa(env);
     return InvokeWithJValues(soa, soa.Decode<mirror::Object*>(obj), mid, args).GetZ();
   }
@@ -1194,8 +1196,8 @@
   static jbyte CallNonvirtualByteMethod(JNIEnv* env, jobject obj, jclass, jmethodID mid, ...) {
     va_list ap;
     va_start(ap, mid);
-    CHECK_NON_NULL_ARGUMENT(CallNonvirtualByteMethod, obj);
-    CHECK_NON_NULL_ARGUMENT(CallNonvirtualByteMethod, mid);
+    CHECK_NON_NULL_ARGUMENT(obj);
+    CHECK_NON_NULL_ARGUMENT(mid);
     ScopedObjectAccess soa(env);
     JValue result(InvokeWithVarArgs(soa, obj, mid, ap));
     va_end(ap);
@@ -1204,16 +1206,16 @@
 
   static jbyte CallNonvirtualByteMethodV(JNIEnv* env, jobject obj, jclass, jmethodID mid,
                                          va_list args) {
-    CHECK_NON_NULL_ARGUMENT(CallNonvirtualByteMethodV, obj);
-    CHECK_NON_NULL_ARGUMENT(CallNonvirtualByteMethodV, mid);
+    CHECK_NON_NULL_ARGUMENT(obj);
+    CHECK_NON_NULL_ARGUMENT(mid);
     ScopedObjectAccess soa(env);
     return InvokeWithVarArgs(soa, obj, mid, args).GetB();
   }
 
   static jbyte CallNonvirtualByteMethodA(JNIEnv* env, jobject obj, jclass, jmethodID mid,
                                          jvalue* args) {
-    CHECK_NON_NULL_ARGUMENT(CallNonvirtualByteMethodA, obj);
-    CHECK_NON_NULL_ARGUMENT(CallNonvirtualByteMethodA, mid);
+    CHECK_NON_NULL_ARGUMENT(obj);
+    CHECK_NON_NULL_ARGUMENT(mid);
     ScopedObjectAccess soa(env);
     return InvokeWithJValues(soa, soa.Decode<mirror::Object*>(obj), mid, args).GetB();
   }
@@ -1221,8 +1223,8 @@
   static jchar CallNonvirtualCharMethod(JNIEnv* env, jobject obj, jclass, jmethodID mid, ...) {
     va_list ap;
     va_start(ap, mid);
-    CHECK_NON_NULL_ARGUMENT(CallNonvirtualCharMethod, obj);
-    CHECK_NON_NULL_ARGUMENT(CallNonvirtualCharMethod, mid);
+    CHECK_NON_NULL_ARGUMENT(obj);
+    CHECK_NON_NULL_ARGUMENT(mid);
     ScopedObjectAccess soa(env);
     JValue result(InvokeWithVarArgs(soa, obj, mid, ap));
     va_end(ap);
@@ -1231,16 +1233,16 @@
 
   static jchar CallNonvirtualCharMethodV(JNIEnv* env, jobject obj, jclass, jmethodID mid,
                                          va_list args) {
-    CHECK_NON_NULL_ARGUMENT(CallNonvirtualCharMethodV, obj);
-    CHECK_NON_NULL_ARGUMENT(CallNonvirtualCharMethodV, mid);
+    CHECK_NON_NULL_ARGUMENT(obj);
+    CHECK_NON_NULL_ARGUMENT(mid);
     ScopedObjectAccess soa(env);
     return InvokeWithVarArgs(soa, obj, mid, args).GetC();
   }
 
   static jchar CallNonvirtualCharMethodA(JNIEnv* env, jobject obj, jclass, jmethodID mid,
                                          jvalue* args) {
-    CHECK_NON_NULL_ARGUMENT(CallNonvirtualCharMethodA, obj);
-    CHECK_NON_NULL_ARGUMENT(CallNonvirtualCharMethodA, mid);
+    CHECK_NON_NULL_ARGUMENT(obj);
+    CHECK_NON_NULL_ARGUMENT(mid);
     ScopedObjectAccess soa(env);
     return InvokeWithJValues(soa, soa.Decode<mirror::Object*>(obj), mid, args).GetC();
   }
@@ -1248,8 +1250,8 @@
   static jshort CallNonvirtualShortMethod(JNIEnv* env, jobject obj, jclass, jmethodID mid, ...) {
     va_list ap;
     va_start(ap, mid);
-    CHECK_NON_NULL_ARGUMENT(CallNonvirtualShortMethod, obj);
-    CHECK_NON_NULL_ARGUMENT(CallNonvirtualShortMethod, mid);
+    CHECK_NON_NULL_ARGUMENT(obj);
+    CHECK_NON_NULL_ARGUMENT(mid);
     ScopedObjectAccess soa(env);
     JValue result(InvokeWithVarArgs(soa, obj, mid, ap));
     va_end(ap);
@@ -1258,16 +1260,16 @@
 
   static jshort CallNonvirtualShortMethodV(JNIEnv* env, jobject obj, jclass, jmethodID mid,
                                            va_list args) {
-    CHECK_NON_NULL_ARGUMENT(CallNonvirtualShortMethodV, obj);
-    CHECK_NON_NULL_ARGUMENT(CallNonvirtualShortMethodV, mid);
+    CHECK_NON_NULL_ARGUMENT(obj);
+    CHECK_NON_NULL_ARGUMENT(mid);
     ScopedObjectAccess soa(env);
     return InvokeWithVarArgs(soa, obj, mid, args).GetS();
   }
 
   static jshort CallNonvirtualShortMethodA(JNIEnv* env, jobject obj, jclass, jmethodID mid,
                                            jvalue* args) {
-    CHECK_NON_NULL_ARGUMENT(CallNonvirtualShortMethodA, obj);
-    CHECK_NON_NULL_ARGUMENT(CallNonvirtualShortMethodA, mid);
+    CHECK_NON_NULL_ARGUMENT(obj);
+    CHECK_NON_NULL_ARGUMENT(mid);
     ScopedObjectAccess soa(env);
     return InvokeWithJValues(soa, soa.Decode<mirror::Object*>(obj), mid, args).GetS();
   }
@@ -1275,8 +1277,8 @@
   static jint CallNonvirtualIntMethod(JNIEnv* env, jobject obj, jclass, jmethodID mid, ...) {
     va_list ap;
     va_start(ap, mid);
-    CHECK_NON_NULL_ARGUMENT(CallNonvirtualIntMethod, obj);
-    CHECK_NON_NULL_ARGUMENT(CallNonvirtualIntMethod, mid);
+    CHECK_NON_NULL_ARGUMENT(obj);
+    CHECK_NON_NULL_ARGUMENT(mid);
     ScopedObjectAccess soa(env);
     JValue result(InvokeWithVarArgs(soa, obj, mid, ap));
     va_end(ap);
@@ -1285,16 +1287,16 @@
 
   static jint CallNonvirtualIntMethodV(JNIEnv* env, jobject obj, jclass, jmethodID mid,
                                        va_list args) {
-    CHECK_NON_NULL_ARGUMENT(CallNonvirtualIntMethodV, obj);
-    CHECK_NON_NULL_ARGUMENT(CallNonvirtualIntMethodV, mid);
+    CHECK_NON_NULL_ARGUMENT(obj);
+    CHECK_NON_NULL_ARGUMENT(mid);
     ScopedObjectAccess soa(env);
     return InvokeWithVarArgs(soa, obj, mid, args).GetI();
   }
 
   static jint CallNonvirtualIntMethodA(JNIEnv* env, jobject obj, jclass, jmethodID mid,
                                        jvalue* args) {
-    CHECK_NON_NULL_ARGUMENT(CallNonvirtualIntMethodA, obj);
-    CHECK_NON_NULL_ARGUMENT(CallNonvirtualIntMethodA, mid);
+    CHECK_NON_NULL_ARGUMENT(obj);
+    CHECK_NON_NULL_ARGUMENT(mid);
     ScopedObjectAccess soa(env);
     return InvokeWithJValues(soa, soa.Decode<mirror::Object*>(obj), mid, args).GetI();
   }
@@ -1302,8 +1304,8 @@
   static jlong CallNonvirtualLongMethod(JNIEnv* env, jobject obj, jclass, jmethodID mid, ...) {
     va_list ap;
     va_start(ap, mid);
-    CHECK_NON_NULL_ARGUMENT(CallNonvirtualLongMethod, obj);
-    CHECK_NON_NULL_ARGUMENT(CallNonvirtualLongMethod, mid);
+    CHECK_NON_NULL_ARGUMENT(obj);
+    CHECK_NON_NULL_ARGUMENT(mid);
     ScopedObjectAccess soa(env);
     JValue result(InvokeWithVarArgs(soa, obj, mid, ap));
     va_end(ap);
@@ -1312,16 +1314,16 @@
 
   static jlong CallNonvirtualLongMethodV(JNIEnv* env, jobject obj, jclass, jmethodID mid,
                                          va_list args) {
-    CHECK_NON_NULL_ARGUMENT(CallNonvirtualLongMethodV, obj);
-    CHECK_NON_NULL_ARGUMENT(CallNonvirtualLongMethodV, mid);
+    CHECK_NON_NULL_ARGUMENT(obj);
+    CHECK_NON_NULL_ARGUMENT(mid);
     ScopedObjectAccess soa(env);
     return InvokeWithVarArgs(soa, obj, mid, args).GetJ();
   }
 
   static jlong CallNonvirtualLongMethodA(JNIEnv* env, jobject obj, jclass, jmethodID mid,
                                          jvalue* args) {
-    CHECK_NON_NULL_ARGUMENT(CallNonvirtualLongMethodA, obj);
-    CHECK_NON_NULL_ARGUMENT(CallNonvirtualLongMethodA, mid);
+    CHECK_NON_NULL_ARGUMENT(obj);
+    CHECK_NON_NULL_ARGUMENT(mid);
     ScopedObjectAccess soa(env);
     return InvokeWithJValues(soa, soa.Decode<mirror::Object*>(obj), mid, args).GetJ();
   }
@@ -1329,8 +1331,8 @@
   static jfloat CallNonvirtualFloatMethod(JNIEnv* env, jobject obj, jclass, jmethodID mid, ...) {
     va_list ap;
     va_start(ap, mid);
-    CHECK_NON_NULL_ARGUMENT(CallNonvirtualFloatMethod, obj);
-    CHECK_NON_NULL_ARGUMENT(CallNonvirtualFloatMethod, mid);
+    CHECK_NON_NULL_ARGUMENT(obj);
+    CHECK_NON_NULL_ARGUMENT(mid);
     ScopedObjectAccess soa(env);
     JValue result(InvokeWithVarArgs(soa, obj, mid, ap));
     va_end(ap);
@@ -1339,16 +1341,16 @@
 
   static jfloat CallNonvirtualFloatMethodV(JNIEnv* env, jobject obj, jclass, jmethodID mid,
                                            va_list args) {
-    CHECK_NON_NULL_ARGUMENT(CallNonvirtualFloatMethodV, obj);
-    CHECK_NON_NULL_ARGUMENT(CallNonvirtualFloatMethodV, mid);
+    CHECK_NON_NULL_ARGUMENT(obj);
+    CHECK_NON_NULL_ARGUMENT(mid);
     ScopedObjectAccess soa(env);
     return InvokeWithVarArgs(soa, obj, mid, args).GetF();
   }
 
   static jfloat CallNonvirtualFloatMethodA(JNIEnv* env, jobject obj, jclass, jmethodID mid,
                                            jvalue* args) {
-    CHECK_NON_NULL_ARGUMENT(CallNonvirtualFloatMethodA, obj);
-    CHECK_NON_NULL_ARGUMENT(CallNonvirtualFloatMethodA, mid);
+    CHECK_NON_NULL_ARGUMENT(obj);
+    CHECK_NON_NULL_ARGUMENT(mid);
     ScopedObjectAccess soa(env);
     return InvokeWithJValues(soa, soa.Decode<mirror::Object*>(obj), mid, args).GetF();
   }
@@ -1356,8 +1358,8 @@
   static jdouble CallNonvirtualDoubleMethod(JNIEnv* env, jobject obj, jclass, jmethodID mid, ...) {
     va_list ap;
     va_start(ap, mid);
-    CHECK_NON_NULL_ARGUMENT(CallNonvirtualDoubleMethod, obj);
-    CHECK_NON_NULL_ARGUMENT(CallNonvirtualDoubleMethod, mid);
+    CHECK_NON_NULL_ARGUMENT(obj);
+    CHECK_NON_NULL_ARGUMENT(mid);
     ScopedObjectAccess soa(env);
     JValue result(InvokeWithVarArgs(soa, obj, mid, ap));
     va_end(ap);
@@ -1366,16 +1368,16 @@
 
   static jdouble CallNonvirtualDoubleMethodV(JNIEnv* env, jobject obj, jclass, jmethodID mid,
                                              va_list args) {
-    CHECK_NON_NULL_ARGUMENT(CallNonvirtualDoubleMethodV, obj);
-    CHECK_NON_NULL_ARGUMENT(CallNonvirtualDoubleMethodV, mid);
+    CHECK_NON_NULL_ARGUMENT(obj);
+    CHECK_NON_NULL_ARGUMENT(mid);
     ScopedObjectAccess soa(env);
     return InvokeWithVarArgs(soa, obj, mid, args).GetD();
   }
 
   static jdouble CallNonvirtualDoubleMethodA(JNIEnv* env, jobject obj, jclass, jmethodID mid,
                                              jvalue* args) {
-    CHECK_NON_NULL_ARGUMENT(CallNonvirtualDoubleMethodA, obj);
-    CHECK_NON_NULL_ARGUMENT(CallNonvirtualDoubleMethodA, mid);
+    CHECK_NON_NULL_ARGUMENT(obj);
+    CHECK_NON_NULL_ARGUMENT(mid);
     ScopedObjectAccess soa(env);
     return InvokeWithJValues(soa, soa.Decode<mirror::Object*>(obj), mid, args).GetD();
   }
@@ -1383,8 +1385,8 @@
   static void CallNonvirtualVoidMethod(JNIEnv* env, jobject obj, jclass, jmethodID mid, ...) {
     va_list ap;
     va_start(ap, mid);
-    CHECK_NON_NULL_ARGUMENT(CallNonvirtualVoidMethod, obj);
-    CHECK_NON_NULL_ARGUMENT(CallNonvirtualVoidMethod, mid);
+    CHECK_NON_NULL_ARGUMENT(obj);
+    CHECK_NON_NULL_ARGUMENT(mid);
     ScopedObjectAccess soa(env);
     InvokeWithVarArgs(soa, obj, mid, ap);
     va_end(ap);
@@ -1392,40 +1394,40 @@
 
   static void CallNonvirtualVoidMethodV(JNIEnv* env, jobject obj, jclass, jmethodID mid,
                                         va_list args) {
-    CHECK_NON_NULL_ARGUMENT(CallNonvirtualVoidMethodV, obj);
-    CHECK_NON_NULL_ARGUMENT(CallNonvirtualVoidMethodV, mid);
+    CHECK_NON_NULL_ARGUMENT(obj);
+    CHECK_NON_NULL_ARGUMENT(mid);
     ScopedObjectAccess soa(env);
     InvokeWithVarArgs(soa, obj, mid, args);
   }
 
   static void CallNonvirtualVoidMethodA(JNIEnv* env, jobject obj, jclass, jmethodID mid,
                                         jvalue* args) {
-    CHECK_NON_NULL_ARGUMENT(CallNonvirtualVoidMethodA, obj);
-    CHECK_NON_NULL_ARGUMENT(CallNonvirtualVoidMethodA, mid);
+    CHECK_NON_NULL_ARGUMENT(obj);
+    CHECK_NON_NULL_ARGUMENT(mid);
     ScopedObjectAccess soa(env);
     InvokeWithJValues(soa, soa.Decode<mirror::Object*>(obj), mid, args);
   }
 
   static jfieldID GetFieldID(JNIEnv* env, jclass java_class, const char* name, const char* sig) {
-    CHECK_NON_NULL_ARGUMENT(GetFieldID, java_class);
-    CHECK_NON_NULL_ARGUMENT(GetFieldID, name);
-    CHECK_NON_NULL_ARGUMENT(GetFieldID, sig);
+    CHECK_NON_NULL_ARGUMENT(java_class);
+    CHECK_NON_NULL_ARGUMENT(name);
+    CHECK_NON_NULL_ARGUMENT(sig);
     ScopedObjectAccess soa(env);
     return FindFieldID(soa, java_class, name, sig, false);
   }
 
   static jfieldID GetStaticFieldID(JNIEnv* env, jclass java_class, const char* name,
                                    const char* sig) {
-    CHECK_NON_NULL_ARGUMENT(GetStaticFieldID, java_class);
-    CHECK_NON_NULL_ARGUMENT(GetStaticFieldID, name);
-    CHECK_NON_NULL_ARGUMENT(GetFieldID, sig);
+    CHECK_NON_NULL_ARGUMENT(java_class);
+    CHECK_NON_NULL_ARGUMENT(name);
+    CHECK_NON_NULL_ARGUMENT(sig);
     ScopedObjectAccess soa(env);
     return FindFieldID(soa, java_class, name, sig, true);
   }
 
   static jobject GetObjectField(JNIEnv* env, jobject obj, jfieldID fid) {
-    CHECK_NON_NULL_ARGUMENT(GetObjectField, obj);
-    CHECK_NON_NULL_ARGUMENT(GetObjectField, fid);
+    CHECK_NON_NULL_ARGUMENT(obj);
+    CHECK_NON_NULL_ARGUMENT(fid);
     ScopedObjectAccess soa(env);
     mirror::Object* o = soa.Decode<mirror::Object*>(obj);
     mirror::ArtField* f = soa.DecodeField(fid);
@@ -1433,15 +1435,15 @@
   }
 
   static jobject GetStaticObjectField(JNIEnv* env, jclass, jfieldID fid) {
-    CHECK_NON_NULL_ARGUMENT(GetStaticObjectField, fid);
+    CHECK_NON_NULL_ARGUMENT(fid);
     ScopedObjectAccess soa(env);
     mirror::ArtField* f = soa.DecodeField(fid);
     return soa.AddLocalReference<jobject>(f->GetObject(f->GetDeclaringClass()));
   }
 
   static void SetObjectField(JNIEnv* env, jobject java_object, jfieldID fid, jobject java_value) {
-    CHECK_NON_NULL_ARGUMENT(SetObjectField, java_object);
-    CHECK_NON_NULL_ARGUMENT(SetObjectField, fid);
+    CHECK_NON_NULL_ARGUMENT(java_object);
+    CHECK_NON_NULL_ARGUMENT(fid);
     ScopedObjectAccess soa(env);
     mirror::Object* o = soa.Decode<mirror::Object*>(java_object);
     mirror::Object* v = soa.Decode<mirror::Object*>(java_value);
@@ -1450,7 +1452,7 @@
   }
 
   static void SetStaticObjectField(JNIEnv* env, jclass, jfieldID fid, jobject java_value) {
-    CHECK_NON_NULL_ARGUMENT(SetStaticObjectField, fid);
+    CHECK_NON_NULL_ARGUMENT(fid);
     ScopedObjectAccess soa(env);
     mirror::Object* v = soa.Decode<mirror::Object*>(java_value);
     mirror::ArtField* f = soa.DecodeField(fid);
@@ -1458,29 +1460,29 @@
   }
 
 #define GET_PRIMITIVE_FIELD(fn, instance) \
-  CHECK_NON_NULL_ARGUMENT(Get #fn Field, instance); \
-  CHECK_NON_NULL_ARGUMENT(Get #fn Field, fid); \
+  CHECK_NON_NULL_ARGUMENT(instance); \
+  CHECK_NON_NULL_ARGUMENT(fid); \
   ScopedObjectAccess soa(env); \
   mirror::Object* o = soa.Decode<mirror::Object*>(instance); \
   mirror::ArtField* f = soa.DecodeField(fid); \
   return f->Get ##fn (o)
 
 #define GET_STATIC_PRIMITIVE_FIELD(fn) \
-  CHECK_NON_NULL_ARGUMENT(GetStatic #fn Field, fid); \
+  CHECK_NON_NULL_ARGUMENT(fid); \
   ScopedObjectAccess soa(env); \
   mirror::ArtField* f = soa.DecodeField(fid); \
   return f->Get ##fn (f->GetDeclaringClass())
 
 #define SET_PRIMITIVE_FIELD(fn, instance, value) \
-  CHECK_NON_NULL_ARGUMENT(Set #fn Field, instance); \
-  CHECK_NON_NULL_ARGUMENT(Set #fn Field, fid); \
+  CHECK_NON_NULL_ARGUMENT(instance); \
+  CHECK_NON_NULL_ARGUMENT(fid); \
   ScopedObjectAccess soa(env); \
   mirror::Object* o = soa.Decode<mirror::Object*>(instance); \
   mirror::ArtField* f = soa.DecodeField(fid); \
   f->Set ##fn <false>(o, value)
 
 #define SET_STATIC_PRIMITIVE_FIELD(fn, value) \
-  CHECK_NON_NULL_ARGUMENT(SetStatic #fn Field, fid); \
+  CHECK_NON_NULL_ARGUMENT(fid); \
   ScopedObjectAccess soa(env); \
   mirror::ArtField* f = soa.DecodeField(fid); \
   f->Set ##fn <false>(f->GetDeclaringClass(), value)
@@ -1616,7 +1618,7 @@
   static jobject CallStaticObjectMethod(JNIEnv* env, jclass, jmethodID mid, ...) {
     va_list ap;
     va_start(ap, mid);
-    CHECK_NON_NULL_ARGUMENT(CallStaticObjectMethod, mid);
+    CHECK_NON_NULL_ARGUMENT(mid);
     ScopedObjectAccess soa(env);
     JValue result(InvokeWithVarArgs(soa, nullptr, mid, ap));
     jobject local_result = soa.AddLocalReference<jobject>(result.GetL());
@@ -1625,14 +1627,14 @@
   }
 
   static jobject CallStaticObjectMethodV(JNIEnv* env, jclass, jmethodID mid, va_list args) {
-    CHECK_NON_NULL_ARGUMENT(CallStaticObjectMethodV, mid);
+    CHECK_NON_NULL_ARGUMENT(mid);
     ScopedObjectAccess soa(env);
     JValue result(InvokeWithVarArgs(soa, nullptr, mid, args));
     return soa.AddLocalReference<jobject>(result.GetL());
   }
 
   static jobject CallStaticObjectMethodA(JNIEnv* env, jclass, jmethodID mid, jvalue* args) {
-    CHECK_NON_NULL_ARGUMENT(CallStaticObjectMethodA, mid);
+    CHECK_NON_NULL_ARGUMENT(mid);
     ScopedObjectAccess soa(env);
     JValue result(InvokeWithJValues(soa, nullptr, mid, args));
     return soa.AddLocalReference<jobject>(result.GetL());
@@ -1641,7 +1643,7 @@
   static jboolean CallStaticBooleanMethod(JNIEnv* env, jclass, jmethodID mid, ...) {
     va_list ap;
     va_start(ap, mid);
-    CHECK_NON_NULL_ARGUMENT(CallStaticBooleanMethod, mid);
+    CHECK_NON_NULL_ARGUMENT(mid);
     ScopedObjectAccess soa(env);
     JValue result(InvokeWithVarArgs(soa, nullptr, mid, ap));
     va_end(ap);
@@ -1649,13 +1651,13 @@
   }
 
   static jboolean CallStaticBooleanMethodV(JNIEnv* env, jclass, jmethodID mid, va_list args) {
-    CHECK_NON_NULL_ARGUMENT(CallStaticBooleanMethodV, mid);
+    CHECK_NON_NULL_ARGUMENT(mid);
     ScopedObjectAccess soa(env);
     return InvokeWithVarArgs(soa, nullptr, mid, args).GetZ();
   }
 
   static jboolean CallStaticBooleanMethodA(JNIEnv* env, jclass, jmethodID mid, jvalue* args) {
-    CHECK_NON_NULL_ARGUMENT(CallStaticBooleanMethodA, mid);
+    CHECK_NON_NULL_ARGUMENT(mid);
     ScopedObjectAccess soa(env);
     return InvokeWithJValues(soa, nullptr, mid, args).GetZ();
   }
@@ -1663,7 +1665,7 @@
   static jbyte CallStaticByteMethod(JNIEnv* env, jclass, jmethodID mid, ...) {
     va_list ap;
     va_start(ap, mid);
-    CHECK_NON_NULL_ARGUMENT(CallStaticByteMethod, mid);
+    CHECK_NON_NULL_ARGUMENT(mid);
     ScopedObjectAccess soa(env);
     JValue result(InvokeWithVarArgs(soa, nullptr, mid, ap));
     va_end(ap);
@@ -1671,13 +1673,13 @@
   }
 
   static jbyte CallStaticByteMethodV(JNIEnv* env, jclass, jmethodID mid, va_list args) {
-    CHECK_NON_NULL_ARGUMENT(CallStaticByteMethodV, mid);
+    CHECK_NON_NULL_ARGUMENT(mid);
     ScopedObjectAccess soa(env);
     return InvokeWithVarArgs(soa, nullptr, mid, args).GetB();
   }
 
   static jbyte CallStaticByteMethodA(JNIEnv* env, jclass, jmethodID mid, jvalue* args) {
-    CHECK_NON_NULL_ARGUMENT(CallStaticByteMethodA, mid);
+    CHECK_NON_NULL_ARGUMENT(mid);
     ScopedObjectAccess soa(env);
     return InvokeWithJValues(soa, nullptr, mid, args).GetB();
   }
@@ -1685,7 +1687,7 @@
   static jchar CallStaticCharMethod(JNIEnv* env, jclass, jmethodID mid, ...) {
     va_list ap;
     va_start(ap, mid);
-    CHECK_NON_NULL_ARGUMENT(CallStaticCharMethod, mid);
+    CHECK_NON_NULL_ARGUMENT(mid);
     ScopedObjectAccess soa(env);
     JValue result(InvokeWithVarArgs(soa, nullptr, mid, ap));
     va_end(ap);
@@ -1693,13 +1695,13 @@
   }
 
   static jchar CallStaticCharMethodV(JNIEnv* env, jclass, jmethodID mid, va_list args) {
-    CHECK_NON_NULL_ARGUMENT(CallStaticCharMethodV, mid);
+    CHECK_NON_NULL_ARGUMENT(mid);
     ScopedObjectAccess soa(env);
     return InvokeWithVarArgs(soa, nullptr, mid, args).GetC();
   }
 
   static jchar CallStaticCharMethodA(JNIEnv* env, jclass, jmethodID mid, jvalue* args) {
-    CHECK_NON_NULL_ARGUMENT(CallStaticCharMethodA, mid);
+    CHECK_NON_NULL_ARGUMENT(mid);
     ScopedObjectAccess soa(env);
     return InvokeWithJValues(soa, nullptr, mid, args).GetC();
   }
@@ -1707,7 +1709,7 @@
   static jshort CallStaticShortMethod(JNIEnv* env, jclass, jmethodID mid, ...) {
     va_list ap;
     va_start(ap, mid);
-    CHECK_NON_NULL_ARGUMENT(CallStaticShortMethod, mid);
+    CHECK_NON_NULL_ARGUMENT(mid);
     ScopedObjectAccess soa(env);
     JValue result(InvokeWithVarArgs(soa, nullptr, mid, ap));
     va_end(ap);
@@ -1715,13 +1717,13 @@
   }
 
   static jshort CallStaticShortMethodV(JNIEnv* env, jclass, jmethodID mid, va_list args) {
-    CHECK_NON_NULL_ARGUMENT(CallStaticShortMethodV, mid);
+    CHECK_NON_NULL_ARGUMENT(mid);
     ScopedObjectAccess soa(env);
     return InvokeWithVarArgs(soa, nullptr, mid, args).GetS();
   }
 
   static jshort CallStaticShortMethodA(JNIEnv* env, jclass, jmethodID mid, jvalue* args) {
-    CHECK_NON_NULL_ARGUMENT(CallStaticShortMethodA, mid);
+    CHECK_NON_NULL_ARGUMENT(mid);
     ScopedObjectAccess soa(env);
     return InvokeWithJValues(soa, nullptr, mid, args).GetS();
   }
@@ -1729,7 +1731,7 @@
   static jint CallStaticIntMethod(JNIEnv* env, jclass, jmethodID mid, ...) {
     va_list ap;
     va_start(ap, mid);
-    CHECK_NON_NULL_ARGUMENT(CallStaticIntMethod, mid);
+    CHECK_NON_NULL_ARGUMENT(mid);
     ScopedObjectAccess soa(env);
     JValue result(InvokeWithVarArgs(soa, nullptr, mid, ap));
     va_end(ap);
@@ -1737,13 +1739,13 @@
   }
 
   static jint CallStaticIntMethodV(JNIEnv* env, jclass, jmethodID mid, va_list args) {
-    CHECK_NON_NULL_ARGUMENT(CallStaticIntMethodV, mid);
+    CHECK_NON_NULL_ARGUMENT(mid);
     ScopedObjectAccess soa(env);
     return InvokeWithVarArgs(soa, nullptr, mid, args).GetI();
   }
 
   static jint CallStaticIntMethodA(JNIEnv* env, jclass, jmethodID mid, jvalue* args) {
-    CHECK_NON_NULL_ARGUMENT(CallStaticIntMethodA, mid);
+    CHECK_NON_NULL_ARGUMENT(mid);
     ScopedObjectAccess soa(env);
     return InvokeWithJValues(soa, nullptr, mid, args).GetI();
   }
@@ -1751,7 +1753,7 @@
   static jlong CallStaticLongMethod(JNIEnv* env, jclass, jmethodID mid, ...) {
     va_list ap;
     va_start(ap, mid);
-    CHECK_NON_NULL_ARGUMENT(CallStaticLongMethod, mid);
+    CHECK_NON_NULL_ARGUMENT(mid);
     ScopedObjectAccess soa(env);
     JValue result(InvokeWithVarArgs(soa, nullptr, mid, ap));
     va_end(ap);
@@ -1759,13 +1761,13 @@
   }
 
   static jlong CallStaticLongMethodV(JNIEnv* env, jclass, jmethodID mid, va_list args) {
-    CHECK_NON_NULL_ARGUMENT(CallStaticLongMethodV, mid);
+    CHECK_NON_NULL_ARGUMENT(mid);
     ScopedObjectAccess soa(env);
     return InvokeWithVarArgs(soa, nullptr, mid, args).GetJ();
   }
 
   static jlong CallStaticLongMethodA(JNIEnv* env, jclass, jmethodID mid, jvalue* args) {
-    CHECK_NON_NULL_ARGUMENT(CallStaticLongMethodA, mid);
+    CHECK_NON_NULL_ARGUMENT(mid);
     ScopedObjectAccess soa(env);
     return InvokeWithJValues(soa, nullptr, mid, args).GetJ();
   }
@@ -1773,7 +1775,7 @@
   static jfloat CallStaticFloatMethod(JNIEnv* env, jclass, jmethodID mid, ...) {
     va_list ap;
     va_start(ap, mid);
-    CHECK_NON_NULL_ARGUMENT(CallStaticFloatMethod, mid);
+    CHECK_NON_NULL_ARGUMENT(mid);
     ScopedObjectAccess soa(env);
     JValue result(InvokeWithVarArgs(soa, nullptr, mid, ap));
     va_end(ap);
@@ -1781,13 +1783,13 @@
   }
 
   static jfloat CallStaticFloatMethodV(JNIEnv* env, jclass, jmethodID mid, va_list args) {
-    CHECK_NON_NULL_ARGUMENT(CallStaticFloatMethodV, mid);
+    CHECK_NON_NULL_ARGUMENT(mid);
     ScopedObjectAccess soa(env);
     return InvokeWithVarArgs(soa, nullptr, mid, args).GetF();
   }
 
   static jfloat CallStaticFloatMethodA(JNIEnv* env, jclass, jmethodID mid, jvalue* args) {
-    CHECK_NON_NULL_ARGUMENT(CallStaticFloatMethodA, mid);
+    CHECK_NON_NULL_ARGUMENT(mid);
     ScopedObjectAccess soa(env);
     return InvokeWithJValues(soa, nullptr, mid, args).GetF();
   }
@@ -1795,7 +1797,7 @@
   static jdouble CallStaticDoubleMethod(JNIEnv* env, jclass, jmethodID mid, ...) {
     va_list ap;
     va_start(ap, mid);
-    CHECK_NON_NULL_ARGUMENT(CallStaticDoubleMethod, mid);
+    CHECK_NON_NULL_ARGUMENT(mid);
     ScopedObjectAccess soa(env);
     JValue result(InvokeWithVarArgs(soa, nullptr, mid, ap));
     va_end(ap);
@@ -1803,13 +1805,13 @@
   }
 
   static jdouble CallStaticDoubleMethodV(JNIEnv* env, jclass, jmethodID mid, va_list args) {
-    CHECK_NON_NULL_ARGUMENT(CallStaticDoubleMethodV, mid);
+    CHECK_NON_NULL_ARGUMENT(mid);
     ScopedObjectAccess soa(env);
     return InvokeWithVarArgs(soa, nullptr, mid, args).GetD();
   }
 
   static jdouble CallStaticDoubleMethodA(JNIEnv* env, jclass, jmethodID mid, jvalue* args) {
-    CHECK_NON_NULL_ARGUMENT(CallStaticDoubleMethodA, mid);
+    CHECK_NON_NULL_ARGUMENT(mid);
     ScopedObjectAccess soa(env);
     return InvokeWithJValues(soa, nullptr, mid, args).GetD();
   }
@@ -1817,20 +1819,20 @@
   static void CallStaticVoidMethod(JNIEnv* env, jclass, jmethodID mid, ...) {
     va_list ap;
     va_start(ap, mid);
-    CHECK_NON_NULL_ARGUMENT(CallStaticVoidMethod, mid);
+    CHECK_NON_NULL_ARGUMENT(mid);
     ScopedObjectAccess soa(env);
     InvokeWithVarArgs(soa, nullptr, mid, ap);
     va_end(ap);
   }
 
   static void CallStaticVoidMethodV(JNIEnv* env, jclass, jmethodID mid, va_list args) {
-    CHECK_NON_NULL_ARGUMENT(CallStaticVoidMethodV, mid);
+    CHECK_NON_NULL_ARGUMENT(mid);
     ScopedObjectAccess soa(env);
     InvokeWithVarArgs(soa, nullptr, mid, args);
   }
 
   static void CallStaticVoidMethodA(JNIEnv* env, jclass, jmethodID mid, jvalue* args) {
-    CHECK_NON_NULL_ARGUMENT(CallStaticVoidMethodA, mid);
+    CHECK_NON_NULL_ARGUMENT(mid);
     ScopedObjectAccess soa(env);
     InvokeWithJValues(soa, nullptr, mid, args);
   }
@@ -1859,26 +1861,26 @@
   }
 
   static jsize GetStringLength(JNIEnv* env, jstring java_string) {
-    CHECK_NON_NULL_ARGUMENT(GetStringLength, java_string);
+    CHECK_NON_NULL_ARGUMENT(java_string);
     ScopedObjectAccess soa(env);
     return soa.Decode<mirror::String*>(java_string)->GetLength();
   }
 
   static jsize GetStringUTFLength(JNIEnv* env, jstring java_string) {
-    CHECK_NON_NULL_ARGUMENT(GetStringLength, java_string);
+    CHECK_NON_NULL_ARGUMENT(java_string);
     ScopedObjectAccess soa(env);
     return soa.Decode<mirror::String*>(java_string)->GetUtfLength();
   }
 
   static void GetStringRegion(JNIEnv* env, jstring java_string, jsize start, jsize length,
                               jchar* buf) {
-    CHECK_NON_NULL_ARGUMENT(GetStringRegion, java_string);
+    CHECK_NON_NULL_ARGUMENT(java_string);
     ScopedObjectAccess soa(env);
     mirror::String* s = soa.Decode<mirror::String*>(java_string);
     if (start < 0 || length < 0 || start + length > s->GetLength()) {
       ThrowSIOOBE(soa, start, length, s->GetLength());
     } else {
-      CHECK_NON_NULL_MEMCPY_ARGUMENT(GetStringRegion, length, buf);
+      CHECK_NON_NULL_MEMCPY_ARGUMENT(length, buf);
       const jchar* chars = s->GetCharArray()->GetData() + s->GetOffset();
       memcpy(buf, chars + start, length * sizeof(jchar));
     }
@@ -1886,20 +1888,20 @@
 
   static void GetStringUTFRegion(JNIEnv* env, jstring java_string, jsize start, jsize length,
                                  char* buf) {
-    CHECK_NON_NULL_ARGUMENT(GetStringUTFRegion, java_string);
+    CHECK_NON_NULL_ARGUMENT(java_string);
     ScopedObjectAccess soa(env);
     mirror::String* s = soa.Decode<mirror::String*>(java_string);
     if (start < 0 || length < 0 || start + length > s->GetLength()) {
       ThrowSIOOBE(soa, start, length, s->GetLength());
     } else {
-      CHECK_NON_NULL_MEMCPY_ARGUMENT(GetStringUTFRegion, length, buf);
+      CHECK_NON_NULL_MEMCPY_ARGUMENT(length, buf);
       const jchar* chars = s->GetCharArray()->GetData() + s->GetOffset();
       ConvertUtf16ToModifiedUtf8(buf, chars + start, length);
     }
   }
 
   static const jchar* GetStringChars(JNIEnv* env, jstring java_string, jboolean* is_copy) {
-    CHECK_NON_NULL_ARGUMENT(GetStringChars, java_string);
+    CHECK_NON_NULL_ARGUMENT(java_string);
     ScopedObjectAccess soa(env);
     mirror::String* s = soa.Decode<mirror::String*>(java_string);
     mirror::CharArray* chars = s->GetCharArray();
@@ -1918,7 +1920,7 @@
   }
 
   static void ReleaseStringChars(JNIEnv* env, jstring java_string, const jchar* chars) {
-    CHECK_NON_NULL_ARGUMENT(ReleaseStringChars, java_string);
+    CHECK_NON_NULL_ARGUMENT(java_string);
     delete[] chars;
     ScopedObjectAccess soa(env);
     UnpinPrimitiveArray(soa, soa.Decode<mirror::String*>(java_string)->GetCharArray());
@@ -1955,7 +1957,7 @@
   }
 
   static jsize GetArrayLength(JNIEnv* env, jarray java_array) {
-    CHECK_NON_NULL_ARGUMENT(GetArrayLength, java_array);
+    CHECK_NON_NULL_ARGUMENT(java_array);
     ScopedObjectAccess soa(env);
     mirror::Object* obj = soa.Decode<mirror::Object*>(java_array);
     if (UNLIKELY(!obj->IsArrayInstance())) {
@@ -1966,7 +1968,7 @@
   }
 
   static jobject GetObjectArrayElement(JNIEnv* env, jobjectArray java_array, jsize index) {
-    CHECK_NON_NULL_ARGUMENT(GetObjectArrayElement, java_array);
+    CHECK_NON_NULL_ARGUMENT(java_array);
     ScopedObjectAccess soa(env);
     mirror::ObjectArray<mirror::Object>* array =
         soa.Decode<mirror::ObjectArray<mirror::Object>*>(java_array);
@@ -1975,7 +1977,7 @@
 
   static void SetObjectArrayElement(JNIEnv* env, jobjectArray java_array, jsize index,
                                     jobject java_value) {
-    CHECK_NON_NULL_ARGUMENT(SetObjectArrayElement, java_array);
+    CHECK_NON_NULL_ARGUMENT(java_array);
     ScopedObjectAccess soa(env);
     mirror::ObjectArray<mirror::Object>* array =
         soa.Decode<mirror::ObjectArray<mirror::Object>*>(java_array);
@@ -2070,7 +2072,7 @@
   }
 
   static void* GetPrimitiveArrayCritical(JNIEnv* env, jarray java_array, jboolean* is_copy) {
-    CHECK_NON_NULL_ARGUMENT(GetPrimitiveArrayCritical, java_array);
+    CHECK_NON_NULL_ARGUMENT(java_array);
     ScopedObjectAccess soa(env);
     mirror::Array* array = soa.Decode<mirror::Array*>(java_array);
     gc::Heap* heap = Runtime::Current()->GetHeap();
@@ -2087,54 +2089,54 @@
   }
 
   static void ReleasePrimitiveArrayCritical(JNIEnv* env, jarray array, void* elements, jint mode) {
-    CHECK_NON_NULL_ARGUMENT(ReleasePrimitiveArrayCritical, array);
+    CHECK_NON_NULL_ARGUMENT(array);
     ReleasePrimitiveArray(env, array, elements, mode);
   }
 
   static jboolean* GetBooleanArrayElements(JNIEnv* env, jbooleanArray array, jboolean* is_copy) {
-    CHECK_NON_NULL_ARGUMENT(GetBooleanArrayElements, array);
+    CHECK_NON_NULL_ARGUMENT(array);
     ScopedObjectAccess soa(env);
     return GetPrimitiveArray<jbooleanArray, jboolean*, mirror::BooleanArray>(soa, array, is_copy);
   }
 
   static jbyte* GetByteArrayElements(JNIEnv* env, jbyteArray array, jboolean* is_copy) {
-    CHECK_NON_NULL_ARGUMENT(GetByteArrayElements, array);
+    CHECK_NON_NULL_ARGUMENT(array);
     ScopedObjectAccess soa(env);
     return GetPrimitiveArray<jbyteArray, jbyte*, mirror::ByteArray>(soa, array, is_copy);
   }
 
   static jchar* GetCharArrayElements(JNIEnv* env, jcharArray array, jboolean* is_copy) {
-    CHECK_NON_NULL_ARGUMENT(GetCharArrayElements, array);
+    CHECK_NON_NULL_ARGUMENT(array);
     ScopedObjectAccess soa(env);
     return GetPrimitiveArray<jcharArray, jchar*, mirror::CharArray>(soa, array, is_copy);
   }
 
   static jdouble* GetDoubleArrayElements(JNIEnv* env, jdoubleArray array, jboolean* is_copy) {
-    CHECK_NON_NULL_ARGUMENT(GetDoubleArrayElements, array);
+    CHECK_NON_NULL_ARGUMENT(array);
     ScopedObjectAccess soa(env);
     return GetPrimitiveArray<jdoubleArray, jdouble*, mirror::DoubleArray>(soa, array, is_copy);
   }
 
   static jfloat* GetFloatArrayElements(JNIEnv* env, jfloatArray array, jboolean* is_copy) {
-    CHECK_NON_NULL_ARGUMENT(GetFloatArrayElements, array);
+    CHECK_NON_NULL_ARGUMENT(array);
     ScopedObjectAccess soa(env);
     return GetPrimitiveArray<jfloatArray, jfloat*, mirror::FloatArray>(soa, array, is_copy);
   }
 
   static jint* GetIntArrayElements(JNIEnv* env, jintArray array, jboolean* is_copy) {
-    CHECK_NON_NULL_ARGUMENT(GetIntArrayElements, array);
+    CHECK_NON_NULL_ARGUMENT(array);
     ScopedObjectAccess soa(env);
     return GetPrimitiveArray<jintArray, jint*, mirror::IntArray>(soa, array, is_copy);
   }
 
   static jlong* GetLongArrayElements(JNIEnv* env, jlongArray array, jboolean* is_copy) {
-    CHECK_NON_NULL_ARGUMENT(GetLongArrayElements, array);
+    CHECK_NON_NULL_ARGUMENT(array);
     ScopedObjectAccess soa(env);
     return GetPrimitiveArray<jlongArray, jlong*, mirror::LongArray>(soa, array, is_copy);
   }
 
   static jshort* GetShortArrayElements(JNIEnv* env, jshortArray array, jboolean* is_copy) {
-    CHECK_NON_NULL_ARGUMENT(GetShortArrayElements, array);
+    CHECK_NON_NULL_ARGUMENT(array);
     ScopedObjectAccess soa(env);
     return GetPrimitiveArray<jshortArray, jshort*, mirror::ShortArray>(soa, array, is_copy);
   }
@@ -2290,7 +2292,7 @@
       JniAbortF("RegisterNatives", "negative method count: %d", method_count);
       return JNI_ERR;  // Not reached.
     }
-    CHECK_NON_NULL_ARGUMENT(RegisterNatives, java_class);
+    CHECK_NON_NULL_ARGUMENT_FN_NAME("RegisterNatives", java_class);
     ScopedObjectAccess soa(env);
     mirror::Class* c = soa.Decode<mirror::Class*>(java_class);
     if (UNLIKELY(method_count == 0)) {
@@ -2298,7 +2300,7 @@
           << PrettyDescriptor(c);
       return JNI_OK;
     }
-    CHECK_NON_NULL_ARGUMENT(RegisterNatives, methods);
+    CHECK_NON_NULL_ARGUMENT_FN_NAME("RegisterNatives", methods);
     for (jint i = 0; i < method_count; ++i) {
       const char* name = methods[i].name;
       const char* sig = methods[i].signature;
@@ -2335,7 +2337,7 @@
   }
 
   static jint UnregisterNatives(JNIEnv* env, jclass java_class) {
-    CHECK_NON_NULL_ARGUMENT(UnregisterNatives, java_class);
+    CHECK_NON_NULL_ARGUMENT(java_class);
     ScopedObjectAccess soa(env);
     mirror::Class* c = soa.Decode<mirror::Class*>(java_class);
 
@@ -2358,7 +2360,7 @@
   }
 
   static jint MonitorEnter(JNIEnv* env, jobject java_object) NO_THREAD_SAFETY_ANALYSIS {
-    CHECK_NON_NULL_ARGUMENT(MonitorEnter, java_object);
+    CHECK_NON_NULL_ARGUMENT(java_object);
     ScopedObjectAccess soa(env);
     mirror::Object* o = soa.Decode<mirror::Object*>(java_object);
     o = o->MonitorEnter(soa.Self());
@@ -2370,7 +2372,7 @@
   }
 
   static jint MonitorExit(JNIEnv* env, jobject java_object) NO_THREAD_SAFETY_ANALYSIS {
-    CHECK_NON_NULL_ARGUMENT(MonitorExit, java_object);
+    CHECK_NON_NULL_ARGUMENT(java_object);
     ScopedObjectAccess soa(env);
     mirror::Object* o = soa.Decode<mirror::Object*>(java_object);
     o->MonitorExit(soa.Self());
@@ -2382,7 +2384,7 @@
   }
 
   static jint GetJavaVM(JNIEnv* env, JavaVM** vm) {
-    CHECK_NON_NULL_ARGUMENT(GetJavaVM, vm);
+    CHECK_NON_NULL_ARGUMENT(vm);
     Runtime* runtime = Runtime::Current();
     if (runtime != nullptr) {
       *vm = runtime->GetJavaVM();
@@ -2422,7 +2424,7 @@
   }
 
   static jobjectRefType GetObjectRefType(JNIEnv* env, jobject java_object) {
-    CHECK_NON_NULL_ARGUMENT(GetObjectRefType, java_object);
+    CHECK_NON_NULL_ARGUMENT(java_object);
 
     // Do we definitely know what kind of reference this is?
     IndirectRef ref = reinterpret_cast<IndirectRef>(java_object);
@@ -2543,12 +2545,12 @@
   static void GetPrimitiveArrayRegion(ScopedObjectAccess& soa, JavaArrayT java_array,
                                       jsize start, jsize length, JavaT* buf)
       SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
-    CHECK_NON_NULL_ARGUMENT(GetPrimitiveArrayRegion, java_array);
+    CHECK_NON_NULL_ARGUMENT(java_array);
     ArrayT* array = soa.Decode<ArrayT*>(java_array);
     if (start < 0 || length < 0 || start + length > array->GetLength()) {
       ThrowAIOOBE(soa, array, start, length, "src");
     } else {
-      CHECK_NON_NULL_MEMCPY_ARGUMENT(GetStringRegion, length, buf);
+      CHECK_NON_NULL_MEMCPY_ARGUMENT(length, buf);
       JavaT* data = array->GetData();
       memcpy(buf, data + start, length * sizeof(JavaT));
     }
@@ -2558,12 +2560,12 @@
   static void SetPrimitiveArrayRegion(ScopedObjectAccess& soa, JavaArrayT java_array,
                                       jsize start, jsize length, const JavaT* buf)
       SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
-    CHECK_NON_NULL_ARGUMENT(SetPrimitiveArrayRegion, java_array);
+    CHECK_NON_NULL_ARGUMENT(java_array);
     ArrayT* array = soa.Decode<ArrayT*>(java_array);
     if (start < 0 || length < 0 || start + length > array->GetLength()) {
       ThrowAIOOBE(soa, array, start, length, "dst");
     } else {
-      CHECK_NON_NULL_MEMCPY_ARGUMENT(GetStringRegion, length, buf);
+      CHECK_NON_NULL_MEMCPY_ARGUMENT(length, buf);
       JavaT* data = array->GetData();
       memcpy(data + start, buf, length * sizeof(JavaT));
     }
diff --git a/runtime/mirror/array-inl.h b/runtime/mirror/array-inl.h
index 3d2fd7b..7f974d0 100644
--- a/runtime/mirror/array-inl.h
+++ b/runtime/mirror/array-inl.h
@@ -27,10 +27,11 @@
 namespace art {
 namespace mirror {
 
-template<VerifyObjectFlags kVerifyFlags>
+template<VerifyObjectFlags kVerifyFlags, bool kDoReadBarrier>
 inline size_t Array::SizeOf() {
   // This is safe from overflow because the array was already allocated, so we know it's sane.
-  size_t component_size = GetClass<kVerifyFlags>()->GetComponentSize();
+  size_t component_size =
+      GetClass<kVerifyFlags, kDoReadBarrier>()->template GetComponentSize<kDoReadBarrier>();
   // Don't need to check this since we already check this in GetClass.
   int32_t component_count =
       GetLength<static_cast<VerifyObjectFlags>(kVerifyFlags & ~kVerifyThis)>();
diff --git a/runtime/mirror/array.h b/runtime/mirror/array.h
index 772d303..6bfd5c8 100644
--- a/runtime/mirror/array.h
+++ b/runtime/mirror/array.h
@@ -41,7 +41,7 @@
                                  const SirtRef<IntArray>& dimensions)
       SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
 
-  template<VerifyObjectFlags kVerifyFlags = kDefaultVerifyFlags>
+  template<VerifyObjectFlags kVerifyFlags = kDefaultVerifyFlags, bool kDoReadBarrier = true>
   size_t SizeOf() SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
   template<VerifyObjectFlags kVerifyFlags = kDefaultVerifyFlags>
   int32_t GetLength() SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
diff --git a/runtime/mirror/art_field.cc b/runtime/mirror/art_field.cc
index f91cab1..7b0b94c 100644
--- a/runtime/mirror/art_field.cc
+++ b/runtime/mirror/art_field.cc
@@ -19,6 +19,7 @@
 #include "art_field-inl.h"
 #include "gc/accounting/card_table-inl.h"
 #include "object-inl.h"
+#include "object_array-inl.h"
 #include "object_utils.h"
 #include "runtime.h"
 #include "scoped_thread_state_change.h"
@@ -69,5 +70,25 @@
   }
 }
 
+// TODO: we could speed up the search if fields are ordered by offsets.
+ArtField* ArtField::FindInstanceFieldWithOffset(mirror::Class* klass, uint32_t field_offset) {
+  DCHECK(klass != nullptr);
+  ObjectArray<ArtField>* instance_fields = klass->GetIFields();
+  if (instance_fields != nullptr) {
+    for (int32_t i = 0, e = instance_fields->GetLength(); i < e; ++i) {
+      mirror::ArtField* field = instance_fields->GetWithoutChecks(i);
+      if (field->GetOffset().Uint32Value() == field_offset) {
+        return field;
+      }
+    }
+  }
+  // We did not find field in the class: look into superclass.
+  if (klass->GetSuperClass() != NULL) {
+    return FindInstanceFieldWithOffset(klass->GetSuperClass(), field_offset);
+  } else {
+    return nullptr;
+  }
+}
+
 }  // namespace mirror
 }  // namespace art
diff --git a/runtime/mirror/art_field.h b/runtime/mirror/art_field.h
index 0daa838..ba70cc6 100644
--- a/runtime/mirror/art_field.h
+++ b/runtime/mirror/art_field.h
@@ -132,6 +132,10 @@
     return (GetAccessFlags() & kAccVolatile) != 0;
   }
 
+  // Returns an instance field with this offset in the given class or nullptr if not found.
+  static ArtField* FindInstanceFieldWithOffset(mirror::Class* klass, uint32_t field_offset)
+      SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
+
  private:
   // Field order required by test "ValidateFieldOrderOfJavaCppUnionClasses".
   // The class we are a part of
diff --git a/runtime/mirror/art_method-inl.h b/runtime/mirror/art_method-inl.h
index 5d62b88..6e1f062 100644
--- a/runtime/mirror/art_method-inl.h
+++ b/runtime/mirror/art_method-inl.h
@@ -78,13 +78,11 @@
 
 inline uint32_t ArtMethod::GetCodeSize() {
   DCHECK(!IsRuntimeMethod() && !IsProxyMethod()) << PrettyMethod(this);
-  uintptr_t code = reinterpret_cast<uintptr_t>(GetEntryPointFromQuickCompiledCode());
-  if (code == 0) {
-    return 0;
+  const void* code = EntryPointToCodePointer(GetEntryPointFromQuickCompiledCode());
+  if (code == nullptr) {
+    return 0u;
   }
-  // TODO: make this Thumb2 specific
-  code &= ~0x1;
-  return reinterpret_cast<OatMethodHeader*>(code)[-1].code_size_;
+  return reinterpret_cast<const OatMethodHeader*>(code)[-1].code_size_;
 }
 
 inline bool ArtMethod::CheckIncompatibleClassChange(InvokeType type) {
@@ -124,7 +122,8 @@
     return;
   }
   ClassLinker* class_linker = Runtime::Current()->GetClassLinker();
-  if (code == GetQuickResolutionTrampoline(class_linker)) {
+  if (code == GetQuickResolutionTrampoline(class_linker) ||
+      code == GetQuickToInterpreterBridgeTrampoline(class_linker)) {
     return;
   }
   DCHECK(IsWithinQuickCode(pc))
@@ -154,26 +153,6 @@
   SetEntryPointFromPortableCompiledCode(reinterpret_cast<void*>(code_offset));
 }
 
-inline uint32_t ArtMethod::GetOatMappingTableOffset() {
-  DCHECK(!Runtime::Current()->IsStarted());
-  return PointerToLowMemUInt32(GetMappingTable());
-}
-
-inline void ArtMethod::SetOatMappingTableOffset(uint32_t mapping_table_offset) {
-  DCHECK(!Runtime::Current()->IsStarted());
-  SetMappingTable(reinterpret_cast<const uint8_t*>(mapping_table_offset));
-}
-
-inline uint32_t ArtMethod::GetOatVmapTableOffset() {
-  DCHECK(!Runtime::Current()->IsStarted());
-  return PointerToLowMemUInt32(GetVmapTable());
-}
-
-inline void ArtMethod::SetOatVmapTableOffset(uint32_t vmap_table_offset) {
-  DCHECK(!Runtime::Current()->IsStarted());
-  SetVmapTable(reinterpret_cast<uint8_t*>(vmap_table_offset));
-}
-
 inline void ArtMethod::SetOatNativeGcMapOffset(uint32_t gc_map_offset) {
   DCHECK(!Runtime::Current()->IsStarted());
   SetNativeGcMap(reinterpret_cast<uint8_t*>(gc_map_offset));
diff --git a/runtime/mirror/art_method.cc b/runtime/mirror/art_method.cc
index f3303a8..90bcbab 100644
--- a/runtime/mirror/art_method.cc
+++ b/runtime/mirror/art_method.cc
@@ -315,13 +315,13 @@
       } else {
         (*art_portable_invoke_stub)(this, args, args_size, self, result, shorty[0]);
       }
-      if (UNLIKELY(reinterpret_cast<intptr_t>(self->GetException(NULL)) == -1)) {
-        // Unusual case where we were running LLVM generated code and an
+      if (UNLIKELY(self->GetException(nullptr) == Thread::GetDeoptimizationException())) {
+        // Unusual case where we were running generated code and an
         // exception was thrown to force the activations to be removed from the
         // stack. Continue execution in the interpreter.
         self->ClearException();
         ShadowFrame* shadow_frame = self->GetAndClearDeoptimizationShadowFrame(result);
-        self->SetTopOfStack(NULL, 0);
+        self->SetTopOfStack(nullptr, 0);
         self->SetTopOfShadowStack(shadow_frame);
         interpreter::EnterInterpreterFromDeoptimize(self, shadow_frame, result);
       }
@@ -368,5 +368,43 @@
   RegisterNative(self, GetJniDlsymLookupStub(), false);
 }
 
+const void* ArtMethod::GetOatCodePointer() {
+  if (IsPortableCompiled() || IsNative() || IsAbstract() || IsRuntimeMethod() || IsProxyMethod()) {
+    return nullptr;
+  }
+  Runtime* runtime = Runtime::Current();
+  const void* entry_point = runtime->GetInstrumentation()->GetQuickCodeFor(this);
+  // On failure, instead of nullptr we get the quick-to-interpreter-bridge (but not the trampoline).
+  DCHECK(entry_point != GetQuickToInterpreterBridgeTrampoline(runtime->GetClassLinker()));
+  if (entry_point == GetQuickToInterpreterBridge()) {
+    return nullptr;
+  }
+  return EntryPointToCodePointer(entry_point);
+}
+
+const uint8_t* ArtMethod::GetMappingTable() {
+  const void* code = GetOatCodePointer();
+  if (code == nullptr) {
+    return nullptr;
+  }
+  uint32_t offset = reinterpret_cast<const OatMethodHeader*>(code)[-1].mapping_table_offset_;
+  if (UNLIKELY(offset == 0u)) {
+    return nullptr;
+  }
+  return reinterpret_cast<const uint8_t*>(code) - offset;
+}
+
+const uint8_t* ArtMethod::GetVmapTable() {
+  const void* code = GetOatCodePointer();
+  if (code == nullptr) {
+    return nullptr;
+  }
+  uint32_t offset = reinterpret_cast<const OatMethodHeader*>(code)[-1].vmap_table_offset_;
+  if (UNLIKELY(offset == 0u)) {
+    return nullptr;
+  }
+  return reinterpret_cast<const uint8_t*>(code) - offset;
+}
+
 }  // namespace mirror
 }  // namespace art
diff --git a/runtime/mirror/art_method.h b/runtime/mirror/art_method.h
index d684266..b3b9ca7 100644
--- a/runtime/mirror/art_method.h
+++ b/runtime/mirror/art_method.h
@@ -21,6 +21,7 @@
 #include "dex_file.h"
 #include "invoke_type.h"
 #include "modifiers.h"
+#include "oat.h"
 #include "object.h"
 #include "object_callbacks.h"
 
@@ -261,7 +262,6 @@
         EntryPointFromQuickCompiledCodeOffset(), entry_point_from_quick_compiled_code, false);
   }
 
-
   uint32_t GetCodeSize() SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
 
   bool IsWithinQuickCode(uintptr_t pc) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
@@ -286,37 +286,20 @@
   void SetQuickOatCodeOffset(uint32_t code_offset);
   void SetPortableOatCodeOffset(uint32_t code_offset);
 
+  static const void* EntryPointToCodePointer(const void* entry_point) ALWAYS_INLINE {
+    uintptr_t code = reinterpret_cast<uintptr_t>(entry_point);
+    code &= ~0x1;  // TODO: Make this Thumb2 specific.
+    return reinterpret_cast<const void*>(code);
+  }
+
+  // Actual pointer to compiled oat code or nullptr.
+  const void* GetOatCodePointer() SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
+
   // Callers should wrap the uint8_t* in a MappingTable instance for convenient access.
-  const uint8_t* GetMappingTable() {
-    return GetFieldPtr<const uint8_t*>(OFFSET_OF_OBJECT_MEMBER(ArtMethod, quick_mapping_table_),
-        false);
-  }
-
-  template<VerifyObjectFlags kVerifyFlags = kDefaultVerifyFlags>
-  void SetMappingTable(const uint8_t* mapping_table) {
-    SetFieldPtr<false, true, kVerifyFlags>(
-        OFFSET_OF_OBJECT_MEMBER(ArtMethod, quick_mapping_table_), mapping_table, false);
-  }
-
-  uint32_t GetOatMappingTableOffset();
-
-  void SetOatMappingTableOffset(uint32_t mapping_table_offset);
+  const uint8_t* GetMappingTable() SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
 
   // Callers should wrap the uint8_t* in a VmapTable instance for convenient access.
-  const uint8_t* GetVmapTable() {
-    return GetFieldPtr<const uint8_t*>(OFFSET_OF_OBJECT_MEMBER(ArtMethod, quick_vmap_table_),
-        false);
-  }
-
-  template<VerifyObjectFlags kVerifyFlags = kDefaultVerifyFlags>
-  void SetVmapTable(const uint8_t* vmap_table) {
-    SetFieldPtr<false, true, kVerifyFlags>(
-        OFFSET_OF_OBJECT_MEMBER(ArtMethod, quick_vmap_table_), vmap_table, false);
-  }
-
-  uint32_t GetOatVmapTableOffset();
-
-  void SetOatVmapTableOffset(uint32_t vmap_table_offset);
+  const uint8_t* GetVmapTable() SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
 
   const uint8_t* GetNativeGcMap() {
     return GetFieldPtr<uint8_t*>(OFFSET_OF_OBJECT_MEMBER(ArtMethod, gc_map_), false);
@@ -426,7 +409,9 @@
 
   static void SetClass(Class* java_lang_reflect_ArtMethod);
 
+  template <bool kDoReadBarrier = true>
   static Class* GetJavaLangReflectArtMethod() {
+    // This does not need a RB because it is a root.
     return java_lang_reflect_ArtMethod_;
   }
 
@@ -469,20 +454,6 @@
   // offsets for the quick compiler and dex PCs for the portable.
   uint64_t gc_map_;
 
-  // --- Quick compiler meta-data. ---
-  // TODO: merge and place in native heap, such as done with the code size.
-
-  // Pointer to a data structure created by the quick compiler to map between dex PCs and native
-  // PCs, and vice-versa.
-  uint64_t quick_mapping_table_;
-
-  // When a register is promoted into a register, the spill mask holds which registers hold dex
-  // registers. The first promoted register's corresponding dex register is vmap_table_[1], the Nth
-  // is vmap_table_[N]. vmap_table_[0] holds the length of the table.
-  uint64_t quick_vmap_table_;
-
-  // --- End of quick compiler meta-data. ---
-
   // Access flags; low 16 bits are defined by spec.
   uint32_t access_flags_;
 
diff --git a/runtime/mirror/class-inl.h b/runtime/mirror/class-inl.h
index 025e62a..3c02aa0 100644
--- a/runtime/mirror/class-inl.h
+++ b/runtime/mirror/class-inl.h
@@ -478,6 +478,19 @@
   VisitStaticFieldsReferences<kVisitClass>(this, visitor);
 }
 
+template<bool kDoReadBarrier>
+bool Class::IsArtFieldClass() {
+  Class* java_lang_Class = GetClass<kVerifyNone, kDoReadBarrier>();
+  Class* java_lang_reflect_ArtField =
+      java_lang_Class->GetInstanceField(0)->GetClass<kVerifyNone, kDoReadBarrier>();
+  return this == java_lang_reflect_ArtField;
+}
+
+template<bool kDoReadBarrier>
+bool Class::IsArtMethodClass() {
+  return this == ArtMethod::GetJavaLangReflectArtMethod<kDoReadBarrier>();
+}
+
 }  // namespace mirror
 }  // namespace art
 
diff --git a/runtime/mirror/class.cc b/runtime/mirror/class.cc
index 6dbb29d..ad86e1f 100644
--- a/runtime/mirror/class.cc
+++ b/runtime/mirror/class.cc
@@ -328,16 +328,6 @@
   return WellKnownClasses::ToClass(WellKnownClasses::java_lang_Throwable)->IsAssignableFrom(this);
 }
 
-bool Class::IsArtFieldClass() {
-  Class* java_lang_Class = GetClass();
-  Class* java_lang_reflect_ArtField = java_lang_Class->GetInstanceField(0)->GetClass();
-  return this == java_lang_reflect_ArtField;
-}
-
-bool Class::IsArtMethodClass() {
-  return this == ArtMethod::GetJavaLangReflectArtMethod();
-}
-
 void Class::SetClassLoader(ClassLoader* new_class_loader) {
   if (Runtime::Current()->IsActiveTransaction()) {
     SetFieldObject<true>(OFFSET_OF_OBJECT_MEMBER(Class, class_loader_), new_class_loader, false);
diff --git a/runtime/mirror/class.h b/runtime/mirror/class.h
index d955b97..226dee0 100644
--- a/runtime/mirror/class.h
+++ b/runtime/mirror/class.h
@@ -364,9 +364,9 @@
     return depth;
   }
 
-  template<VerifyObjectFlags kVerifyFlags = kDefaultVerifyFlags>
+  template<VerifyObjectFlags kVerifyFlags = kDefaultVerifyFlags, bool kDoReadBarrier = true>
   bool IsArrayClass() SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
-    return GetComponentType<kVerifyFlags>() != NULL;
+    return GetComponentType<kVerifyFlags, kDoReadBarrier>() != NULL;
   }
 
   bool IsClassClass() SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
@@ -375,17 +375,19 @@
 
   bool IsThrowableClass() SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
 
+  template<bool kDoReadBarrier = true>
   bool IsArtFieldClass() SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
 
+  template<bool kDoReadBarrier = true>
   bool IsArtMethodClass();
 
   static MemberOffset ComponentTypeOffset() {
     return OFFSET_OF_OBJECT_MEMBER(Class, component_type_);
   }
 
-  template<VerifyObjectFlags kVerifyFlags = kDefaultVerifyFlags>
+  template<VerifyObjectFlags kVerifyFlags = kDefaultVerifyFlags, bool kDoReadBarrier = true>
   Class* GetComponentType() SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
-    return GetFieldObject<Class, kVerifyFlags>(ComponentTypeOffset(), false);
+    return GetFieldObject<Class, kVerifyFlags, kDoReadBarrier>(ComponentTypeOffset(), false);
   }
 
   void SetComponentType(Class* new_component_type) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
@@ -395,8 +397,10 @@
     SetFieldObject<false, false>(ComponentTypeOffset(), new_component_type, false);
   }
 
+  template<bool kDoReadBarrier = true>
   size_t GetComponentSize() SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
-    return Primitive::ComponentSize(GetComponentType()->GetPrimitiveType());
+    return Primitive::ComponentSize(
+        GetComponentType<kDefaultVerifyFlags, kDoReadBarrier>()->GetPrimitiveType());
   }
 
   bool IsObjectClass() SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
@@ -427,7 +431,7 @@
     return IsClassClass() || IsArrayClass();
   }
 
-  template<VerifyObjectFlags kVerifyFlags = kDefaultVerifyFlags>
+  template<VerifyObjectFlags kVerifyFlags = kDefaultVerifyFlags, bool kDoReadBarrier = true>
   uint32_t SizeOf() SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
     return GetField32<kVerifyFlags>(OFFSET_OF_OBJECT_MEMBER(Class, class_size_), false);
   }
diff --git a/runtime/mirror/object-inl.h b/runtime/mirror/object-inl.h
index b195dea..04517ec 100644
--- a/runtime/mirror/object-inl.h
+++ b/runtime/mirror/object-inl.h
@@ -34,9 +34,10 @@
 namespace art {
 namespace mirror {
 
-template<VerifyObjectFlags kVerifyFlags>
+template<VerifyObjectFlags kVerifyFlags, bool kDoReadBarrier>
 inline Class* Object::GetClass() {
-  return GetFieldObject<Class, kVerifyFlags>(OFFSET_OF_OBJECT_MEMBER(Object, klass_), false);
+  return GetFieldObject<Class, kVerifyFlags, kDoReadBarrier>(
+      OFFSET_OF_OBJECT_MEMBER(Object, klass_), false);
 }
 
 template<VerifyObjectFlags kVerifyFlags>
@@ -105,18 +106,45 @@
 #endif
 }
 
-inline void Object::SetReadBarrierPointer(Object* rb_pointer) {
+inline void Object::SetReadBarrierPointer(Object* rb_ptr) {
 #ifdef USE_BAKER_OR_BROOKS_READ_BARRIER
   DCHECK(kUseBakerOrBrooksReadBarrier);
   // We don't mark the card as this occurs as part of object allocation. Not all objects have
   // backing cards, such as large objects.
   SetFieldObjectWithoutWriteBarrier<false, false, kVerifyNone>(
-      OFFSET_OF_OBJECT_MEMBER(Object, x_rb_ptr_), rb_pointer, false);
+      OFFSET_OF_OBJECT_MEMBER(Object, x_rb_ptr_), rb_ptr, false);
 #else
   LOG(FATAL) << "Unreachable";
 #endif
 }
 
+inline bool Object::AtomicSetReadBarrierPointer(Object* expected_rb_ptr, Object* rb_ptr) {
+#ifdef USE_BAKER_OR_BROOKS_READ_BARRIER
+  DCHECK(kUseBakerOrBrooksReadBarrier);
+  MemberOffset offset = OFFSET_OF_OBJECT_MEMBER(Object, x_rb_ptr_);
+  byte* raw_addr = reinterpret_cast<byte*>(this) + offset.SizeValue();
+  HeapReference<Object>* ref = reinterpret_cast<HeapReference<Object>*>(raw_addr);
+  HeapReference<Object> expected_ref(HeapReference<Object>::FromMirrorPtr(expected_rb_ptr));
+  HeapReference<Object> new_ref(HeapReference<Object>::FromMirrorPtr(rb_ptr));
+  uint32_t expected_val = expected_ref.reference_;
+  uint32_t new_val;
+  do {
+    uint32_t old_val = ref->reference_;
+    if (old_val != expected_val) {
+      // Lost the race.
+      return false;
+    }
+    new_val = new_ref.reference_;
+  } while (!__sync_bool_compare_and_swap(
+      reinterpret_cast<uint32_t*>(raw_addr), expected_val, new_val));
+  DCHECK_EQ(new_val, ref->reference_);
+  return true;
+#else
+  LOG(FATAL) << "Unreachable";
+  return false;
+#endif
+}
+
 inline void Object::AssertReadBarrierPointer() const {
   if (kUseBakerReadBarrier) {
     Object* obj = const_cast<Object*>(this);
@@ -147,16 +175,17 @@
   return klass->IsAssignableFrom(GetClass<kVerifyFlags>());
 }
 
-template<VerifyObjectFlags kVerifyFlags>
+template<VerifyObjectFlags kVerifyFlags, bool kDoReadBarrier>
 inline bool Object::IsClass() {
-  Class* java_lang_Class = GetClass<kVerifyFlags>()->GetClass();
-  return GetClass<static_cast<VerifyObjectFlags>(kVerifyFlags & ~kVerifyThis)>() ==
+  Class* java_lang_Class =
+      GetClass<kVerifyFlags, kDoReadBarrier>()->template GetClass<kVerifyFlags, kDoReadBarrier>();
+  return GetClass<static_cast<VerifyObjectFlags>(kVerifyFlags & ~kVerifyThis), kDoReadBarrier>() ==
       java_lang_Class;
 }
 
-template<VerifyObjectFlags kVerifyFlags>
+template<VerifyObjectFlags kVerifyFlags, bool kDoReadBarrier>
 inline Class* Object::AsClass() {
-  DCHECK(IsClass<kVerifyFlags>());
+  DCHECK((IsClass<kVerifyFlags, kDoReadBarrier>()));
   return down_cast<Class*>(this);
 }
 
@@ -173,14 +202,15 @@
   return down_cast<ObjectArray<T>*>(this);
 }
 
-template<VerifyObjectFlags kVerifyFlags>
+template<VerifyObjectFlags kVerifyFlags, bool kDoReadBarrier>
 inline bool Object::IsArrayInstance() {
-  return GetClass<kVerifyFlags>()->IsArrayClass();
+  return GetClass<kVerifyFlags, kDoReadBarrier>()->
+      template IsArrayClass<kVerifyFlags, kDoReadBarrier>();
 }
 
-template<VerifyObjectFlags kVerifyFlags>
+template<VerifyObjectFlags kVerifyFlags, bool kDoReadBarrier>
 inline bool Object::IsArtField() {
-  return GetClass<kVerifyFlags>()->IsArtFieldClass();
+  return GetClass<kVerifyFlags, kDoReadBarrier>()->template IsArtFieldClass<kDoReadBarrier>();
 }
 
 template<VerifyObjectFlags kVerifyFlags>
@@ -189,9 +219,9 @@
   return down_cast<ArtField*>(this);
 }
 
-template<VerifyObjectFlags kVerifyFlags>
+template<VerifyObjectFlags kVerifyFlags, bool kDoReadBarrier>
 inline bool Object::IsArtMethod() {
-  return GetClass<kVerifyFlags>()->IsArtMethodClass();
+  return GetClass<kVerifyFlags, kDoReadBarrier>()->template IsArtMethodClass<kDoReadBarrier>();
 }
 
 template<VerifyObjectFlags kVerifyFlags>
@@ -211,9 +241,9 @@
   return down_cast<Reference*>(this);
 }
 
-template<VerifyObjectFlags kVerifyFlags>
+template<VerifyObjectFlags kVerifyFlags, bool kDoReadBarrier>
 inline Array* Object::AsArray() {
-  DCHECK(IsArrayInstance<kVerifyFlags>());
+  DCHECK((IsArrayInstance<kVerifyFlags, kDoReadBarrier>()));
   return down_cast<Array*>(this);
 }
 
@@ -339,20 +369,21 @@
   return GetClass<kVerifyFlags>()->IsPhantomReferenceClass();
 }
 
-template<VerifyObjectFlags kVerifyFlags>
+template<VerifyObjectFlags kVerifyFlags, bool kDoReadBarrier>
 inline size_t Object::SizeOf() {
   size_t result;
   constexpr auto kNewFlags = static_cast<VerifyObjectFlags>(kVerifyFlags & ~kVerifyThis);
-  if (IsArrayInstance<kVerifyFlags>()) {
-    result = AsArray<kNewFlags>()->template SizeOf<kNewFlags>();
-  } else if (IsClass<kNewFlags>()) {
-    result = AsClass<kNewFlags>()->template SizeOf<kNewFlags>();
+  if (IsArrayInstance<kVerifyFlags, kDoReadBarrier>()) {
+    result = AsArray<kNewFlags, kDoReadBarrier>()->template SizeOf<kNewFlags, kDoReadBarrier>();
+  } else if (IsClass<kNewFlags, kDoReadBarrier>()) {
+    result = AsClass<kNewFlags, kDoReadBarrier>()->template SizeOf<kNewFlags, kDoReadBarrier>();
   } else {
-    result = GetClass<kNewFlags>()->GetObjectSize();
+    result = GetClass<kNewFlags, kDoReadBarrier>()->GetObjectSize();
   }
-  DCHECK_GE(result, sizeof(Object)) << " class=" << PrettyTypeOf(GetClass<kNewFlags>());
-  DCHECK(!IsArtField<kNewFlags>()  || result == sizeof(ArtField));
-  DCHECK(!IsArtMethod<kNewFlags>() || result == sizeof(ArtMethod));
+  DCHECK_GE(result, sizeof(Object))
+      << " class=" << PrettyTypeOf(GetClass<kNewFlags, kDoReadBarrier>());
+  DCHECK(!(IsArtField<kNewFlags, kDoReadBarrier>())  || result == sizeof(ArtField));
+  DCHECK(!(IsArtMethod<kNewFlags, kDoReadBarrier>()) || result == sizeof(ArtMethod));
   return result;
 }
 
diff --git a/runtime/mirror/object.h b/runtime/mirror/object.h
index fd31dfb..370b3b8 100644
--- a/runtime/mirror/object.h
+++ b/runtime/mirror/object.h
@@ -72,14 +72,16 @@
     return OFFSET_OF_OBJECT_MEMBER(Object, klass_);
   }
 
-  template<VerifyObjectFlags kVerifyFlags = kDefaultVerifyFlags>
+  template<VerifyObjectFlags kVerifyFlags = kDefaultVerifyFlags, bool kDoReadBarrier = true>
   Class* GetClass() SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
 
   template<VerifyObjectFlags kVerifyFlags = kDefaultVerifyFlags>
   void SetClass(Class* new_klass) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
 
   Object* GetReadBarrierPointer() SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
-  void SetReadBarrierPointer(Object* rb_pointer) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
+  void SetReadBarrierPointer(Object* rb_ptr) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
+  bool AtomicSetReadBarrierPointer(Object* expected_rb_ptr, Object* rb_ptr)
+      SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
   void AssertReadBarrierPointer() const SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
 
   // The verifier treats all interfaces as java.lang.Object and relies on runtime checks in
@@ -89,7 +91,7 @@
   template<VerifyObjectFlags kVerifyFlags = kDefaultVerifyFlags>
   bool InstanceOf(Class* klass) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
 
-  template<VerifyObjectFlags kVerifyFlags = kDefaultVerifyFlags>
+  template<VerifyObjectFlags kVerifyFlags = kDefaultVerifyFlags, bool kDoReadBarrier = true>
   size_t SizeOf() SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
 
   Object* Clone(Thread* self) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
@@ -116,9 +118,9 @@
   void Wait(Thread* self) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
   void Wait(Thread* self, int64_t timeout, int32_t nanos) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
 
-  template<VerifyObjectFlags kVerifyFlags = kDefaultVerifyFlags>
+  template<VerifyObjectFlags kVerifyFlags = kDefaultVerifyFlags, bool kDoReadBarrier = true>
   bool IsClass() SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
-  template<VerifyObjectFlags kVerifyFlags = kDefaultVerifyFlags>
+  template<VerifyObjectFlags kVerifyFlags = kDefaultVerifyFlags, bool kDoReadBarrier = true>
   Class* AsClass() SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
 
   template<VerifyObjectFlags kVerifyFlags = kDefaultVerifyFlags>
@@ -126,9 +128,9 @@
   template<class T, VerifyObjectFlags kVerifyFlags = kDefaultVerifyFlags>
   ObjectArray<T>* AsObjectArray() SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
 
-  template<VerifyObjectFlags kVerifyFlags = kDefaultVerifyFlags>
+  template<VerifyObjectFlags kVerifyFlags = kDefaultVerifyFlags, bool kDoReadBarrier = true>
   bool IsArrayInstance() SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
-  template<VerifyObjectFlags kVerifyFlags = kDefaultVerifyFlags>
+  template<VerifyObjectFlags kVerifyFlags = kDefaultVerifyFlags, bool kDoReadBarrier = true>
   Array* AsArray() SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
 
   template<VerifyObjectFlags kVerifyFlags = kDefaultVerifyFlags>
@@ -161,12 +163,12 @@
   template<VerifyObjectFlags kVerifyFlags = kDefaultVerifyFlags>
   Throwable* AsThrowable() SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
 
-  template<VerifyObjectFlags kVerifyFlags = kDefaultVerifyFlags>
+  template<VerifyObjectFlags kVerifyFlags = kDefaultVerifyFlags, bool kDoReadBarrier = true>
   bool IsArtMethod() SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
   template<VerifyObjectFlags kVerifyFlags = kDefaultVerifyFlags>
   ArtMethod* AsArtMethod() SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
 
-  template<VerifyObjectFlags kVerifyFlags = kDefaultVerifyFlags>
+  template<VerifyObjectFlags kVerifyFlags = kDefaultVerifyFlags, bool kDoReadBarrier = true>
   bool IsArtField() SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
   template<VerifyObjectFlags kVerifyFlags = kDefaultVerifyFlags>
   ArtField* AsArtField() SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
diff --git a/runtime/mirror/object_array.h b/runtime/mirror/object_array.h
index 5ff0490..26b1fd1 100644
--- a/runtime/mirror/object_array.h
+++ b/runtime/mirror/object_array.h
@@ -83,9 +83,9 @@
   template<const bool kVisitClass, typename Visitor>
   void VisitReferences(const Visitor& visitor) NO_THREAD_SAFETY_ANALYSIS;
 
- private:
   static MemberOffset OffsetOfElement(int32_t i);
 
+ private:
   DISALLOW_IMPLICIT_CONSTRUCTORS(ObjectArray);
 };
 
diff --git a/runtime/native/dalvik_system_DexFile.cc b/runtime/native/dalvik_system_DexFile.cc
index 6af16f4..2231070 100644
--- a/runtime/native/dalvik_system_DexFile.cc
+++ b/runtime/native/dalvik_system_DexFile.cc
@@ -262,7 +262,7 @@
 static jboolean DexFile_isDexOptNeededInternal(JNIEnv* env, jclass, jstring javaFilename,
     jstring javaPkgname, jboolean defer) {
   const bool kVerboseLogging = false;  // Spammy logging.
-  const bool kDebugLogging = true;  // Logging useful for debugging.
+  const bool kReasonLogging = true;  // Logging of reason for returning JNI_TRUE.
 
   ScopedUtfChars filename(env, javaFilename);
   if ((filename.c_str() == nullptr) || !OS::FileExists(filename.c_str())) {
@@ -312,7 +312,7 @@
     int e2 = stat(prev_profile_file.c_str(), &prevstat);
     if (e1 < 0) {
       // No profile file, need to run dex2oat
-      if (kDebugLogging) {
+      if (kReasonLogging) {
         LOG(INFO) << "DexFile_isDexOptNeeded profile file " << profile_file << " doesn't exist";
       }
       return JNI_TRUE;
@@ -330,12 +330,12 @@
       bool newOk = ProfileHelper::LoadTopKSamples(newTopK, profile_file, topKThreshold);
       bool oldOk = ProfileHelper::LoadTopKSamples(oldTopK, prev_profile_file, topKThreshold);
       if (!newOk || !oldOk) {
-        if (kDebugLogging) {
+        if (kVerboseLogging) {
           LOG(INFO) << "DexFile_isDexOptNeeded Ignoring invalid profiles: "
                     << (newOk ?  "" : profile_file) << " " << (oldOk ? "" : prev_profile_file);
         }
       } else if (newTopK.empty()) {
-        if (kDebugLogging && kVerboseLogging) {
+        if (kVerboseLogging) {
           LOG(INFO) << "DexFile_isDexOptNeeded empty profile: " << profile_file;
         }
         // If the new topK is empty we shouldn't optimize so we leave the changePercent at 0.0.
@@ -345,7 +345,7 @@
           std::inserter(diff, diff.end()));
         // TODO: consider using the usedPercentage instead of the plain diff count.
         changePercent = 100.0 * static_cast<double>(diff.size()) / static_cast<double>(newTopK.size());
-        if (kDebugLogging && kVerboseLogging) {
+        if (kVerboseLogging) {
           std::set<std::string>::iterator end = diff.end();
           for (std::set<std::string>::iterator it = diff.begin(); it != end; it++) {
             LOG(INFO) << "DexFile_isDexOptNeeded new in topK: " << *it;
@@ -354,7 +354,7 @@
       }
 
       if (changePercent > changeThreshold) {
-        if (kDebugLogging) {
+        if (kReasonLogging) {
           LOG(INFO) << "DexFile_isDexOptNeeded size of new profile file " << profile_file <<
           " is significantly different from old profile file " << prev_profile_file << " (top "
           << topKThreshold << "% samples changed in proportion of " << changePercent << "%)";
@@ -366,13 +366,12 @@
       }
     } else {
       // Previous profile does not exist.  Make a copy of the current one.
-      if (kDebugLogging) {
+      if (kVerboseLogging) {
         LOG(INFO) << "DexFile_isDexOptNeeded previous profile doesn't exist: " << prev_profile_file;
       }
       if (!defer) {
         CopyProfileFile(profile_file.c_str(), prev_profile_file.c_str());
       }
-      return JNI_TRUE;
     }
   }
 
@@ -389,7 +388,7 @@
     error_msg.clear();
   } else {
     const art::OatFile::OatDexFile* oat_dex_file = oat_file->GetOatDexFile(filename.c_str(), NULL,
-                                                                           kDebugLogging);
+                                                                           kReasonLogging);
     if (oat_dex_file != nullptr) {
       uint32_t location_checksum;
       // If its not possible to read the classes.dex assume up-to-date as we won't be able to
@@ -423,7 +422,7 @@
   std::string cache_location(GetDalvikCacheFilenameOrDie(filename.c_str()));
   oat_file.reset(OatFile::Open(cache_location, filename.c_str(), NULL, false, &error_msg));
   if (oat_file.get() == nullptr) {
-    if (kDebugLogging) {
+    if (kReasonLogging) {
       LOG(INFO) << "DexFile_isDexOptNeeded cache file " << cache_location
           << " does not exist for " << filename.c_str() << ": " << error_msg;
     }
@@ -436,7 +435,7 @@
       const ImageHeader& image_header = space->AsImageSpace()->GetImageHeader();
       if (oat_file->GetOatHeader().GetImageFileLocationOatChecksum() !=
           image_header.GetOatChecksum()) {
-        if (kDebugLogging) {
+        if (kReasonLogging) {
           ScopedObjectAccess soa(env);
           LOG(INFO) << "DexFile_isDexOptNeeded cache file " << cache_location
               << " has out-of-date oat checksum compared to "
@@ -446,7 +445,7 @@
       }
       if (oat_file->GetOatHeader().GetImageFileLocationOatDataBegin()
           != reinterpret_cast<uintptr_t>(image_header.GetOatDataBegin())) {
-        if (kDebugLogging) {
+        if (kReasonLogging) {
           ScopedObjectAccess soa(env);
           LOG(INFO) << "DexFile_isDexOptNeeded cache file " << cache_location
               << " has out-of-date oat begin compared to "
@@ -459,7 +458,7 @@
 
   uint32_t location_checksum;
   if (!DexFile::GetChecksum(filename.c_str(), &location_checksum, &error_msg)) {
-    if (kDebugLogging) {
+    if (kReasonLogging) {
       LOG(ERROR) << "DexFile_isDexOptNeeded failed to compute checksum of " << filename.c_str()
             << " (error " << error_msg << ")";
     }
@@ -468,7 +467,7 @@
 
   if (!ClassLinker::VerifyOatFileChecksums(oat_file.get(), filename.c_str(), location_checksum,
                                            &error_msg)) {
-    if (kDebugLogging) {
+    if (kReasonLogging) {
       LOG(INFO) << "DexFile_isDexOptNeeded cache file " << cache_location
           << " has out-of-date checksum compared to " << filename.c_str()
           << " (error " << error_msg << ")";
diff --git a/runtime/oat.cc b/runtime/oat.cc
index d01dc72b..c1a48e9 100644
--- a/runtime/oat.cc
+++ b/runtime/oat.cc
@@ -22,7 +22,7 @@
 namespace art {
 
 const uint8_t OatHeader::kOatMagic[] = { 'o', 'a', 't', '\n' };
-const uint8_t OatHeader::kOatVersion[] = { '0', '2', '1', '\0' };
+const uint8_t OatHeader::kOatVersion[] = { '0', '2', '2', '\0' };
 
 OatHeader::OatHeader() {
   memset(this, 0, sizeof(*this));
@@ -348,8 +348,6 @@
     frame_size_in_bytes_(0),
     core_spill_mask_(0),
     fp_spill_mask_(0),
-    mapping_table_offset_(0),
-    vmap_table_offset_(0),
     gc_map_offset_(0)
 {}
 
@@ -357,27 +355,28 @@
                                    uint32_t frame_size_in_bytes,
                                    uint32_t core_spill_mask,
                                    uint32_t fp_spill_mask,
-                                   uint32_t mapping_table_offset,
-                                   uint32_t vmap_table_offset,
                                    uint32_t gc_map_offset
                                    )
   : code_offset_(code_offset),
     frame_size_in_bytes_(frame_size_in_bytes),
     core_spill_mask_(core_spill_mask),
     fp_spill_mask_(fp_spill_mask),
-    mapping_table_offset_(mapping_table_offset),
-    vmap_table_offset_(vmap_table_offset),
     gc_map_offset_(gc_map_offset)
 {}
 
 OatMethodOffsets::~OatMethodOffsets() {}
 
 OatMethodHeader::OatMethodHeader()
-  : code_size_(0)
+  : mapping_table_offset_(0),
+    vmap_table_offset_(0),
+    code_size_(0)
 {}
 
-OatMethodHeader::OatMethodHeader(uint32_t code_size)
-  : code_size_(code_size)
+OatMethodHeader::OatMethodHeader(uint32_t vmap_table_offset, uint32_t mapping_table_offset,
+                                 uint32_t code_size)
+  : mapping_table_offset_(mapping_table_offset),
+    vmap_table_offset_(vmap_table_offset),
+    code_size_(code_size)
 {}
 
 OatMethodHeader::~OatMethodHeader() {}
diff --git a/runtime/oat.h b/runtime/oat.h
index 035aba1..e9dfae9 100644
--- a/runtime/oat.h
+++ b/runtime/oat.h
@@ -119,9 +119,9 @@
   DISALLOW_COPY_AND_ASSIGN(OatHeader);
 };
 
-// OatMethodOffsets are currently 7x32-bits=224-bits long, so if we can
+// OatMethodOffsets are currently 5x32-bits=160-bits long, so if we can
 // save even one OatMethodOffsets struct, the more complicated encoding
-// using a bitmap pays for itself since few classes will have 224
+// using a bitmap pays for itself since few classes will have 160
 // methods.
 enum OatClassType {
   kOatClassAllCompiled = 0,   // OatClass is followed by an OatMethodOffsets for each method.
@@ -140,8 +140,6 @@
                    uint32_t frame_size_in_bytes,
                    uint32_t core_spill_mask,
                    uint32_t fp_spill_mask,
-                   uint32_t mapping_table_offset,
-                   uint32_t vmap_table_offset,
                    uint32_t gc_map_offset);
 
   ~OatMethodOffsets();
@@ -150,8 +148,6 @@
   uint32_t frame_size_in_bytes_;
   uint32_t core_spill_mask_;
   uint32_t fp_spill_mask_;
-  uint32_t mapping_table_offset_;
-  uint32_t vmap_table_offset_;
   uint32_t gc_map_offset_;
 };
 
@@ -160,10 +156,15 @@
  public:
   OatMethodHeader();
 
-  explicit OatMethodHeader(uint32_t code_size);
+  explicit OatMethodHeader(uint32_t mapping_table_offset, uint32_t vmap_table_offset,
+                           uint32_t code_size);
 
   ~OatMethodHeader();
 
+  // The offset in bytes from the start of the mapping table to the end of the header.
+  uint32_t mapping_table_offset_;
+  // The offset in bytes from the start of the vmap table to the end of the header.
+  uint32_t vmap_table_offset_;
   // The code size in bytes.
   uint32_t code_size_;
 };
diff --git a/runtime/oat_file-inl.h b/runtime/oat_file-inl.h
new file mode 100644
index 0000000..00ae797
--- /dev/null
+++ b/runtime/oat_file-inl.h
@@ -0,0 +1,60 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef ART_RUNTIME_OAT_FILE_INL_H_
+#define ART_RUNTIME_OAT_FILE_INL_H_
+
+#include "oat_file.h"
+
+namespace art {
+
+inline uint32_t OatFile::OatMethod::GetMappingTableOffset() const {
+  const uint8_t* mapping_table = GetMappingTable();
+  return static_cast<uint32_t>(mapping_table != nullptr ? mapping_table - begin_ : 0u);
+}
+
+inline uint32_t OatFile::OatMethod::GetVmapTableOffset() const {
+  const uint8_t* vmap_table = GetVmapTable();
+  return static_cast<uint32_t>(vmap_table != nullptr ? vmap_table - begin_ : 0u);
+}
+
+inline const uint8_t* OatFile::OatMethod::GetMappingTable() const {
+  const void* code = mirror::ArtMethod::EntryPointToCodePointer(GetQuickCode());
+  if (code == nullptr) {
+    return nullptr;
+  }
+  uint32_t offset = reinterpret_cast<const OatMethodHeader*>(code)[-1].mapping_table_offset_;
+  if (UNLIKELY(offset == 0u)) {
+    return nullptr;
+  }
+  return reinterpret_cast<const uint8_t*>(code) - offset;
+}
+
+inline const uint8_t* OatFile::OatMethod::GetVmapTable() const {
+  const void* code = mirror::ArtMethod::EntryPointToCodePointer(GetQuickCode());
+  if (code == nullptr) {
+    return nullptr;
+  }
+  uint32_t offset = reinterpret_cast<const OatMethodHeader*>(code)[-1].vmap_table_offset_;
+  if (UNLIKELY(offset == 0u)) {
+    return nullptr;
+  }
+  return reinterpret_cast<const uint8_t*>(code) - offset;
+}
+
+}  // namespace art
+
+#endif  // ART_RUNTIME_OAT_FILE_INL_H_
diff --git a/runtime/oat_file.cc b/runtime/oat_file.cc
index 0aff8c3..56e1f05 100644
--- a/runtime/oat_file.cc
+++ b/runtime/oat_file.cc
@@ -464,7 +464,7 @@
   // NOTE: We don't keep the number of methods and cannot do a bounds check for method_index.
   if (methods_pointer_ == NULL) {
     CHECK_EQ(kOatClassNoneCompiled, type_);
-    return OatMethod(NULL, 0, 0, 0, 0, 0, 0, 0);
+    return OatMethod(NULL, 0, 0, 0, 0, 0);
   }
   size_t methods_pointer_index;
   if (bitmap_ == NULL) {
@@ -473,7 +473,7 @@
   } else {
     CHECK_EQ(kOatClassSomeCompiled, type_);
     if (!BitVector::IsBitSet(bitmap_, method_index)) {
-      return OatMethod(NULL, 0, 0, 0, 0, 0, 0, 0);
+      return OatMethod(NULL, 0, 0, 0, 0, 0);
     }
     size_t num_set_bits = BitVector::NumSetBits(bitmap_, method_index);
     methods_pointer_index = num_set_bits;
@@ -485,8 +485,6 @@
       oat_method_offsets.frame_size_in_bytes_,
       oat_method_offsets.core_spill_mask_,
       oat_method_offsets.fp_spill_mask_,
-      oat_method_offsets.mapping_table_offset_,
-      oat_method_offsets.vmap_table_offset_,
       oat_method_offsets.gc_map_offset_);
 }
 
@@ -495,32 +493,13 @@
                               const size_t frame_size_in_bytes,
                               const uint32_t core_spill_mask,
                               const uint32_t fp_spill_mask,
-                              const uint32_t mapping_table_offset,
-                              const uint32_t vmap_table_offset,
                               const uint32_t gc_map_offset)
   : begin_(base),
     code_offset_(code_offset),
     frame_size_in_bytes_(frame_size_in_bytes),
     core_spill_mask_(core_spill_mask),
     fp_spill_mask_(fp_spill_mask),
-    mapping_table_offset_(mapping_table_offset),
-    vmap_table_offset_(vmap_table_offset),
     native_gc_map_offset_(gc_map_offset) {
-  if (kIsDebugBuild) {
-    if (mapping_table_offset_ != 0) {  // implies non-native, non-stub code
-      if (vmap_table_offset_ == 0) {
-        CHECK_EQ(0U, static_cast<uint32_t>(__builtin_popcount(core_spill_mask_) +
-                                           __builtin_popcount(fp_spill_mask_)));
-      } else {
-        VmapTable vmap_table(reinterpret_cast<const uint8_t*>(begin_ + vmap_table_offset_));
-
-        CHECK_EQ(vmap_table.Size(), static_cast<uint32_t>(__builtin_popcount(core_spill_mask_) +
-                                                          __builtin_popcount(fp_spill_mask_)));
-      }
-    } else {
-      CHECK_EQ(vmap_table_offset_, 0U);
-    }
-  }
 }
 
 OatFile::OatMethod::~OatMethod() {}
@@ -543,8 +522,6 @@
   method->SetFrameSizeInBytes(frame_size_in_bytes_);
   method->SetCoreSpillMask(core_spill_mask_);
   method->SetFpSpillMask(fp_spill_mask_);
-  method->SetMappingTable(GetMappingTable());
-  method->SetVmapTable(GetVmapTable());
   method->SetNativeGcMap(GetNativeGcMap());  // Used by native methods in work around JNI mode.
 }
 
diff --git a/runtime/oat_file.h b/runtime/oat_file.h
index 10f64cc..5f6cb1e 100644
--- a/runtime/oat_file.h
+++ b/runtime/oat_file.h
@@ -87,12 +87,6 @@
     uint32_t GetFpSpillMask() const {
       return fp_spill_mask_;
     }
-    uint32_t GetMappingTableOffset() const {
-      return mapping_table_offset_;
-    }
-    uint32_t GetVmapTableOffset() const {
-      return vmap_table_offset_;
-    }
     uint32_t GetNativeGcMapOffset() const {
       return native_gc_map_offset_;
     }
@@ -122,16 +116,15 @@
     }
     uint32_t GetQuickCodeSize() const;
 
-    const uint8_t* GetMappingTable() const {
-      return GetOatPointer<const uint8_t*>(mapping_table_offset_);
-    }
-    const uint8_t* GetVmapTable() const {
-      return GetOatPointer<const uint8_t*>(vmap_table_offset_);
-    }
     const uint8_t* GetNativeGcMap() const {
       return GetOatPointer<const uint8_t*>(native_gc_map_offset_);
     }
 
+    uint32_t GetMappingTableOffset() const;
+    uint32_t GetVmapTableOffset() const;
+    const uint8_t* GetMappingTable() const;
+    const uint8_t* GetVmapTable() const;
+
     ~OatMethod();
 
     // Create an OatMethod with offsets relative to the given base address
@@ -140,8 +133,6 @@
               const size_t frame_size_in_bytes,
               const uint32_t core_spill_mask,
               const uint32_t fp_spill_mask,
-              const uint32_t mapping_table_offset,
-              const uint32_t vmap_table_offset,
               const uint32_t gc_map_offset);
 
    private:
@@ -159,8 +150,6 @@
     size_t frame_size_in_bytes_;
     uint32_t core_spill_mask_;
     uint32_t fp_spill_mask_;
-    uint32_t mapping_table_offset_;
-    uint32_t vmap_table_offset_;
     uint32_t native_gc_map_offset_;
 
     friend class OatClass;
diff --git a/runtime/catch_finder.cc b/runtime/quick_exception_handler.cc
similarity index 67%
rename from runtime/catch_finder.cc
rename to runtime/quick_exception_handler.cc
index f0293d7..d5844b6 100644
--- a/runtime/catch_finder.cc
+++ b/runtime/quick_exception_handler.cc
@@ -14,37 +14,37 @@
  * limitations under the License.
  */
 
-#include "catch_finder.h"
+#include "quick_exception_handler.h"
+
 #include "catch_block_stack_visitor.h"
+#include "deoptimize_stack_visitor.h"
+#include "entrypoints/entrypoint_utils.h"
+#include "sirt_ref-inl.h"
 
 namespace art {
 
-CatchFinder::CatchFinder(Thread* self, const ThrowLocation& throw_location,
-            mirror::Throwable* exception, bool is_deoptimization)
-  : self_(self), context_(self->GetLongJumpContext()),
-    exception_(exception), is_deoptimization_(is_deoptimization), throw_location_(throw_location),
+QuickExceptionHandler::QuickExceptionHandler(Thread* self, bool is_deoptimization)
+  : self_(self), context_(self->GetLongJumpContext()), is_deoptimization_(is_deoptimization),
     method_tracing_active_(is_deoptimization ||
                            Runtime::Current()->GetInstrumentation()->AreExitStubsInstalled()),
-                           handler_quick_frame_(nullptr), handler_quick_frame_pc_(0),
-                           handler_dex_pc_(0), clear_exception_(false), top_shadow_frame_(nullptr),
-                           handler_frame_id_(kInvalidFrameId) {
-  // Exception not in root sets, can't allow GC.
-  last_no_assert_suspension_cause_ = self->StartAssertNoThreadSuspension("Finding catch block");
+    handler_quick_frame_(nullptr), handler_quick_frame_pc_(0), handler_dex_pc_(0),
+    clear_exception_(false), top_shadow_frame_(nullptr), handler_frame_id_(kInvalidFrameId) {
 }
 
-void CatchFinder::FindCatch() {
+void QuickExceptionHandler::FindCatch(const ThrowLocation& throw_location,
+                                      mirror::Throwable* exception) {
+  DCHECK(!is_deoptimization_);
+  SirtRef<mirror::Throwable> exception_ref(self_, exception);
+
   // Walk the stack to find catch handler or prepare for deoptimization.
-  CatchBlockStackVisitor visitor(self_, context_, exception_, is_deoptimization_, this);
+  CatchBlockStackVisitor visitor(self_, context_, exception_ref, this);
   visitor.WalkStack(true);
 
   mirror::ArtMethod* catch_method = *handler_quick_frame_;
-  if (catch_method == nullptr) {
-    if (kDebugExceptionDelivery) {
+  if (kDebugExceptionDelivery) {
+    if (catch_method == nullptr) {
       LOG(INFO) << "Handler is upcall";
-    }
-  } else {
-    CHECK(!is_deoptimization_);
-    if (kDebugExceptionDelivery) {
+    } else {
       const DexFile& dex_file = *catch_method->GetDeclaringClass()->GetDexCache()->GetDexFile();
       int line_number = dex_file.GetLineNumFromPC(catch_method, handler_dex_pc_);
       LOG(INFO) << "Handler: " << PrettyMethod(catch_method) << " (line: " << line_number << ")";
@@ -55,17 +55,23 @@
     DCHECK(!self_->IsExceptionPending());
   } else {
     // Put exception back in root set with clear throw location.
-    self_->SetException(ThrowLocation(), exception_);
+    self_->SetException(ThrowLocation(), exception_ref.get());
   }
-  self_->EndAssertNoThreadSuspension(last_no_assert_suspension_cause_);
-  // Do instrumentation events after allowing thread suspension again.
-  if (!is_deoptimization_) {
-    // The debugger may suspend this thread and walk its stack. Let's do this before popping
-    // instrumentation frames.
-    instrumentation::Instrumentation* instrumentation = Runtime::Current()->GetInstrumentation();
-    instrumentation->ExceptionCaughtEvent(self_, throw_location_, catch_method, handler_dex_pc_,
-                                          exception_);
-  }
+  // The debugger may suspend this thread and walk its stack. Let's do this before popping
+  // instrumentation frames.
+  instrumentation::Instrumentation* instrumentation = Runtime::Current()->GetInstrumentation();
+  instrumentation->ExceptionCaughtEvent(self_, throw_location, catch_method, handler_dex_pc_,
+                                        exception_ref.get());
+}
+
+void QuickExceptionHandler::DeoptimizeStack() {
+  DCHECK(is_deoptimization_);
+
+  DeoptimizeStackVisitor visitor(self_, context_, this);
+  visitor.WalkStack(true);
+
+  // Restore deoptimization exception
+  self_->SetException(ThrowLocation(), Thread::GetDeoptimizationException());
 }
 
 // Unwinds all instrumentation stack frame prior to catch handler or upcall.
@@ -105,7 +111,7 @@
   DISALLOW_COPY_AND_ASSIGN(InstrumentationStackVisitor);
 };
 
-void CatchFinder::UpdateInstrumentationStack() {
+void QuickExceptionHandler::UpdateInstrumentationStack() {
   if (method_tracing_active_) {
     InstrumentationStackVisitor visitor(self_, is_deoptimization_, handler_frame_id_);
     visitor.WalkStack(true);
@@ -118,7 +124,7 @@
   }
 }
 
-void CatchFinder::DoLongJump() {
+void QuickExceptionHandler::DoLongJump() {
   if (is_deoptimization_) {
     // TODO: proper return value.
     self_->SetDeoptimizationShadowFrame(top_shadow_frame_);
diff --git a/runtime/catch_finder.h b/runtime/quick_exception_handler.h
similarity index 76%
rename from runtime/catch_finder.h
rename to runtime/quick_exception_handler.h
index ebbafe2..d06ce7c 100644
--- a/runtime/catch_finder.h
+++ b/runtime/quick_exception_handler.h
@@ -14,29 +14,39 @@
  * limitations under the License.
  */
 
-#ifndef ART_RUNTIME_CATCH_FINDER_H_
-#define ART_RUNTIME_CATCH_FINDER_H_
+#ifndef ART_RUNTIME_QUICK_EXCEPTION_HANDLER_H_
+#define ART_RUNTIME_QUICK_EXCEPTION_HANDLER_H_
 
-#include "mirror/art_method-inl.h"
-#include "thread.h"
+#include "base/logging.h"
+#include "base/mutex.h"
 
 namespace art {
 
+namespace mirror {
+class ArtMethod;
+class Throwable;
+}  // namespace mirror
+class Context;
+class Thread;
+class ThrowLocation;
+class ShadowFrame;
+
 static constexpr bool kDebugExceptionDelivery = false;
 static constexpr size_t kInvalidFrameId = 0xffffffff;
 
 // Manages exception delivery for Quick backend. Not used by Portable backend.
-class CatchFinder {
+class QuickExceptionHandler {
  public:
-  CatchFinder(Thread* self, const ThrowLocation& throw_location, mirror::Throwable* exception,
-              bool is_deoptimization)
+  QuickExceptionHandler(Thread* self, bool is_deoptimization)
       SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
 
-  ~CatchFinder() {
+  ~QuickExceptionHandler() {
     LOG(FATAL) << "UNREACHABLE";  // Expected to take long jump.
   }
 
-  void FindCatch() SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
+  void FindCatch(const ThrowLocation& throw_location, mirror::Throwable* exception)
+      SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
+  void DeoptimizeStack() SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
   void UpdateInstrumentationStack() SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
   void DoLongJump() SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
 
@@ -67,14 +77,9 @@
  private:
   Thread* const self_;
   Context* const context_;
-  mirror::Throwable* const exception_;
   const bool is_deoptimization_;
-  // Location of the throw.
-  const ThrowLocation& throw_location_;
   // Is method tracing active?
   const bool method_tracing_active_;
-  // Support for nesting no thread suspension checks.
-  const char* last_no_assert_suspension_cause_;
   // Quick frame with found handler or last frame if no handler found.
   mirror::ArtMethod** handler_quick_frame_;
   // PC to branch to for the handler.
@@ -88,8 +93,8 @@
   // Frame id of the catch handler or the upcall.
   size_t handler_frame_id_;
 
-  DISALLOW_COPY_AND_ASSIGN(CatchFinder);
+  DISALLOW_COPY_AND_ASSIGN(QuickExceptionHandler);
 };
 
 }  // namespace art
-#endif  // ART_RUNTIME_CATCH_FINDER_H_
+#endif  // ART_RUNTIME_QUICK_EXCEPTION_HANDLER_H_
diff --git a/runtime/scoped_thread_state_change.h b/runtime/scoped_thread_state_change.h
index 404c616..7698d6a 100644
--- a/runtime/scoped_thread_state_change.h
+++ b/runtime/scoped_thread_state_change.h
@@ -38,23 +38,18 @@
       Runtime* runtime = Runtime::Current();
       CHECK(runtime == NULL || !runtime->IsStarted() || runtime->IsShuttingDown(self_));
     } else {
-      bool runnable_transition;
       DCHECK_EQ(self, Thread::Current());
       // Read state without locks, ok as state is effectively thread local and we're not interested
       // in the suspend count (this will be handled in the runnable transitions).
       old_thread_state_ = self->GetState();
-      runnable_transition = old_thread_state_ == kRunnable || new_thread_state == kRunnable;
-      if (!runnable_transition) {
-        // A suspended transition to another effectively suspended transition, ok to use Unsafe.
-        self_->SetState(new_thread_state);
-      }
-
-      if (runnable_transition && old_thread_state_ != new_thread_state) {
+      if (old_thread_state_ != new_thread_state) {
         if (new_thread_state == kRunnable) {
           self_->TransitionFromSuspendedToRunnable();
-        } else {
-          DCHECK_EQ(old_thread_state_, kRunnable);
+        } else if (old_thread_state_ == kRunnable) {
           self_->TransitionFromRunnableToSuspended(new_thread_state);
+        } else {
+          // A suspended transition to another effectively suspended transition, ok to use Unsafe.
+          self_->SetState(new_thread_state);
         }
       }
     }
diff --git a/runtime/thread.cc b/runtime/thread.cc
index 998579d..771680b 100644
--- a/runtime/thread.cc
+++ b/runtime/thread.cc
@@ -32,7 +32,6 @@
 
 #include "arch/context.h"
 #include "base/mutex.h"
-#include "catch_finder.h"
 #include "class_linker.h"
 #include "class_linker-inl.h"
 #include "cutils/atomic.h"
@@ -54,6 +53,7 @@
 #include "mirror/stack_trace_element.h"
 #include "monitor.h"
 #include "object_utils.h"
+#include "quick_exception_handler.h"
 #include "reflection.h"
 #include "runtime.h"
 #include "scoped_thread_state_change.h"
@@ -1018,7 +1018,8 @@
   tls32_.state_and_flags.as_struct.flags = 0;
   tls32_.state_and_flags.as_struct.state = kNative;
   memset(&tlsPtr_.held_mutexes[0], 0, sizeof(tlsPtr_.held_mutexes));
-  memset(tlsPtr_.rosalloc_runs, 0, sizeof(tlsPtr_.rosalloc_runs));
+  std::fill(tlsPtr_.rosalloc_runs, tlsPtr_.rosalloc_runs + kRosAllocNumOfSizeBrackets,
+            gc::allocator::RosAlloc::GetDedicatedFullRun());
   for (uint32_t i = 0; i < kMaxCheckpoints; ++i) {
     tlsPtr_.checkpoint_functions[i] = nullptr;
   }
@@ -1841,7 +1842,7 @@
   // Don't leave exception visible while we try to find the handler, which may cause class
   // resolution.
   ClearException();
-  bool is_deoptimization = (exception == reinterpret_cast<mirror::Throwable*>(-1));
+  bool is_deoptimization = (exception == GetDeoptimizationException());
   if (kDebugExceptionDelivery) {
     if (!is_deoptimization) {
       mirror::String* msg = exception->GetDetailMessage();
@@ -1852,10 +1853,14 @@
       DumpStack(LOG(INFO) << "Deoptimizing: ");
     }
   }
-  CatchFinder catch_finder(this, throw_location, exception, is_deoptimization);
-  catch_finder.FindCatch();
-  catch_finder.UpdateInstrumentationStack();
-  catch_finder.DoLongJump();
+  QuickExceptionHandler exception_handler(this, is_deoptimization);
+  if (is_deoptimization) {
+    exception_handler.DeoptimizeStack();
+  } else {
+    exception_handler.FindCatch(throw_location, exception);
+  }
+  exception_handler.UpdateInstrumentationStack();
+  exception_handler.DoLongJump();
   LOG(FATAL) << "UNREACHABLE";
 }
 
@@ -2060,7 +2065,7 @@
   if (tlsPtr_.opeer != nullptr) {
     visitor(&tlsPtr_.opeer, arg, thread_id, kRootThreadObject);
   }
-  if (tlsPtr_.exception != nullptr) {
+  if (tlsPtr_.exception != nullptr && tlsPtr_.exception != GetDeoptimizationException()) {
     visitor(reinterpret_cast<mirror::Object**>(&tlsPtr_.exception), arg, thread_id, kRootNativeStack);
   }
   tlsPtr_.throw_location.VisitRoots(visitor, arg);
diff --git a/runtime/thread.h b/runtime/thread.h
index d25bbe9..e5e4cae 100644
--- a/runtime/thread.h
+++ b/runtime/thread.h
@@ -686,6 +686,11 @@
     return tlsPtr_.single_step_control;
   }
 
+  // Returns the fake exception used to activate deoptimization.
+  static mirror::Throwable* GetDeoptimizationException() {
+    return reinterpret_cast<mirror::Throwable*>(-1);
+  }
+
   void SetDeoptimizationShadowFrame(ShadowFrame* sf);
   void SetDeoptimizationReturnValue(const JValue& ret_val);
 
diff --git a/runtime/verifier/method_verifier.cc b/runtime/verifier/method_verifier.cc
index 535c76d..91170f0 100644
--- a/runtime/verifier/method_verifier.cc
+++ b/runtime/verifier/method_verifier.cc
@@ -1176,8 +1176,11 @@
         // it's effectively considered initialized the instant we reach here (in the sense that we
         // can return without doing anything or call virtual methods).
         {
-          const RegType& reg_type = reg_types_.FromDescriptor(class_loader_->get(), descriptor,
-                                                              false);
+          const RegType& reg_type = ResolveClassAndCheckAccess(iterator.GetTypeIdx());
+          if (!reg_type.IsNonZeroReferenceTypes()) {
+            DCHECK(HasFailures());
+            return false;
+          }
           reg_line->SetRegisterType(arg_start + cur_arg, reg_type);
         }
         break;
@@ -2865,11 +2868,7 @@
             common_super = &reg_types_.JavaLangThrowable(false);
           } else {
             const RegType& exception = ResolveClassAndCheckAccess(iterator.GetHandlerTypeIndex());
-            if (common_super == NULL) {
-              // Unconditionally assign for the first handler. We don't assert this is a Throwable
-              // as that is caught at runtime
-              common_super = &exception;
-            } else if (!reg_types_.JavaLangThrowable(false).IsAssignableFrom(exception)) {
+            if (!reg_types_.JavaLangThrowable(false).IsAssignableFrom(exception)) {
               if (exception.IsUnresolvedTypes()) {
                 // We don't know enough about the type. Fail here and let runtime handle it.
                 Fail(VERIFY_ERROR_NO_CLASS) << "unresolved exception class " << exception;
@@ -2878,6 +2877,8 @@
                 Fail(VERIFY_ERROR_BAD_CLASS_SOFT) << "unexpected non-exception class " << exception;
                 return reg_types_.Conflict();
               }
+            } else if (common_super == nullptr) {
+              common_super = &exception;
             } else if (common_super->Equals(exception)) {
               // odd case, but nothing to do
             } else {
@@ -3596,29 +3597,6 @@
   }
 }
 
-// Look for an instance field with this offset.
-// TODO: we may speed up the search if offsets are sorted by doing a quick search.
-static mirror::ArtField* FindInstanceFieldWithOffset(mirror::Class* klass, uint32_t field_offset)
-    SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
-  mirror::ObjectArray<mirror::ArtField>* instance_fields = klass->GetIFields();
-  if (instance_fields != NULL) {
-    for (int32_t i = 0, e = instance_fields->GetLength(); i < e; ++i) {
-      mirror::ArtField* field = instance_fields->Get(i);
-      if (field->GetOffset().Uint32Value() == field_offset) {
-        return field;
-      }
-    }
-  }
-  // We did not find field in class: look into superclass.
-  if (klass->GetSuperClass() != NULL) {
-    return FindInstanceFieldWithOffset(klass->GetSuperClass(), field_offset);
-  } else {
-    VLOG(verifier) << "Failed to find instance field at offset '" << field_offset
-        << "' from '" << PrettyDescriptor(klass) << "'";
-    return nullptr;
-  }
-}
-
 mirror::ArtField* MethodVerifier::GetQuickFieldAccess(const Instruction* inst,
                                                       RegisterLine* reg_line) {
   DCHECK(inst->Opcode() == Instruction::IGET_QUICK ||
@@ -3633,7 +3611,13 @@
     return nullptr;
   }
   uint32_t field_offset = static_cast<uint32_t>(inst->VRegC_22c());
-  return FindInstanceFieldWithOffset(object_type.GetClass(), field_offset);
+  mirror::ArtField* f = mirror::ArtField::FindInstanceFieldWithOffset(object_type.GetClass(),
+                                                                      field_offset);
+  if (f == nullptr) {
+    VLOG(verifier) << "Failed to find instance field at offset '" << field_offset
+                   << "' from '" << PrettyDescriptor(object_type.GetClass()) << "'";
+  }
+  return f;
 }
 
 void MethodVerifier::VerifyIGetQuick(const Instruction* inst, const RegType& insn_type,
diff --git a/test/046-reflect/expected.txt b/test/046-reflect/expected.txt
index 55b0dbe..ecb3599 100644
--- a/test/046-reflect/expected.txt
+++ b/test/046-reflect/expected.txt
@@ -92,6 +92,8 @@
 Target constructor (IF)V : ii=7 ff=3.3333
 myMethod (I)I
  arg=17 anInt=7
+got expected exception for Class.newInstance
+got expected exception for Constructor.newInstance
 ReflectTest done!
 public method
 static java.lang.Object java.util.Collections.checkType(java.lang.Object,java.lang.Class) accessible=false
diff --git a/test/046-reflect/src/Main.java b/test/046-reflect/src/Main.java
index d60fcb4..3e6d700 100644
--- a/test/046-reflect/src/Main.java
+++ b/test/046-reflect/src/Main.java
@@ -362,6 +362,27 @@
             targ = cons.newInstance(args);
             targ.myMethod(17);
 
+            try {
+                Thrower thrower = Thrower.class.newInstance();
+                System.out.println("ERROR: Class.newInstance did not throw exception");
+            } catch (UnsupportedOperationException uoe) {
+                System.out.println("got expected exception for Class.newInstance");
+            } catch (Exception e) {
+                System.out.println("ERROR: Class.newInstance got unexpected exception: " +
+                                   e.getClass().getName());
+            }
+
+            try {
+                Constructor<Thrower> constructor = Thrower.class.getDeclaredConstructor();
+                Thrower thrower = constructor.newInstance();
+                System.out.println("ERROR: Constructor.newInstance did not throw exception");
+            } catch (InvocationTargetException ite) {
+                System.out.println("got expected exception for Constructor.newInstance");
+            } catch (Exception e) {
+                System.out.println("ERROR: Constructor.newInstance got unexpected exception: " +
+                                   e.getClass().getName());
+            }
+
         } catch (Exception ex) {
             System.out.println("----- unexpected exception -----");
             ex.printStackTrace();
@@ -669,3 +690,9 @@
   public static void staticMethod() {}
   public void createMethodNoisyInit(MethodNoisyInit ni) {}
 }
+
+class Thrower {
+  public Thrower() throws UnsupportedOperationException {
+    throw new UnsupportedOperationException();
+  }
+}
diff --git a/test/083-compiler-regressions/expected.txt b/test/083-compiler-regressions/expected.txt
index db50300..7576b02 100644
--- a/test/083-compiler-regressions/expected.txt
+++ b/test/083-compiler-regressions/expected.txt
@@ -16,6 +16,7 @@
 largeFrame passes
 largeFrameFloat passes
 mulBy1Test passes
+constantPropagationTest passes
 getterSetterTest passes
 identityTest passes
 wideGetterSetterTest passes
diff --git a/test/083-compiler-regressions/src/Main.java b/test/083-compiler-regressions/src/Main.java
index d32c037..6a12ca9 100644
--- a/test/083-compiler-regressions/src/Main.java
+++ b/test/083-compiler-regressions/src/Main.java
@@ -38,6 +38,7 @@
         largeFrameTest();
         largeFrameTestFloat();
         mulBy1Test();
+        constantPropagationTest();
         getterSetterTest();
         identityTest();
         wideGetterSetterTest();
@@ -766,6 +767,32 @@
         }
     }
 
+    static void constantPropagationTest() {
+        int i = 1;
+        int t = 1;
+        float z = 1F;
+        long h = 1L;
+        int g[] = new int[1];
+        int w = 1;
+        long f = 0;
+
+        for (int a = 1; a < 100; a++) {
+            try {
+                i = (int)(z);
+                h >>= (0 % t);
+            }
+            finally {
+                w = (int)(2 * (f * 6));
+            }
+        }
+
+        if (w == 0 && h == 1 && g[0] == 0) {
+            System.out.println("constantPropagationTest passes");
+        } else {
+            System.out.println("constantPropagationTest fails");
+        }
+    }
+
     static void b2296099Test() throws Exception {
        int x = -1190771042;
        int dist = 360530809;