Merge "Check for errors in ThreadGroupReference JDWP commands"
diff --git a/build/Android.gtest.mk b/build/Android.gtest.mk
index 700bcf0..4ecda91 100644
--- a/build/Android.gtest.mk
+++ b/build/Android.gtest.mk
@@ -79,6 +79,7 @@
   runtime/base/histogram_test.cc \
   runtime/base/mutex_test.cc \
   runtime/base/scoped_flock_test.cc \
+  runtime/base/stringprintf_test.cc \
   runtime/base/timing_logger_test.cc \
   runtime/base/unix_file/fd_file_test.cc \
   runtime/base/unix_file/mapped_file_test.cc \
@@ -151,6 +152,7 @@
   compiler/optimizing/register_allocator_test.cc \
   compiler/optimizing/ssa_test.cc \
   compiler/optimizing/stack_map_test.cc \
+  compiler/optimizing/suspend_check_test.cc \
   compiler/output_stream_test.cc \
   compiler/utils/arena_allocator_test.cc \
   compiler/utils/dedupe_set_test.cc \
diff --git a/compiler/common_compiler_test.cc b/compiler/common_compiler_test.cc
index db9dcd4..fbaed9f 100644
--- a/compiler/common_compiler_test.cc
+++ b/compiler/common_compiler_test.cc
@@ -367,7 +367,7 @@
   MakeExecutable(method);
 }
 
-void CommonCompilerTest::CompileDirectMethod(ConstHandle<mirror::ClassLoader> class_loader,
+void CommonCompilerTest::CompileDirectMethod(Handle<mirror::ClassLoader> class_loader,
                                              const char* class_name, const char* method_name,
                                              const char* signature) {
   std::string class_descriptor(DotToDescriptor(class_name));
@@ -380,7 +380,7 @@
   CompileMethod(method);
 }
 
-void CommonCompilerTest::CompileVirtualMethod(ConstHandle<mirror::ClassLoader> class_loader,
+void CommonCompilerTest::CompileVirtualMethod(Handle<mirror::ClassLoader> class_loader,
                                               const char* class_name, const char* method_name,
                                               const char* signature) {
   std::string class_descriptor(DotToDescriptor(class_name));
diff --git a/compiler/common_compiler_test.h b/compiler/common_compiler_test.h
index 4e74f0a..df06b71 100644
--- a/compiler/common_compiler_test.h
+++ b/compiler/common_compiler_test.h
@@ -63,11 +63,11 @@
 
   void CompileMethod(mirror::ArtMethod* method) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
 
-  void CompileDirectMethod(ConstHandle<mirror::ClassLoader> class_loader, const char* class_name,
+  void CompileDirectMethod(Handle<mirror::ClassLoader> class_loader, const char* class_name,
                            const char* method_name, const char* signature)
       SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
 
-  void CompileVirtualMethod(ConstHandle<mirror::ClassLoader> class_loader, const char* class_name,
+  void CompileVirtualMethod(Handle<mirror::ClassLoader> class_loader, const char* class_name,
                             const char* method_name, const char* signature)
       SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
 
diff --git a/compiler/compiled_method.h b/compiler/compiled_method.h
index 3e34144..cc46b92 100644
--- a/compiler/compiled_method.h
+++ b/compiler/compiled_method.h
@@ -154,7 +154,7 @@
       // get rid of the highest values
       size_t i = size() - 1;
       for (; i > 0 ; i--) {
-        if ((*this)[i].from_ >= highest_pc) {
+        if ((*this)[i].from_ < highest_pc) {
           break;
         }
       }
diff --git a/compiler/dex/mir_optimization.cc b/compiler/dex/mir_optimization.cc
index 7ac878f..fdabc3e 100644
--- a/compiler/dex/mir_optimization.cc
+++ b/compiler/dex/mir_optimization.cc
@@ -1360,11 +1360,20 @@
     if (!method_info.FastPath()) {
       continue;
     }
+
     InvokeType sharp_type = method_info.GetSharpType();
-    if ((sharp_type != kDirect) &&
-        (sharp_type != kStatic || method_info.NeedsClassInitialization())) {
+    if ((sharp_type != kDirect) && (sharp_type != kStatic)) {
       continue;
     }
+
+    if (sharp_type == kStatic) {
+      bool needs_clinit = method_info.NeedsClassInitialization() &&
+          ((mir->optimization_flags & MIR_IGNORE_CLINIT_CHECK) == 0);
+      if (needs_clinit) {
+        continue;
+      }
+    }
+
     DCHECK(cu_->compiler_driver->GetMethodInlinerMap() != nullptr);
     MethodReference target = method_info.GetTargetMethod();
     if (cu_->compiler_driver->GetMethodInlinerMap()->GetMethodInliner(target.dex_file)
diff --git a/compiler/driver/compiler_driver.cc b/compiler/driver/compiler_driver.cc
index bbd1939..d743f90 100644
--- a/compiler/driver/compiler_driver.cc
+++ b/compiler/driver/compiler_driver.cc
@@ -350,10 +350,10 @@
       dump_stats_(dump_stats),
       dump_passes_(dump_passes),
       timings_logger_(timer),
-      compiler_library_(NULL),
-      compiler_context_(NULL),
-      compiler_enable_auto_elf_loading_(NULL),
-      compiler_get_method_code_addr_(NULL),
+      compiler_library_(nullptr),
+      compiler_context_(nullptr),
+      compiler_enable_auto_elf_loading_(nullptr),
+      compiler_get_method_code_addr_(nullptr),
       support_boot_image_fixup_(instruction_set != kMips),
       dedupe_code_("dedupe code"),
       dedupe_src_mapping_table_("dedupe source mapping table"),
@@ -365,7 +365,7 @@
   DCHECK(verification_results_ != nullptr);
   DCHECK(method_inliner_map_ != nullptr);
 
-  CHECK_PTHREAD_CALL(pthread_key_create, (&tls_key_, NULL), "compiler tls key");
+  CHECK_PTHREAD_CALL(pthread_key_create, (&tls_key_, nullptr), "compiler tls key");
 
   dex_to_dex_compiler_ = reinterpret_cast<DexToDexCompilerFn>(ArtCompileDEX);
 
@@ -445,7 +445,7 @@
 CompilerTls* CompilerDriver::GetTls() {
   // Lazily create thread-local storage
   CompilerTls* res = static_cast<CompilerTls*>(pthread_getspecific(tls_key_));
-  if (res == NULL) {
+  if (res == nullptr) {
     res = compiler_->CreateNewCompilerTls();
     CHECK_PTHREAD_CALL(pthread_setspecific, (tls_key_, res), "compiler tls");
   }
@@ -520,20 +520,18 @@
   const char* descriptor = dex_file.GetClassDescriptor(class_def);
   ClassLinker* class_linker = Runtime::Current()->GetClassLinker();
   mirror::Class* klass = class_linker->FindClass(self, descriptor, class_loader);
-  if (klass == NULL) {
+  if (klass == nullptr) {
     CHECK(self->IsExceptionPending());
     self->ClearException();
     return kDontDexToDexCompile;
   }
-  // The verifier can only run on "quick" instructions at runtime (see usage of
-  // FindAccessedFieldAtDexPc and FindInvokedMethodAtDexPc in ThrowNullPointerExceptionFromDexPC
-  // function). Since image classes can be verified again while compiling an application,
-  // we must prevent the DEX-to-DEX compiler from introducing them.
-  // TODO: find a way to enable "quick" instructions for image classes and remove this check.
-  bool compiling_image_classes = class_loader.Get() == nullptr;
-  if (compiling_image_classes) {
-    return kRequired;
-  } else if (klass->IsVerified()) {
+  // DexToDex at the kOptimize level may introduce quickened opcodes, which replace symbolic
+  // references with actual offsets. We cannot re-verify such instructions.
+  //
+  // We store the verification information in the class status in the oat file, which the linker
+  // can validate (checksums) and use to skip load-time verification. It is thus safe to
+  // optimize when a class has been fully verified before.
+  if (klass->IsVerified()) {
     // Class is verified so we can enable DEX-to-DEX compilation for performance.
     return kOptimize;
   } else if (klass->IsCompileTimeVerified()) {
@@ -606,13 +604,14 @@
                                 ThreadPool* thread_pool, TimingLogger* timings) {
   LoadImageClasses(timings);
 
+  Resolve(class_loader, dex_files, thread_pool, timings);
+
   if (!compiler_options_->IsVerificationEnabled()) {
-    VLOG(compiler) << "Verify none mode specified, skipping pre-compilation";
+    LOG(INFO) << "Verify none mode specified, skipping verification.";
+    SetVerified(class_loader, dex_files, thread_pool, timings);
     return;
   }
 
-  Resolve(class_loader, dex_files, thread_pool, timings);
-
   Verify(class_loader, dex_files, thread_pool, timings);
 
   InitializeClasses(class_loader, dex_files, thread_pool, timings);
@@ -628,11 +627,11 @@
   }
 }
 
-static void ResolveExceptionsForMethod(MethodHelper* mh,
+static void ResolveExceptionsForMethod(MutableMethodHelper* mh,
     std::set<std::pair<uint16_t, const DexFile*>>& exceptions_to_resolve)
     SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
   const DexFile::CodeItem* code_item = mh->GetMethod()->GetCodeItem();
-  if (code_item == NULL) {
+  if (code_item == nullptr) {
     return;  // native or abstract method
   }
   if (code_item->tries_size_ == 0) {
@@ -671,7 +670,7 @@
   std::set<std::pair<uint16_t, const DexFile*>>* exceptions_to_resolve =
       reinterpret_cast<std::set<std::pair<uint16_t, const DexFile*>>*>(arg);
   StackHandleScope<1> hs(Thread::Current());
-  MethodHelper mh(hs.NewHandle<mirror::ArtMethod>(nullptr));
+  MutableMethodHelper mh(hs.NewHandle<mirror::ArtMethod>(nullptr));
   for (size_t i = 0; i < c->NumVirtualMethods(); ++i) {
     mh.ChangeMethod(c->GetVirtualMethod(i));
     ResolveExceptionsForMethod(&mh, *exceptions_to_resolve);
@@ -710,7 +709,7 @@
     StackHandleScope<1> hs(self);
     Handle<mirror::Class> klass(
         hs.NewHandle(class_linker->FindSystemClass(self, descriptor.c_str())));
-    if (klass.Get() == NULL) {
+    if (klass.Get() == nullptr) {
       VLOG(compiler) << "Failed to find class " << descriptor;
       image_classes_->erase(it++);
       self->ClearException();
@@ -738,7 +737,7 @@
       Handle<mirror::Class> klass(hs.NewHandle(
           class_linker->ResolveType(*dex_file, exception_type_idx, dex_cache,
                                     NullHandle<mirror::ClassLoader>())));
-      if (klass.Get() == NULL) {
+      if (klass.Get() == nullptr) {
         const DexFile::TypeId& type_id = dex_file->GetTypeId(exception_type_idx);
         const char* descriptor = dex_file->GetTypeDescriptor(type_id);
         LOG(FATAL) << "Failed to resolve class " << descriptor;
@@ -762,7 +761,7 @@
   Thread* self = Thread::Current();
   StackHandleScope<1> hs(self);
   // Make a copy of the handle so that we don't clobber it doing Assign.
-  Handle<mirror::Class> klass(hs.NewHandle(c.Get()));
+  MutableHandle<mirror::Class> klass(hs.NewHandle(c.Get()));
   std::string temp;
   while (!klass->IsObjectClass()) {
     const char* descriptor = klass->GetDescriptor(&temp);
@@ -785,8 +784,8 @@
 }
 
 void CompilerDriver::FindClinitImageClassesCallback(mirror::Object* object, void* arg) {
-  DCHECK(object != NULL);
-  DCHECK(arg != NULL);
+  DCHECK(object != nullptr);
+  DCHECK(arg != nullptr);
   CompilerDriver* compiler_driver = reinterpret_cast<CompilerDriver*>(arg);
   StackHandleScope<1> hs(Thread::Current());
   MaybeAddToImageClasses(hs.NewHandle(object->GetClass()), compiler_driver->image_classes_.get());
@@ -854,29 +853,29 @@
                                                 uint32_t type_idx,
                                                 bool* type_known_final, bool* type_known_abstract,
                                                 bool* equals_referrers_class) {
-  if (type_known_final != NULL) {
+  if (type_known_final != nullptr) {
     *type_known_final = false;
   }
-  if (type_known_abstract != NULL) {
+  if (type_known_abstract != nullptr) {
     *type_known_abstract = false;
   }
-  if (equals_referrers_class != NULL) {
+  if (equals_referrers_class != nullptr) {
     *equals_referrers_class = false;
   }
   ScopedObjectAccess soa(Thread::Current());
   mirror::DexCache* dex_cache = Runtime::Current()->GetClassLinker()->FindDexCache(dex_file);
   // Get type from dex cache assuming it was populated by the verifier
   mirror::Class* resolved_class = dex_cache->GetResolvedType(type_idx);
-  if (resolved_class == NULL) {
+  if (resolved_class == nullptr) {
     stats_->TypeNeedsAccessCheck();
     return false;  // Unknown class needs access checks.
   }
   const DexFile::MethodId& method_id = dex_file.GetMethodId(referrer_idx);
-  if (equals_referrers_class != NULL) {
+  if (equals_referrers_class != nullptr) {
     *equals_referrers_class = (method_id.class_idx_ == type_idx);
   }
   mirror::Class* referrer_class = dex_cache->GetResolvedType(method_id.class_idx_);
-  if (referrer_class == NULL) {
+  if (referrer_class == nullptr) {
     stats_->TypeNeedsAccessCheck();
     return false;  // Incomplete referrer knowledge needs access check.
   }
@@ -885,10 +884,10 @@
   bool result = referrer_class->CanAccess(resolved_class);
   if (result) {
     stats_->TypeDoesntNeedAccessCheck();
-    if (type_known_final != NULL) {
+    if (type_known_final != nullptr) {
       *type_known_final = resolved_class->IsFinal() && !resolved_class->IsArrayClass();
     }
-    if (type_known_abstract != NULL) {
+    if (type_known_abstract != nullptr) {
       *type_known_abstract = resolved_class->IsAbstract() && !resolved_class->IsArrayClass();
     }
   } else {
@@ -904,13 +903,13 @@
   mirror::DexCache* dex_cache = Runtime::Current()->GetClassLinker()->FindDexCache(dex_file);
   // Get type from dex cache assuming it was populated by the verifier.
   mirror::Class* resolved_class = dex_cache->GetResolvedType(type_idx);
-  if (resolved_class == NULL) {
+  if (resolved_class == nullptr) {
     stats_->TypeNeedsAccessCheck();
     return false;  // Unknown class needs access checks.
   }
   const DexFile::MethodId& method_id = dex_file.GetMethodId(referrer_idx);
   mirror::Class* referrer_class = dex_cache->GetResolvedType(method_id.class_idx_);
-  if (referrer_class == NULL) {
+  if (referrer_class == nullptr) {
     stats_->TypeNeedsAccessCheck();
     return false;  // Incomplete referrer knowledge needs access check.
   }
@@ -1310,6 +1309,10 @@
 }
 
 bool CompilerDriver::IsSafeCast(const DexCompilationUnit* mUnit, uint32_t dex_pc) {
+  if (!compiler_options_->IsVerificationEnabled()) {
+    // If we didn't verify, every cast has to be treated as non-safe.
+    return false;
+  }
   DCHECK(mUnit->GetVerifiedMethod() != nullptr);
   bool result = mUnit->GetVerifiedMethod()->IsSafeCast(dex_pc);
   if (result) {
@@ -1410,7 +1413,7 @@
       thread_pool_(thread_pool) {}
 
   ClassLinker* GetClassLinker() const {
-    CHECK(class_linker_ != NULL);
+    CHECK(class_linker_ != nullptr);
     return class_linker_;
   }
 
@@ -1419,12 +1422,12 @@
   }
 
   CompilerDriver* GetCompiler() const {
-    CHECK(compiler_ != NULL);
+    CHECK(compiler_ != nullptr);
     return compiler_;
   }
 
   const DexFile* GetDexFile() const {
-    CHECK(dex_file_ != NULL);
+    CHECK(dex_file_ != nullptr);
     return dex_file_;
   }
 
@@ -1499,10 +1502,10 @@
 // that avoids the expensive FindInClassPath search.
 static bool SkipClass(jobject class_loader, const DexFile& dex_file, mirror::Class* klass)
     SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
-  DCHECK(klass != NULL);
+  DCHECK(klass != nullptr);
   const DexFile& original_dex_file = *klass->GetDexCache()->GetDexFile();
   if (&dex_file != &original_dex_file) {
-    if (class_loader == NULL) {
+    if (class_loader == nullptr) {
       LOG(WARNING) << "Skipping class " << PrettyDescriptor(klass) << " from "
                    << dex_file.GetLocation() << " previously found in "
                    << original_dex_file.GetLocation();
@@ -1587,7 +1590,7 @@
   // static fields, instance fields, direct methods, and virtual
   // methods.
   const byte* class_data = dex_file.GetClassData(class_def);
-  if (class_data == NULL) {
+  if (class_data == nullptr) {
     // Empty class such as a marker interface.
     requires_constructor_barrier = false;
   } else {
@@ -1596,7 +1599,7 @@
       if (resolve_fields_and_methods) {
         mirror::ArtField* field = class_linker->ResolveField(dex_file, it.GetMemberIndex(),
                                                              dex_cache, class_loader, true);
-        if (field == NULL) {
+        if (field == nullptr) {
           CheckAndClearResolveException(soa.Self());
         }
       }
@@ -1605,13 +1608,13 @@
     // We require a constructor barrier if there are final instance fields.
     requires_constructor_barrier = false;
     while (it.HasNextInstanceField()) {
-      if ((it.GetMemberAccessFlags() & kAccFinal) != 0) {
+      if (it.MemberIsFinal()) {
         requires_constructor_barrier = true;
       }
       if (resolve_fields_and_methods) {
         mirror::ArtField* field = class_linker->ResolveField(dex_file, it.GetMemberIndex(),
                                                              dex_cache, class_loader, false);
-        if (field == NULL) {
+        if (field == nullptr) {
           CheckAndClearResolveException(soa.Self());
         }
       }
@@ -1623,7 +1626,7 @@
                                                                 dex_cache, class_loader,
                                                                 NullHandle<mirror::ArtMethod>(),
                                                                 it.GetMethodInvokeType(class_def));
-        if (method == NULL) {
+        if (method == nullptr) {
           CheckAndClearResolveException(soa.Self());
         }
         it.Next();
@@ -1633,7 +1636,7 @@
                                                                 dex_cache, class_loader,
                                                                 NullHandle<mirror::ArtMethod>(),
                                                                 it.GetMethodInvokeType(class_def));
-        if (method == NULL) {
+        if (method == nullptr) {
           CheckAndClearResolveException(soa.Self());
         }
         it.Next();
@@ -1658,9 +1661,9 @@
       hs.NewHandle(soa.Decode<mirror::ClassLoader*>(manager->GetClassLoader())));
   mirror::Class* klass = class_linker->ResolveType(dex_file, type_idx, dex_cache, class_loader);
 
-  if (klass == NULL) {
+  if (klass == nullptr) {
     CHECK(soa.Self()->IsExceptionPending());
-    mirror::Throwable* exception = soa.Self()->GetException(NULL);
+    mirror::Throwable* exception = soa.Self()->GetException(nullptr);
     VLOG(compiler) << "Exception during type resolution: " << exception->Dump();
     if (exception->GetClass()->DescriptorEquals("Ljava/lang/OutOfMemoryError;")) {
       // There's little point continuing compilation if the heap is exhausted.
@@ -1691,11 +1694,20 @@
   context.ForAll(0, dex_file.NumClassDefs(), ResolveClassFieldsAndMethods, thread_count_);
 }
 
+void CompilerDriver::SetVerified(jobject class_loader, const std::vector<const DexFile*>& dex_files,
+                                 ThreadPool* thread_pool, TimingLogger* timings) {
+  for (size_t i = 0; i != dex_files.size(); ++i) {
+    const DexFile* dex_file = dex_files[i];
+    CHECK(dex_file != nullptr);
+    SetVerifiedDexFile(class_loader, *dex_file, dex_files, thread_pool, timings);
+  }
+}
+
 void CompilerDriver::Verify(jobject class_loader, const std::vector<const DexFile*>& dex_files,
                             ThreadPool* thread_pool, TimingLogger* timings) {
   for (size_t i = 0; i != dex_files.size(); ++i) {
     const DexFile* dex_file = dex_files[i];
-    CHECK(dex_file != NULL);
+    CHECK(dex_file != nullptr);
     VerifyDexFile(class_loader, *dex_file, dex_files, thread_pool, timings);
   }
 }
@@ -1757,6 +1769,50 @@
   context.ForAll(0, dex_file.NumClassDefs(), VerifyClass, thread_count_);
 }
 
+static void SetVerifiedClass(const ParallelCompilationManager* manager, size_t class_def_index)
+    LOCKS_EXCLUDED(Locks::mutator_lock_) {
+  ATRACE_CALL();
+  ScopedObjectAccess soa(Thread::Current());
+  const DexFile& dex_file = *manager->GetDexFile();
+  const DexFile::ClassDef& class_def = dex_file.GetClassDef(class_def_index);
+  const char* descriptor = dex_file.GetClassDescriptor(class_def);
+  ClassLinker* class_linker = manager->GetClassLinker();
+  jobject jclass_loader = manager->GetClassLoader();
+  StackHandleScope<3> hs(soa.Self());
+  Handle<mirror::ClassLoader> class_loader(
+      hs.NewHandle(soa.Decode<mirror::ClassLoader*>(jclass_loader)));
+  Handle<mirror::Class> klass(
+      hs.NewHandle(class_linker->FindClass(soa.Self(), descriptor, class_loader)));
+  // Class might have failed resolution. Then don't set it to verified.
+  if (klass.Get() != nullptr) {
+    // Only do this if the class is resolved. If even resolution fails, quickening will go very,
+    // very wrong.
+    if (klass->IsResolved()) {
+      if (klass->GetStatus() < mirror::Class::kStatusVerified) {
+        ObjectLock<mirror::Class> lock(soa.Self(), klass);
+        klass->SetStatus(mirror::Class::kStatusVerified, soa.Self());
+      }
+      // Record the final class status if necessary.
+      ClassReference ref(manager->GetDexFile(), class_def_index);
+      manager->GetCompiler()->RecordClassStatus(ref, klass->GetStatus());
+    }
+  } else {
+    Thread* self = soa.Self();
+    DCHECK(self->IsExceptionPending());
+    self->ClearException();
+  }
+}
+
+void CompilerDriver::SetVerifiedDexFile(jobject class_loader, const DexFile& dex_file,
+                                        const std::vector<const DexFile*>& dex_files,
+                                        ThreadPool* thread_pool, TimingLogger* timings) {
+  TimingLogger::ScopedTiming t("Verify Dex File", timings);
+  ClassLinker* class_linker = Runtime::Current()->GetClassLinker();
+  ParallelCompilationManager context(class_linker, class_loader, this, &dex_file, dex_files,
+                                     thread_pool);
+  context.ForAll(0, dex_file.NumClassDefs(), SetVerifiedClass, thread_count_);
+}
+
 static void InitializeClass(const ParallelCompilationManager* manager, size_t class_def_index)
     LOCKS_EXCLUDED(Locks::mutator_lock_) {
   ATRACE_CALL();
@@ -1865,7 +1921,7 @@
                                        ThreadPool* thread_pool, TimingLogger* timings) {
   for (size_t i = 0; i != dex_files.size(); ++i) {
     const DexFile* dex_file = dex_files[i];
-    CHECK(dex_file != NULL);
+    CHECK(dex_file != nullptr);
     InitializeClasses(class_loader, *dex_file, dex_files, thread_pool, timings);
   }
   if (IsImage()) {
@@ -1878,7 +1934,7 @@
                              ThreadPool* thread_pool, TimingLogger* timings) {
   for (size_t i = 0; i != dex_files.size(); ++i) {
     const DexFile* dex_file = dex_files[i];
-    CHECK(dex_file != NULL);
+    CHECK(dex_file != nullptr);
     CompileDexFile(class_loader, *dex_file, dex_files, thread_pool, timings);
   }
 }
@@ -1911,7 +1967,7 @@
     return;
   }
   const byte* class_data = dex_file.GetClassData(class_def);
-  if (class_data == NULL) {
+  if (class_data == nullptr) {
     // empty class, probably a marker interface
     return;
   }
@@ -1946,7 +2002,7 @@
       continue;
     }
     previous_direct_method_idx = method_idx;
-    driver->CompileMethod(it.GetMethodCodeItem(), it.GetMemberAccessFlags(),
+    driver->CompileMethod(it.GetMethodCodeItem(), it.GetMethodAccessFlags(),
                           it.GetMethodInvokeType(class_def), class_def_index,
                           method_idx, jclass_loader, dex_file, dex_to_dex_compilation_level);
     it.Next();
@@ -1962,7 +2018,7 @@
       continue;
     }
     previous_virtual_method_idx = method_idx;
-    driver->CompileMethod(it.GetMethodCodeItem(), it.GetMemberAccessFlags(),
+    driver->CompileMethod(it.GetMethodCodeItem(), it.GetMethodAccessFlags(),
                           it.GetMethodInvokeType(class_def), class_def_index,
                           method_idx, jclass_loader, dex_file, dex_to_dex_compilation_level);
     it.Next();
@@ -1984,7 +2040,7 @@
                                    uint32_t method_idx, jobject class_loader,
                                    const DexFile& dex_file,
                                    DexToDexCompilationLevel dex_to_dex_compilation_level) {
-  CompiledMethod* compiled_method = NULL;
+  CompiledMethod* compiled_method = nullptr;
   uint64_t start_ns = kTimeCompileMethod ? NanoTime() : 0;
 
   if ((access_flags & kAccNative) != 0) {
@@ -1994,14 +2050,14 @@
       // Leaving this empty will trigger the generic JNI version
     } else {
       compiled_method = compiler_->JniCompile(access_flags, method_idx, dex_file);
-      CHECK(compiled_method != NULL);
+      CHECK(compiled_method != nullptr);
     }
   } else if ((access_flags & kAccAbstract) != 0) {
   } else {
     MethodReference method_ref(&dex_file, method_idx);
     bool compile = verification_results_->IsCandidateForCompilation(method_ref, access_flags);
     if (compile) {
-      // NOTE: if compiler declines to compile this method, it will return NULL.
+      // NOTE: if compiler declines to compile this method, it will return nullptr.
       compiled_method = compiler_->Compile(code_item, access_flags, invoke_type, class_def_idx,
                                            method_idx, class_loader, dex_file);
     }
@@ -2022,20 +2078,20 @@
   }
 
   Thread* self = Thread::Current();
-  if (compiled_method != NULL) {
+  if (compiled_method != nullptr) {
     MethodReference ref(&dex_file, method_idx);
-    DCHECK(GetCompiledMethod(ref) == NULL) << PrettyMethod(method_idx, dex_file);
+    DCHECK(GetCompiledMethod(ref) == nullptr) << PrettyMethod(method_idx, dex_file);
     {
       MutexLock mu(self, compiled_methods_lock_);
       compiled_methods_.Put(ref, compiled_method);
     }
-    DCHECK(GetCompiledMethod(ref) != NULL) << PrettyMethod(method_idx, dex_file);
+    DCHECK(GetCompiledMethod(ref) != nullptr) << PrettyMethod(method_idx, dex_file);
   }
 
   if (self->IsExceptionPending()) {
     ScopedObjectAccess soa(self);
     LOG(FATAL) << "Unexpected exception compiling: " << PrettyMethod(method_idx, dex_file) << "\n"
-        << self->GetException(NULL)->Dump();
+        << self->GetException(nullptr)->Dump();
   }
 }
 
@@ -2043,9 +2099,9 @@
   MutexLock mu(Thread::Current(), compiled_classes_lock_);
   ClassTable::const_iterator it = compiled_classes_.find(ref);
   if (it == compiled_classes_.end()) {
-    return NULL;
+    return nullptr;
   }
-  CHECK(it->second != NULL);
+  CHECK(it->second != nullptr);
   return it->second;
 }
 
@@ -2079,9 +2135,9 @@
   MutexLock mu(Thread::Current(), compiled_methods_lock_);
   MethodTable::const_iterator it = compiled_methods_.find(ref);
   if (it == compiled_methods_.end()) {
-    return NULL;
+    return nullptr;
   }
-  CHECK(it->second != NULL);
+  CHECK(it->second != nullptr);
   return it->second;
 }
 
diff --git a/compiler/driver/compiler_driver.h b/compiler/driver/compiler_driver.h
index 624947d..e7bd357 100644
--- a/compiler/driver/compiler_driver.h
+++ b/compiler/driver/compiler_driver.h
@@ -81,7 +81,7 @@
   // Create a compiler targeting the requested "instruction_set".
   // "image" should be true if image specific optimizations should be
   // enabled.  "image_classes" lets the compiler know what classes it
-  // can assume will be in the image, with NULL implying all available
+  // can assume will be in the image, with nullptr implying all available
   // classes.
   explicit CompilerDriver(const CompilerOptions* compiler_options,
                           VerificationResults* verification_results,
@@ -183,9 +183,9 @@
 
   // Are runtime access checks necessary in the compiled code?
   bool CanAccessTypeWithoutChecks(uint32_t referrer_idx, const DexFile& dex_file,
-                                  uint32_t type_idx, bool* type_known_final = NULL,
-                                  bool* type_known_abstract = NULL,
-                                  bool* equals_referrers_class = NULL)
+                                  uint32_t type_idx, bool* type_known_final = nullptr,
+                                  bool* type_known_abstract = nullptr,
+                                  bool* equals_referrers_class = nullptr)
       LOCKS_EXCLUDED(Locks::mutator_lock_);
 
   // Are runtime access and instantiable checks necessary in the code?
@@ -260,7 +260,7 @@
       uint16_t* declaring_class_idx, uint16_t* declaring_method_idx)
     SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
 
-  // Get declaration location of a resolved field.
+  // Get the index in the vtable of the method.
   uint16_t GetResolvedMethodVTableIndex(
       mirror::ArtMethod* resolved_method, InvokeType type)
     SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
@@ -436,7 +436,7 @@
         referrer_class_def_idx_(referrer_class_def_idx),
         referrer_method_idx_(referrer_method_idx),
         literal_offset_(literal_offset) {
-      CHECK(dex_file_ != NULL);
+      CHECK(dex_file_ != nullptr);
     }
     virtual ~PatchInformation() {}
 
@@ -655,6 +655,13 @@
                      ThreadPool* thread_pool, TimingLogger* timings)
       LOCKS_EXCLUDED(Locks::mutator_lock_);
 
+  void SetVerified(jobject class_loader, const std::vector<const DexFile*>& dex_files,
+                   ThreadPool* thread_pool, TimingLogger* timings);
+  void SetVerifiedDexFile(jobject class_loader, const DexFile& dex_file,
+                          const std::vector<const DexFile*>& dex_files,
+                          ThreadPool* thread_pool, TimingLogger* timings)
+      LOCKS_EXCLUDED(Locks::mutator_lock_);
+
   void InitializeClasses(jobject class_loader, const std::vector<const DexFile*>& dex_files,
                          ThreadPool* thread_pool, TimingLogger* timings)
       LOCKS_EXCLUDED(Locks::mutator_lock_);
@@ -712,7 +719,7 @@
   const bool image_;
 
   // If image_ is true, specifies the classes that will be included in
-  // the image. Note if image_classes_ is NULL, all classes are
+  // the image. Note if image_classes_ is nullptr, all classes are
   // included in the image.
   std::unique_ptr<std::set<std::string>> image_classes_;
 
diff --git a/compiler/elf_fixup.cc b/compiler/elf_fixup.cc
index bbfbc6e..0d34879 100644
--- a/compiler/elf_fixup.cc
+++ b/compiler/elf_fixup.cc
@@ -89,17 +89,18 @@
 
 bool ElfFixup::FixupSectionHeaders(ElfFile& elf_file, uintptr_t base_address) {
   for (Elf32_Word i = 0; i < elf_file.GetSectionHeaderNum(); i++) {
-    Elf32_Shdr& sh = elf_file.GetSectionHeader(i);
+    Elf32_Shdr* sh = elf_file.GetSectionHeader(i);
+    CHECK(sh != nullptr);
     // 0 implies that the section will not exist in the memory of the process
-    if (sh.sh_addr == 0) {
+    if (sh->sh_addr == 0) {
       continue;
     }
     if (DEBUG_FIXUP) {
       LOG(INFO) << StringPrintf("In %s moving Elf32_Shdr[%d] from 0x%08x to 0x%08" PRIxPTR,
                                 elf_file.GetFile().GetPath().c_str(), i,
-                                sh.sh_addr, sh.sh_addr + base_address);
+                                sh->sh_addr, sh->sh_addr + base_address);
     }
-    sh.sh_addr += base_address;
+    sh->sh_addr += base_address;
   }
   return true;
 }
@@ -107,18 +108,19 @@
 bool ElfFixup::FixupProgramHeaders(ElfFile& elf_file, uintptr_t base_address) {
   // TODO: ELFObjectFile doesn't have give to Elf32_Phdr, so we do that ourselves for now.
   for (Elf32_Word i = 0; i < elf_file.GetProgramHeaderNum(); i++) {
-    Elf32_Phdr& ph = elf_file.GetProgramHeader(i);
-    CHECK_EQ(ph.p_vaddr, ph.p_paddr) << elf_file.GetFile().GetPath() << " i=" << i;
-    CHECK((ph.p_align == 0) || (0 == ((ph.p_vaddr - ph.p_offset) & (ph.p_align - 1))))
+    Elf32_Phdr* ph = elf_file.GetProgramHeader(i);
+    CHECK(ph != nullptr);
+    CHECK_EQ(ph->p_vaddr, ph->p_paddr) << elf_file.GetFile().GetPath() << " i=" << i;
+    CHECK((ph->p_align == 0) || (0 == ((ph->p_vaddr - ph->p_offset) & (ph->p_align - 1))))
             << elf_file.GetFile().GetPath() << " i=" << i;
     if (DEBUG_FIXUP) {
       LOG(INFO) << StringPrintf("In %s moving Elf32_Phdr[%d] from 0x%08x to 0x%08" PRIxPTR,
                                 elf_file.GetFile().GetPath().c_str(), i,
-                                ph.p_vaddr, ph.p_vaddr + base_address);
+                                ph->p_vaddr, ph->p_vaddr + base_address);
     }
-    ph.p_vaddr += base_address;
-    ph.p_paddr += base_address;
-    CHECK((ph.p_align == 0) || (0 == ((ph.p_vaddr - ph.p_offset) & (ph.p_align - 1))))
+    ph->p_vaddr += base_address;
+    ph->p_paddr += base_address;
+    CHECK((ph->p_align == 0) || (0 == ((ph->p_vaddr - ph->p_offset) & (ph->p_align - 1))))
             << elf_file.GetFile().GetPath() << " i=" << i;
   }
   return true;
@@ -128,20 +130,21 @@
   Elf32_Word section_type = dynamic ? SHT_DYNSYM : SHT_SYMTAB;
   // TODO: Unfortunate ELFObjectFile has protected symbol access, so use ElfFile
   Elf32_Shdr* symbol_section = elf_file.FindSectionByType(section_type);
-  if (symbol_section == NULL) {
+  if (symbol_section == nullptr) {
     // file is missing optional .symtab
     CHECK(!dynamic) << elf_file.GetFile().GetPath();
     return true;
   }
   for (uint32_t i = 0; i < elf_file.GetSymbolNum(*symbol_section); i++) {
-    Elf32_Sym& symbol = elf_file.GetSymbol(section_type, i);
-    if (symbol.st_value != 0) {
+    Elf32_Sym* symbol = elf_file.GetSymbol(section_type, i);
+    CHECK(symbol != nullptr);
+    if (symbol->st_value != 0) {
       if (DEBUG_FIXUP) {
         LOG(INFO) << StringPrintf("In %s moving Elf32_Sym[%d] from 0x%08x to 0x%08" PRIxPTR,
                                   elf_file.GetFile().GetPath().c_str(), i,
-                                  symbol.st_value, symbol.st_value + base_address);
+                                  symbol->st_value, symbol->st_value + base_address);
       }
-      symbol.st_value += base_address;
+      symbol->st_value += base_address;
     }
   }
   return true;
@@ -149,10 +152,11 @@
 
 bool ElfFixup::FixupRelocations(ElfFile& elf_file, uintptr_t base_address) {
   for (Elf32_Word i = 0; i < elf_file.GetSectionHeaderNum(); i++) {
-    Elf32_Shdr& sh = elf_file.GetSectionHeader(i);
-    if (sh.sh_type == SHT_REL) {
-      for (uint32_t i = 0; i < elf_file.GetRelNum(sh); i++) {
-        Elf32_Rel& rel = elf_file.GetRel(sh, i);
+    Elf32_Shdr* sh = elf_file.GetSectionHeader(i);
+    CHECK(sh != nullptr);
+    if (sh->sh_type == SHT_REL) {
+      for (uint32_t i = 0; i < elf_file.GetRelNum(*sh); i++) {
+        Elf32_Rel& rel = elf_file.GetRel(*sh, i);
         if (DEBUG_FIXUP) {
           LOG(INFO) << StringPrintf("In %s moving Elf32_Rel[%d] from 0x%08x to 0x%08" PRIxPTR,
                                     elf_file.GetFile().GetPath().c_str(), i,
@@ -160,9 +164,9 @@
         }
         rel.r_offset += base_address;
       }
-    } else if (sh.sh_type == SHT_RELA) {
-      for (uint32_t i = 0; i < elf_file.GetRelaNum(sh); i++) {
-        Elf32_Rela& rela = elf_file.GetRela(sh, i);
+    } else if (sh->sh_type == SHT_RELA) {
+      for (uint32_t i = 0; i < elf_file.GetRelaNum(*sh); i++) {
+        Elf32_Rela& rela = elf_file.GetRela(*sh, i);
         if (DEBUG_FIXUP) {
           LOG(INFO) << StringPrintf("In %s moving Elf32_Rela[%d] from 0x%08x to 0x%08" PRIxPTR,
                                     elf_file.GetFile().GetPath().c_str(), i,
diff --git a/compiler/elf_patcher.cc b/compiler/elf_patcher.cc
index f192227..92eb4d8 100644
--- a/compiler/elf_patcher.cc
+++ b/compiler/elf_patcher.cc
@@ -276,7 +276,7 @@
         << "We got more patches than anticipated";
     CHECK_LE(reinterpret_cast<uintptr_t>(elf_file_->Begin()) + shdr->sh_offset + shdr->sh_size,
               reinterpret_cast<uintptr_t>(elf_file_->End())) << "section is too large";
-    CHECK(shdr == &elf_file_->GetSectionHeader(elf_file_->GetSectionHeaderNum() - 1) ||
+    CHECK(shdr == elf_file_->GetSectionHeader(elf_file_->GetSectionHeaderNum() - 1) ||
           shdr->sh_offset + shdr->sh_size <= (shdr + 1)->sh_offset)
         << "Section overlaps onto next section";
     // It's mmap'd so we can just memcpy.
diff --git a/compiler/elf_stripper.cc b/compiler/elf_stripper.cc
index 0b86ad0..457d8a0 100644
--- a/compiler/elf_stripper.cc
+++ b/compiler/elf_stripper.cc
@@ -72,13 +72,15 @@
   section_headers.reserve(elf_file->GetSectionHeaderNum());
 
 
-  Elf32_Shdr& string_section = elf_file->GetSectionNameStringSection();
+  Elf32_Shdr* string_section = elf_file->GetSectionNameStringSection();
+  CHECK(string_section != nullptr);
   for (Elf32_Word i = 0; i < elf_file->GetSectionHeaderNum(); i++) {
-    Elf32_Shdr& sh = elf_file->GetSectionHeader(i);
-    const char* name = elf_file->GetString(string_section, sh.sh_name);
-    if (name == NULL) {
+    Elf32_Shdr* sh = elf_file->GetSectionHeader(i);
+    CHECK(sh != nullptr);
+    const char* name = elf_file->GetString(*string_section, sh->sh_name);
+    if (name == nullptr) {
       CHECK_EQ(0U, i);
-      section_headers.push_back(sh);
+      section_headers.push_back(*sh);
       section_headers_original_indexes.push_back(0);
       continue;
     }
@@ -87,32 +89,34 @@
         || (strcmp(name, ".symtab") == 0)) {
       continue;
     }
-    section_headers.push_back(sh);
+    section_headers.push_back(*sh);
     section_headers_original_indexes.push_back(i);
   }
   CHECK_NE(0U, section_headers.size());
   CHECK_EQ(section_headers.size(), section_headers_original_indexes.size());
 
   // section 0 is the NULL section, sections start at offset of first section
-  Elf32_Off offset = elf_file->GetSectionHeader(1).sh_offset;
+  CHECK(elf_file->GetSectionHeader(1) != nullptr);
+  Elf32_Off offset = elf_file->GetSectionHeader(1)->sh_offset;
   for (size_t i = 1; i < section_headers.size(); i++) {
     Elf32_Shdr& new_sh = section_headers[i];
-    Elf32_Shdr& old_sh = elf_file->GetSectionHeader(section_headers_original_indexes[i]);
-    CHECK_EQ(new_sh.sh_name, old_sh.sh_name);
-    if (old_sh.sh_addralign > 1) {
-      offset = RoundUp(offset, old_sh.sh_addralign);
+    Elf32_Shdr* old_sh = elf_file->GetSectionHeader(section_headers_original_indexes[i]);
+    CHECK(old_sh != nullptr);
+    CHECK_EQ(new_sh.sh_name, old_sh->sh_name);
+    if (old_sh->sh_addralign > 1) {
+      offset = RoundUp(offset, old_sh->sh_addralign);
     }
-    if (old_sh.sh_offset == offset) {
+    if (old_sh->sh_offset == offset) {
       // already in place
-      offset += old_sh.sh_size;
+      offset += old_sh->sh_size;
       continue;
     }
     // shift section earlier
     memmove(elf_file->Begin() + offset,
-            elf_file->Begin() + old_sh.sh_offset,
-            old_sh.sh_size);
+            elf_file->Begin() + old_sh->sh_offset,
+            old_sh->sh_size);
     new_sh.sh_offset = offset;
-    offset += old_sh.sh_size;
+    offset += old_sh->sh_size;
   }
 
   Elf32_Off shoff = offset;
diff --git a/compiler/oat_writer.cc b/compiler/oat_writer.cc
index c5d1478..e74d6de 100644
--- a/compiler/oat_writer.cc
+++ b/compiler/oat_writer.cc
@@ -437,7 +437,7 @@
         std::vector<uint8_t> const * gc_map = compiled_method->GetGcMap();
         if (gc_map != nullptr) {
           size_t gc_map_size = gc_map->size() * sizeof(gc_map[0]);
-          bool is_native = (it.GetMemberAccessFlags() & kAccNative) != 0;
+          bool is_native = it.MemberIsNative();
           CHECK(gc_map_size != 0 || is_native || status < mirror::Class::kStatusVerified)
               << gc_map << " " << gc_map_size << " " << (is_native ? "true" : "false") << " "
               << (status < mirror::Class::kStatusVerified) << " " << status << " "
diff --git a/compiler/optimizing/builder.cc b/compiler/optimizing/builder.cc
index ecd6802..33b00d2 100644
--- a/compiler/optimizing/builder.cc
+++ b/compiler/optimizing/builder.cc
@@ -138,13 +138,15 @@
 
 template<typename T>
 void HGraphBuilder::If_22t(const Instruction& instruction, uint32_t dex_offset) {
+  int32_t target_offset = instruction.GetTargetOffset();
+  PotentiallyAddSuspendCheck(target_offset, dex_offset);
   HInstruction* first = LoadLocal(instruction.VRegA(), Primitive::kPrimInt);
   HInstruction* second = LoadLocal(instruction.VRegB(), Primitive::kPrimInt);
   T* comparison = new (arena_) T(first, second);
   current_block_->AddInstruction(comparison);
   HInstruction* ifinst = new (arena_) HIf(comparison);
   current_block_->AddInstruction(ifinst);
-  HBasicBlock* target = FindBlockStartingAt(dex_offset + instruction.GetTargetOffset());
+  HBasicBlock* target = FindBlockStartingAt(dex_offset + target_offset);
   DCHECK(target != nullptr);
   current_block_->AddSuccessor(target);
   target = FindBlockStartingAt(dex_offset + instruction.SizeInCodeUnits());
@@ -155,12 +157,14 @@
 
 template<typename T>
 void HGraphBuilder::If_21t(const Instruction& instruction, uint32_t dex_offset) {
+  int32_t target_offset = instruction.GetTargetOffset();
+  PotentiallyAddSuspendCheck(target_offset, dex_offset);
   HInstruction* value = LoadLocal(instruction.VRegA(), Primitive::kPrimInt);
   T* comparison = new (arena_) T(value, GetIntConstant(0));
   current_block_->AddInstruction(comparison);
   HInstruction* ifinst = new (arena_) HIf(comparison);
   current_block_->AddInstruction(ifinst);
-  HBasicBlock* target = FindBlockStartingAt(dex_offset + instruction.GetTargetOffset());
+  HBasicBlock* target = FindBlockStartingAt(dex_offset + target_offset);
   DCHECK(target != nullptr);
   current_block_->AddSuccessor(target);
   target = FindBlockStartingAt(dex_offset + instruction.SizeInCodeUnits());
@@ -209,6 +213,8 @@
   // Add the exit block at the end to give it the highest id.
   graph_->AddBlock(exit_block_);
   exit_block_->AddInstruction(new (arena_) HExit());
+  // Add the suspend check to the entry block.
+  entry_block_->AddInstruction(new (arena_) HSuspendCheck(0));
   entry_block_->AddInstruction(new (arena_) HGoto());
   return graph_;
 }
@@ -325,18 +331,61 @@
                                 bool is_range,
                                 uint32_t* args,
                                 uint32_t register_index) {
+  Instruction::Code opcode = instruction.Opcode();
+  InvokeType invoke_type;
+  switch (opcode) {
+    case Instruction::INVOKE_STATIC:
+    case Instruction::INVOKE_STATIC_RANGE:
+      invoke_type = kStatic;
+      break;
+    case Instruction::INVOKE_DIRECT:
+    case Instruction::INVOKE_DIRECT_RANGE:
+      invoke_type = kDirect;
+      break;
+    case Instruction::INVOKE_VIRTUAL:
+    case Instruction::INVOKE_VIRTUAL_RANGE:
+      invoke_type = kVirtual;
+      break;
+    case Instruction::INVOKE_INTERFACE:
+    case Instruction::INVOKE_INTERFACE_RANGE:
+      invoke_type = kInterface;
+      break;
+    case Instruction::INVOKE_SUPER_RANGE:
+    case Instruction::INVOKE_SUPER:
+      invoke_type = kSuper;
+      break;
+    default:
+      LOG(FATAL) << "Unexpected invoke op: " << opcode;
+      return false;
+  }
+
   const DexFile::MethodId& method_id = dex_file_->GetMethodId(method_idx);
   const DexFile::ProtoId& proto_id = dex_file_->GetProtoId(method_id.proto_idx_);
   const char* descriptor = dex_file_->StringDataByIdx(proto_id.shorty_idx_);
   Primitive::Type return_type = Primitive::GetType(descriptor[0]);
-  bool is_instance_call =
-      instruction.Opcode() != Instruction::INVOKE_STATIC
-      && instruction.Opcode() != Instruction::INVOKE_STATIC_RANGE;
+  bool is_instance_call = invoke_type != kStatic;
   const size_t number_of_arguments = strlen(descriptor) - (is_instance_call ? 0 : 1);
 
-  // Treat invoke-direct like static calls for now.
-  HInvoke* invoke = new (arena_) HInvokeStatic(
-      arena_, number_of_arguments, return_type, dex_offset, method_idx);
+  HInvoke* invoke = nullptr;
+  if (invoke_type == kVirtual) {
+    MethodReference target_method(dex_file_, method_idx);
+    uintptr_t direct_code;
+    uintptr_t direct_method;
+    int vtable_index;
+    // TODO: Add devirtualization support.
+    compiler_driver_->ComputeInvokeInfo(dex_compilation_unit_, dex_offset, true, true,
+                                        &invoke_type, &target_method, &vtable_index,
+                                        &direct_code, &direct_method);
+    if (vtable_index == -1) {
+      return false;
+    }
+    invoke = new (arena_) HInvokeVirtual(
+        arena_, number_of_arguments, return_type, dex_offset, vtable_index);
+  } else {
+    // Treat invoke-direct like static calls for now.
+    invoke = new (arena_) HInvokeStatic(
+        arena_, number_of_arguments, return_type, dex_offset, method_idx);
+  }
 
   size_t start_index = 0;
   Temporaries temps(graph_, is_instance_call ? 1 : 0);
@@ -462,7 +511,15 @@
   }
 }
 
-bool HGraphBuilder::AnalyzeDexInstruction(const Instruction& instruction, int32_t dex_offset) {
+void HGraphBuilder::PotentiallyAddSuspendCheck(int32_t target_offset, uint32_t dex_offset) {
+  if (target_offset <= 0) {
+    // Unconditionnally add a suspend check to backward branches. We can remove
+    // them after we recognize loops in the graph.
+    current_block_->AddInstruction(new (arena_) HSuspendCheck(dex_offset));
+  }
+}
+
+bool HGraphBuilder::AnalyzeDexInstruction(const Instruction& instruction, uint32_t dex_offset) {
   if (current_block_ == nullptr) {
     return true;  // Dead code
   }
@@ -580,7 +637,9 @@
     case Instruction::GOTO:
     case Instruction::GOTO_16:
     case Instruction::GOTO_32: {
-      HBasicBlock* target = FindBlockStartingAt(instruction.GetTargetOffset() + dex_offset);
+      int32_t offset = instruction.GetTargetOffset();
+      PotentiallyAddSuspendCheck(offset, dex_offset);
+      HBasicBlock* target = FindBlockStartingAt(offset + dex_offset);
       DCHECK(target != nullptr);
       current_block_->AddInstruction(new (arena_) HGoto());
       current_block_->AddSuccessor(target);
@@ -604,7 +663,8 @@
     }
 
     case Instruction::INVOKE_STATIC:
-    case Instruction::INVOKE_DIRECT: {
+    case Instruction::INVOKE_DIRECT:
+    case Instruction::INVOKE_VIRTUAL: {
       uint32_t method_idx = instruction.VRegB_35c();
       uint32_t number_of_vreg_arguments = instruction.VRegA_35c();
       uint32_t args[5];
@@ -616,7 +676,8 @@
     }
 
     case Instruction::INVOKE_STATIC_RANGE:
-    case Instruction::INVOKE_DIRECT_RANGE: {
+    case Instruction::INVOKE_DIRECT_RANGE:
+    case Instruction::INVOKE_VIRTUAL_RANGE: {
       uint32_t method_idx = instruction.VRegB_3rc();
       uint32_t number_of_vreg_arguments = instruction.VRegA_3rc();
       uint32_t register_index = instruction.VRegC();
diff --git a/compiler/optimizing/builder.h b/compiler/optimizing/builder.h
index 170c427..e143786 100644
--- a/compiler/optimizing/builder.h
+++ b/compiler/optimizing/builder.h
@@ -54,7 +54,7 @@
   // Analyzes the dex instruction and adds HInstruction to the graph
   // to execute that instruction. Returns whether the instruction can
   // be handled.
-  bool AnalyzeDexInstruction(const Instruction& instruction, int32_t dex_offset);
+  bool AnalyzeDexInstruction(const Instruction& instruction, uint32_t dex_offset);
 
   // Finds all instructions that start a new block, and populates branch_targets_ with
   // the newly created blocks.
@@ -70,6 +70,7 @@
   HLocal* GetLocalAt(int register_index) const;
   void UpdateLocal(int register_index, HInstruction* instruction) const;
   HInstruction* LoadLocal(int register_index, Primitive::Type type) const;
+  void PotentiallyAddSuspendCheck(int32_t target_offset, uint32_t dex_offset);
 
   // Temporarily returns whether the compiler supports the parameters
   // of the method.
diff --git a/compiler/optimizing/code_generator_arm.cc b/compiler/optimizing/code_generator_arm.cc
index e72e39b..ad62279 100644
--- a/compiler/optimizing/code_generator_arm.cc
+++ b/compiler/optimizing/code_generator_arm.cc
@@ -20,6 +20,7 @@
 #include "gc/accounting/card_table.h"
 #include "mirror/array.h"
 #include "mirror/art_method.h"
+#include "mirror/class.h"
 #include "thread.h"
 #include "utils/assembler.h"
 #include "utils/arm/assembler_arm.h"
@@ -90,6 +91,29 @@
   DISALLOW_COPY_AND_ASSIGN(StackOverflowCheckSlowPathARM);
 };
 
+class SuspendCheckSlowPathARM : public SlowPathCode {
+ public:
+  explicit SuspendCheckSlowPathARM(HSuspendCheck* instruction)
+      : instruction_(instruction) {}
+
+  virtual void EmitNativeCode(CodeGenerator* codegen) OVERRIDE {
+    __ Bind(GetEntryLabel());
+    int32_t offset = QUICK_ENTRYPOINT_OFFSET(kArmWordSize, pTestSuspend).Int32Value();
+    __ ldr(LR, Address(TR, offset));
+    __ blx(LR);
+    codegen->RecordPcInfo(instruction_, instruction_->GetDexPc());
+    __ b(GetReturnLabel());
+  }
+
+  Label* GetReturnLabel() { return &return_label_; }
+
+ private:
+  HSuspendCheck* const instruction_;
+  Label return_label_;
+
+  DISALLOW_COPY_AND_ASSIGN(SuspendCheckSlowPathARM);
+};
+
 class BoundsCheckSlowPathARM : public SlowPathCode {
  public:
   explicit BoundsCheckSlowPathARM(HBoundsCheck* instruction,
@@ -795,6 +819,47 @@
 }
 
 void LocationsBuilderARM::VisitInvokeStatic(HInvokeStatic* invoke) {
+  HandleInvoke(invoke);
+}
+
+void InstructionCodeGeneratorARM::LoadCurrentMethod(Register reg) {
+  __ ldr(reg, Address(SP, kCurrentMethodStackOffset));
+}
+
+void InstructionCodeGeneratorARM::VisitInvokeStatic(HInvokeStatic* invoke) {
+  Register temp = invoke->GetLocations()->GetTemp(0).AsArm().AsCoreRegister();
+  uint32_t heap_reference_size = sizeof(mirror::HeapReference<mirror::Object>);
+  size_t index_in_cache = mirror::Array::DataOffset(heap_reference_size).Int32Value() +
+      invoke->GetIndexInDexCache() * kArmWordSize;
+
+  // TODO: Implement all kinds of calls:
+  // 1) boot -> boot
+  // 2) app -> boot
+  // 3) app -> app
+  //
+  // Currently we implement the app -> app logic, which looks up in the resolve cache.
+
+  // temp = method;
+  LoadCurrentMethod(temp);
+  // temp = temp->dex_cache_resolved_methods_;
+  __ ldr(temp, Address(temp, mirror::ArtMethod::DexCacheResolvedMethodsOffset().Int32Value()));
+  // temp = temp[index_in_cache]
+  __ ldr(temp, Address(temp, index_in_cache));
+  // LR = temp[offset_of_quick_compiled_code]
+  __ ldr(LR, Address(temp,
+                     mirror::ArtMethod::EntryPointFromQuickCompiledCodeOffset().Int32Value()));
+  // LR()
+  __ blx(LR);
+
+  codegen_->RecordPcInfo(invoke, invoke->GetDexPc());
+  DCHECK(!codegen_->IsLeafMethod());
+}
+
+void LocationsBuilderARM::VisitInvokeVirtual(HInvokeVirtual* invoke) {
+  HandleInvoke(invoke);
+}
+
+void LocationsBuilderARM::HandleInvoke(HInvoke* invoke) {
   LocationSummary* locations =
       new (GetGraph()->GetArena()) LocationSummary(invoke, LocationSummary::kCall);
   locations->AddTemp(ArmCoreLocation(R0));
@@ -829,37 +894,30 @@
   }
 }
 
-void InstructionCodeGeneratorARM::LoadCurrentMethod(Register reg) {
-  __ ldr(reg, Address(SP, kCurrentMethodStackOffset));
-}
 
-void InstructionCodeGeneratorARM::VisitInvokeStatic(HInvokeStatic* invoke) {
+void InstructionCodeGeneratorARM::VisitInvokeVirtual(HInvokeVirtual* invoke) {
   Register temp = invoke->GetLocations()->GetTemp(0).AsArm().AsCoreRegister();
-  uint32_t heap_reference_size = sizeof(mirror::HeapReference<mirror::Object>);
-  size_t index_in_cache = mirror::Array::DataOffset(heap_reference_size).Int32Value() +
-      invoke->GetIndexInDexCache() * kArmWordSize;
-
-  // TODO: Implement all kinds of calls:
-  // 1) boot -> boot
-  // 2) app -> boot
-  // 3) app -> app
-  //
-  // Currently we implement the app -> app logic, which looks up in the resolve cache.
-
-  // temp = method;
-  LoadCurrentMethod(temp);
-  // temp = temp->dex_cache_resolved_methods_;
-  __ ldr(temp, Address(temp, mirror::ArtMethod::DexCacheResolvedMethodsOffset().Int32Value()));
-  // temp = temp[index_in_cache]
-  __ ldr(temp, Address(temp, index_in_cache));
-  // LR = temp[offset_of_quick_compiled_code]
-  __ ldr(LR, Address(temp,
-                     mirror::ArtMethod::EntryPointFromQuickCompiledCodeOffset().Int32Value()));
-  // LR()
+  uint32_t method_offset = mirror::Class::EmbeddedVTableOffset().Uint32Value() +
+          invoke->GetVTableIndex() * sizeof(mirror::Class::VTableEntry);
+  LocationSummary* locations = invoke->GetLocations();
+  Location receiver = locations->InAt(0);
+  uint32_t class_offset = mirror::Object::ClassOffset().Int32Value();
+  // temp = object->GetClass();
+  if (receiver.IsStackSlot()) {
+    __ ldr(temp, Address(SP, receiver.GetStackIndex()));
+    __ ldr(temp, Address(temp, class_offset));
+  } else {
+    __ ldr(temp, Address(receiver.AsArm().AsCoreRegister(), class_offset));
+  }
+  // temp = temp->GetMethodAt(method_offset);
+  uint32_t entry_point = mirror::ArtMethod::EntryPointFromQuickCompiledCodeOffset().Int32Value();
+  __ ldr(temp, Address(temp, method_offset));
+  // LR = temp->GetEntryPoint();
+  __ ldr(LR, Address(temp, entry_point));
+  // LR();
   __ blx(LR);
-
-  codegen_->RecordPcInfo(invoke, invoke->GetDexPc());
   DCHECK(!codegen_->IsLeafMethod());
+  codegen_->RecordPcInfo(invoke, invoke->GetDexPc());
 }
 
 void LocationsBuilderARM::VisitAdd(HAdd* add) {
@@ -1494,6 +1552,21 @@
   codegen_->GetMoveResolver()->EmitNativeCode(instruction);
 }
 
+void LocationsBuilderARM::VisitSuspendCheck(HSuspendCheck* instruction) {
+  new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kCallOnSlowPath);
+}
+
+void InstructionCodeGeneratorARM::VisitSuspendCheck(HSuspendCheck* instruction) {
+  SuspendCheckSlowPathARM* slow_path =
+      new (GetGraph()->GetArena()) SuspendCheckSlowPathARM(instruction);
+  codegen_->AddSlowPath(slow_path);
+
+  __ AddConstant(R4, R4, -1);
+  __ cmp(R4, ShifterOperand(0));
+  __ b(slow_path->GetEntryLabel(), LE);
+  __ Bind(slow_path->GetReturnLabel());
+}
+
 ArmAssembler* ParallelMoveResolverARM::GetAssembler() const {
   return codegen_->GetAssembler();
 }
diff --git a/compiler/optimizing/code_generator_arm.h b/compiler/optimizing/code_generator_arm.h
index 660294b..2480960 100644
--- a/compiler/optimizing/code_generator_arm.h
+++ b/compiler/optimizing/code_generator_arm.h
@@ -93,6 +93,8 @@
 
 #undef DECLARE_VISIT_INSTRUCTION
 
+  void HandleInvoke(HInvoke* invoke);
+
  private:
   CodeGeneratorARM* const codegen_;
   InvokeDexCallingConventionVisitor parameter_visitor_;
diff --git a/compiler/optimizing/code_generator_x86.cc b/compiler/optimizing/code_generator_x86.cc
index 6602d3f..3383cb2 100644
--- a/compiler/optimizing/code_generator_x86.cc
+++ b/compiler/optimizing/code_generator_x86.cc
@@ -20,6 +20,7 @@
 #include "gc/accounting/card_table.h"
 #include "mirror/array.h"
 #include "mirror/art_method.h"
+#include "mirror/class.h"
 #include "thread.h"
 #include "utils/assembler.h"
 #include "utils/stack_checks.h"
@@ -114,6 +115,27 @@
   DISALLOW_COPY_AND_ASSIGN(BoundsCheckSlowPathX86);
 };
 
+class SuspendCheckSlowPathX86 : public SlowPathCode {
+ public:
+  explicit SuspendCheckSlowPathX86(HSuspendCheck* instruction)
+      : instruction_(instruction) {}
+
+  virtual void EmitNativeCode(CodeGenerator* codegen) OVERRIDE {
+    __ Bind(GetEntryLabel());
+    __ fs()->call(Address::Absolute(QUICK_ENTRYPOINT_OFFSET(kX86WordSize, pTestSuspend)));
+    codegen->RecordPcInfo(instruction_, instruction_->GetDexPc());
+    __ jmp(GetReturnLabel());
+  }
+
+  Label* GetReturnLabel() { return &return_label_; }
+
+ private:
+  HSuspendCheck* const instruction_;
+  Label return_label_;
+
+  DISALLOW_COPY_AND_ASSIGN(SuspendCheckSlowPathX86);
+};
+
 #undef __
 #define __ reinterpret_cast<X86Assembler*>(GetAssembler())->
 
@@ -742,6 +764,40 @@
 }
 
 void LocationsBuilderX86::VisitInvokeStatic(HInvokeStatic* invoke) {
+  HandleInvoke(invoke);
+}
+
+void InstructionCodeGeneratorX86::VisitInvokeStatic(HInvokeStatic* invoke) {
+  Register temp = invoke->GetLocations()->GetTemp(0).AsX86().AsCpuRegister();
+  uint32_t heap_reference_size = sizeof(mirror::HeapReference<mirror::Object>);
+  size_t index_in_cache = mirror::Array::DataOffset(heap_reference_size).Int32Value() +
+      invoke->GetIndexInDexCache() * kX86WordSize;
+
+  // TODO: Implement all kinds of calls:
+  // 1) boot -> boot
+  // 2) app -> boot
+  // 3) app -> app
+  //
+  // Currently we implement the app -> app logic, which looks up in the resolve cache.
+
+  // temp = method;
+  LoadCurrentMethod(temp);
+  // temp = temp->dex_cache_resolved_methods_;
+  __ movl(temp, Address(temp, mirror::ArtMethod::DexCacheResolvedMethodsOffset().Int32Value()));
+  // temp = temp[index_in_cache]
+  __ movl(temp, Address(temp, index_in_cache));
+  // (temp + offset_of_quick_compiled_code)()
+  __ call(Address(temp, mirror::ArtMethod::EntryPointFromQuickCompiledCodeOffset().Int32Value()));
+
+  DCHECK(!codegen_->IsLeafMethod());
+  codegen_->RecordPcInfo(invoke, invoke->GetDexPc());
+}
+
+void LocationsBuilderX86::VisitInvokeVirtual(HInvokeVirtual* invoke) {
+  HandleInvoke(invoke);
+}
+
+void LocationsBuilderX86::HandleInvoke(HInvoke* invoke) {
   LocationSummary* locations =
       new (GetGraph()->GetArena()) LocationSummary(invoke, LocationSummary::kCall);
   locations->AddTemp(X86CpuLocation(EAX));
@@ -778,26 +834,23 @@
   invoke->SetLocations(locations);
 }
 
-void InstructionCodeGeneratorX86::VisitInvokeStatic(HInvokeStatic* invoke) {
+void InstructionCodeGeneratorX86::VisitInvokeVirtual(HInvokeVirtual* invoke) {
   Register temp = invoke->GetLocations()->GetTemp(0).AsX86().AsCpuRegister();
-  uint32_t heap_reference_size = sizeof(mirror::HeapReference<mirror::Object>);
-  size_t index_in_cache = mirror::Array::DataOffset(heap_reference_size).Int32Value() +
-      invoke->GetIndexInDexCache() * kX86WordSize;
-
-  // TODO: Implement all kinds of calls:
-  // 1) boot -> boot
-  // 2) app -> boot
-  // 3) app -> app
-  //
-  // Currently we implement the app -> app logic, which looks up in the resolve cache.
-
-  // temp = method;
-  LoadCurrentMethod(temp);
-  // temp = temp->dex_cache_resolved_methods_;
-  __ movl(temp, Address(temp, mirror::ArtMethod::DexCacheResolvedMethodsOffset().Int32Value()));
-  // temp = temp[index_in_cache]
-  __ movl(temp, Address(temp, index_in_cache));
-  // (temp + offset_of_quick_compiled_code)()
+  uint32_t method_offset = mirror::Class::EmbeddedVTableOffset().Uint32Value() +
+          invoke->GetVTableIndex() * sizeof(mirror::Class::VTableEntry);
+  LocationSummary* locations = invoke->GetLocations();
+  Location receiver = locations->InAt(0);
+  uint32_t class_offset = mirror::Object::ClassOffset().Int32Value();
+  // temp = object->GetClass();
+  if (receiver.IsStackSlot()) {
+    __ movl(temp, Address(ESP, receiver.GetStackIndex()));
+    __ movl(temp, Address(temp, class_offset));
+  } else {
+    __ movl(temp, Address(receiver.AsX86().AsCpuRegister(), class_offset));
+  }
+  // temp = temp->GetMethodAt(method_offset);
+  __ movl(temp, Address(temp, method_offset));
+  // call temp->GetEntryPoint();
   __ call(Address(temp, mirror::ArtMethod::EntryPointFromQuickCompiledCodeOffset().Int32Value()));
 
   DCHECK(!codegen_->IsLeafMethod());
@@ -1483,6 +1536,20 @@
   codegen_->GetMoveResolver()->EmitNativeCode(instruction);
 }
 
+void LocationsBuilderX86::VisitSuspendCheck(HSuspendCheck* instruction) {
+  new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kCallOnSlowPath);
+}
+
+void InstructionCodeGeneratorX86::VisitSuspendCheck(HSuspendCheck* instruction) {
+  SuspendCheckSlowPathX86* slow_path =
+      new (GetGraph()->GetArena()) SuspendCheckSlowPathX86(instruction);
+  codegen_->AddSlowPath(slow_path);
+  __ fs()->cmpl(Address::Absolute(
+      Thread::ThreadFlagsOffset<kX86WordSize>().Int32Value()), Immediate(0));
+  __ j(kNotEqual, slow_path->GetEntryLabel());
+  __ Bind(slow_path->GetReturnLabel());
+}
+
 X86Assembler* ParallelMoveResolverX86::GetAssembler() const {
   return codegen_->GetAssembler();
 }
diff --git a/compiler/optimizing/code_generator_x86.h b/compiler/optimizing/code_generator_x86.h
index 7c50204..f1be0ad 100644
--- a/compiler/optimizing/code_generator_x86.h
+++ b/compiler/optimizing/code_generator_x86.h
@@ -94,6 +94,8 @@
 
 #undef DECLARE_VISIT_INSTRUCTION
 
+  void HandleInvoke(HInvoke* invoke);
+
  private:
   CodeGeneratorX86* const codegen_;
   InvokeDexCallingConventionVisitor parameter_visitor_;
diff --git a/compiler/optimizing/code_generator_x86_64.cc b/compiler/optimizing/code_generator_x86_64.cc
index b2d81e3..ca03af8 100644
--- a/compiler/optimizing/code_generator_x86_64.cc
+++ b/compiler/optimizing/code_generator_x86_64.cc
@@ -20,6 +20,7 @@
 #include "gc/accounting/card_table.h"
 #include "mirror/array.h"
 #include "mirror/art_method.h"
+#include "mirror/class.h"
 #include "mirror/object_reference.h"
 #include "thread.h"
 #include "utils/assembler.h"
@@ -95,6 +96,27 @@
   DISALLOW_COPY_AND_ASSIGN(StackOverflowCheckSlowPathX86_64);
 };
 
+class SuspendCheckSlowPathX86_64 : public SlowPathCode {
+ public:
+  explicit SuspendCheckSlowPathX86_64(HSuspendCheck* instruction)
+      : instruction_(instruction) {}
+
+  virtual void EmitNativeCode(CodeGenerator* codegen) OVERRIDE {
+    __ Bind(GetEntryLabel());
+    __ gs()->call(Address::Absolute(QUICK_ENTRYPOINT_OFFSET(kX86_64WordSize, pTestSuspend), true));
+    codegen->RecordPcInfo(instruction_, instruction_->GetDexPc());
+    __ jmp(GetReturnLabel());
+  }
+
+  Label* GetReturnLabel() { return &return_label_; }
+
+ private:
+  HSuspendCheck* const instruction_;
+  Label return_label_;
+
+  DISALLOW_COPY_AND_ASSIGN(SuspendCheckSlowPathX86_64);
+};
+
 class BoundsCheckSlowPathX86_64 : public SlowPathCode {
  public:
   explicit BoundsCheckSlowPathX86_64(HBoundsCheck* instruction,
@@ -688,12 +710,46 @@
 }
 
 void LocationsBuilderX86_64::VisitInvokeStatic(HInvokeStatic* invoke) {
+  HandleInvoke(invoke);
+}
+
+void InstructionCodeGeneratorX86_64::VisitInvokeStatic(HInvokeStatic* invoke) {
+  CpuRegister temp = invoke->GetLocations()->GetTemp(0).AsX86_64().AsCpuRegister();
+  uint32_t heap_reference_size = sizeof(mirror::HeapReference<mirror::Object>);
+  size_t index_in_cache = mirror::Array::DataOffset(heap_reference_size).SizeValue() +
+      invoke->GetIndexInDexCache() * heap_reference_size;
+
+  // TODO: Implement all kinds of calls:
+  // 1) boot -> boot
+  // 2) app -> boot
+  // 3) app -> app
+  //
+  // Currently we implement the app -> app logic, which looks up in the resolve cache.
+
+  // temp = method;
+  LoadCurrentMethod(temp);
+  // temp = temp->dex_cache_resolved_methods_;
+  __ movl(temp, Address(temp, mirror::ArtMethod::DexCacheResolvedMethodsOffset().SizeValue()));
+  // temp = temp[index_in_cache]
+  __ movl(temp, Address(temp, index_in_cache));
+  // (temp + offset_of_quick_compiled_code)()
+  __ call(Address(temp, mirror::ArtMethod::EntryPointFromQuickCompiledCodeOffset().SizeValue()));
+
+  DCHECK(!codegen_->IsLeafMethod());
+  codegen_->RecordPcInfo(invoke, invoke->GetDexPc());
+}
+
+void LocationsBuilderX86_64::VisitInvokeVirtual(HInvokeVirtual* invoke) {
+  HandleInvoke(invoke);
+}
+
+void LocationsBuilderX86_64::HandleInvoke(HInvoke* invoke) {
   LocationSummary* locations =
       new (GetGraph()->GetArena()) LocationSummary(invoke, LocationSummary::kCall);
   locations->AddTemp(X86_64CpuLocation(RDI));
 
   InvokeDexCallingConventionVisitor calling_convention_visitor;
-  for (size_t i = 0; i < invoke->InputCount(); ++i) {
+  for (size_t i = 0; i < invoke->InputCount(); i++) {
     HInstruction* input = invoke->InputAt(i);
     locations->SetInAt(i, calling_convention_visitor.GetNextLocation(input->GetType()));
   }
@@ -719,26 +775,23 @@
   }
 }
 
-void InstructionCodeGeneratorX86_64::VisitInvokeStatic(HInvokeStatic* invoke) {
+void InstructionCodeGeneratorX86_64::VisitInvokeVirtual(HInvokeVirtual* invoke) {
   CpuRegister temp = invoke->GetLocations()->GetTemp(0).AsX86_64().AsCpuRegister();
-  uint32_t heap_reference_size = sizeof(mirror::HeapReference<mirror::Object>);
-  size_t index_in_cache = mirror::Array::DataOffset(heap_reference_size).SizeValue() +
-      invoke->GetIndexInDexCache() * heap_reference_size;
-
-  // TODO: Implement all kinds of calls:
-  // 1) boot -> boot
-  // 2) app -> boot
-  // 3) app -> app
-  //
-  // Currently we implement the app -> app logic, which looks up in the resolve cache.
-
-  // temp = method;
-  LoadCurrentMethod(temp);
-  // temp = temp->dex_cache_resolved_methods_;
-  __ movl(temp, Address(temp, mirror::ArtMethod::DexCacheResolvedMethodsOffset().SizeValue()));
-  // temp = temp[index_in_cache]
-  __ movl(temp, Address(temp, index_in_cache));
-  // (temp + offset_of_quick_compiled_code)()
+  size_t method_offset = mirror::Class::EmbeddedVTableOffset().SizeValue() +
+          invoke->GetVTableIndex() * sizeof(mirror::Class::VTableEntry);
+  LocationSummary* locations = invoke->GetLocations();
+  Location receiver = locations->InAt(0);
+  size_t class_offset = mirror::Object::ClassOffset().SizeValue();
+  // temp = object->GetClass();
+  if (receiver.IsStackSlot()) {
+    __ movq(temp, Address(CpuRegister(RSP), receiver.GetStackIndex()));
+    __ movq(temp, Address(temp, class_offset));
+  } else {
+    __ movq(temp, Address(receiver.AsX86_64().AsCpuRegister(), class_offset));
+  }
+  // temp = temp->GetMethodAt(method_offset);
+  __ movl(temp, Address(temp, method_offset));
+  // call temp->GetEntryPoint();
   __ call(Address(temp, mirror::ArtMethod::EntryPointFromQuickCompiledCodeOffset().SizeValue()));
 
   DCHECK(!codegen_->IsLeafMethod());
@@ -1329,6 +1382,20 @@
   codegen_->GetMoveResolver()->EmitNativeCode(instruction);
 }
 
+void LocationsBuilderX86_64::VisitSuspendCheck(HSuspendCheck* instruction) {
+  new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kCallOnSlowPath);
+}
+
+void InstructionCodeGeneratorX86_64::VisitSuspendCheck(HSuspendCheck* instruction) {
+  SuspendCheckSlowPathX86_64* slow_path =
+      new (GetGraph()->GetArena()) SuspendCheckSlowPathX86_64(instruction);
+  codegen_->AddSlowPath(slow_path);
+  __ gs()->cmpl(Address::Absolute(
+      Thread::ThreadFlagsOffset<kX86_64WordSize>().Int32Value(), true), Immediate(0));
+  __ j(kNotEqual, slow_path->GetEntryLabel());
+  __ Bind(slow_path->GetReturnLabel());
+}
+
 X86_64Assembler* ParallelMoveResolverX86_64::GetAssembler() const {
   return codegen_->GetAssembler();
 }
diff --git a/compiler/optimizing/code_generator_x86_64.h b/compiler/optimizing/code_generator_x86_64.h
index 44552ea..78b60fe 100644
--- a/compiler/optimizing/code_generator_x86_64.h
+++ b/compiler/optimizing/code_generator_x86_64.h
@@ -91,6 +91,8 @@
 
 #undef DECLARE_VISIT_INSTRUCTION
 
+  void HandleInvoke(HInvoke* invoke);
+
  private:
   CodeGeneratorX86_64* const codegen_;
   InvokeDexCallingConventionVisitor parameter_visitor_;
diff --git a/compiler/optimizing/codegen_test.cc b/compiler/optimizing/codegen_test.cc
index b9712e1..7161eed 100644
--- a/compiler/optimizing/codegen_test.cc
+++ b/compiler/optimizing/codegen_test.cc
@@ -72,6 +72,8 @@
   HGraphBuilder builder(&arena);
   const DexFile::CodeItem* item = reinterpret_cast<const DexFile::CodeItem*>(data);
   HGraph* graph = builder.BuildGraph(*item);
+  // Remove suspend checks, they cannot be executed in this context.
+  RemoveSuspendChecks(graph);
   ASSERT_NE(graph, nullptr);
   InternalCodeAllocator allocator;
 
diff --git a/compiler/optimizing/live_ranges_test.cc b/compiler/optimizing/live_ranges_test.cc
index 21e634d..a81a30e 100644
--- a/compiler/optimizing/live_ranges_test.cc
+++ b/compiler/optimizing/live_ranges_test.cc
@@ -32,6 +32,9 @@
   HGraphBuilder builder(allocator);
   const DexFile::CodeItem* item = reinterpret_cast<const DexFile::CodeItem*>(data);
   HGraph* graph = builder.BuildGraph(*item);
+  // Suspend checks implementation may change in the future, and this test relies
+  // on how instructions are ordered.
+  RemoveSuspendChecks(graph);
   graph->BuildDominatorTree();
   graph->TransformToSSA();
   graph->FindNaturalLoops();
diff --git a/compiler/optimizing/nodes.h b/compiler/optimizing/nodes.h
index 9018fee..d6dfeae 100644
--- a/compiler/optimizing/nodes.h
+++ b/compiler/optimizing/nodes.h
@@ -422,6 +422,7 @@
   M(If)                                                    \
   M(IntConstant)                                           \
   M(InvokeStatic)                                          \
+  M(InvokeVirtual)                                         \
   M(LoadLocal)                                             \
   M(Local)                                                 \
   M(LongConstant)                                          \
@@ -443,6 +444,7 @@
   M(BoundsCheck)                                           \
   M(NullCheck)                                             \
   M(Temporary)                                             \
+  M(SuspendCheck)                                          \
 
 #define FOR_EACH_INSTRUCTION(M)                            \
   FOR_EACH_CONCRETE_INSTRUCTION(M)                         \
@@ -1271,6 +1273,26 @@
   DISALLOW_COPY_AND_ASSIGN(HInvokeStatic);
 };
 
+class HInvokeVirtual : public HInvoke {
+ public:
+  HInvokeVirtual(ArenaAllocator* arena,
+                 uint32_t number_of_arguments,
+                 Primitive::Type return_type,
+                 uint32_t dex_pc,
+                 uint32_t vtable_index)
+      : HInvoke(arena, number_of_arguments, return_type, dex_pc),
+        vtable_index_(vtable_index) {}
+
+  uint32_t GetVTableIndex() const { return vtable_index_; }
+
+  DECLARE_INSTRUCTION(InvokeVirtual);
+
+ private:
+  const uint32_t vtable_index_;
+
+  DISALLOW_COPY_AND_ASSIGN(HInvokeVirtual);
+};
+
 class HNewInstance : public HExpression<0> {
  public:
   HNewInstance(uint32_t dex_pc, uint16_t type_index)
@@ -1593,6 +1615,25 @@
   DISALLOW_COPY_AND_ASSIGN(HTemporary);
 };
 
+class HSuspendCheck : public HTemplateInstruction<0> {
+ public:
+  explicit HSuspendCheck(uint32_t dex_pc)
+      : HTemplateInstruction(SideEffects::ChangesSomething()), dex_pc_(dex_pc) {}
+
+  virtual bool NeedsEnvironment() const {
+    return true;
+  }
+
+  uint32_t GetDexPc() const { return dex_pc_; }
+
+  DECLARE_INSTRUCTION(SuspendCheck);
+
+ private:
+  const uint32_t dex_pc_;
+
+  DISALLOW_COPY_AND_ASSIGN(HSuspendCheck);
+};
+
 class MoveOperands : public ArenaObject {
  public:
   MoveOperands(Location source, Location destination)
diff --git a/compiler/optimizing/optimizing_unit_test.h b/compiler/optimizing/optimizing_unit_test.h
index 36a6a21..c409529 100644
--- a/compiler/optimizing/optimizing_unit_test.h
+++ b/compiler/optimizing/optimizing_unit_test.h
@@ -48,6 +48,19 @@
   return interval;
 }
 
+void RemoveSuspendChecks(HGraph* graph) {
+  for (size_t i = 0, e = graph->GetBlocks().Size(); i < e; ++i) {
+    for (HInstructionIterator it(graph->GetBlocks().Get(i)->GetInstructions());
+         !it.Done();
+         it.Advance()) {
+      HInstruction* current = it.Current();
+      if (current->IsSuspendCheck()) {
+        current->GetBlock()->RemoveInstruction(current);
+      }
+    }
+  }
+}
+
 }  // namespace art
 
 #endif  // ART_COMPILER_OPTIMIZING_OPTIMIZING_UNIT_TEST_H_
diff --git a/compiler/optimizing/pretty_printer_test.cc b/compiler/optimizing/pretty_printer_test.cc
index 7e604e9..da6b294 100644
--- a/compiler/optimizing/pretty_printer_test.cc
+++ b/compiler/optimizing/pretty_printer_test.cc
@@ -45,7 +45,8 @@
 
   const char* expected =
       "BasicBlock 0, succ: 1\n"
-      "  2: Goto 1\n"
+      "  2: SuspendCheck\n"
+      "  3: Goto 1\n"
       "BasicBlock 1, pred: 0, succ: 2\n"
       "  0: ReturnVoid\n"
       "BasicBlock 2, pred: 1\n"
@@ -57,7 +58,8 @@
 TEST(PrettyPrinterTest, CFG1) {
   const char* expected =
     "BasicBlock 0, succ: 1\n"
-    "  3: Goto 1\n"
+    "  3: SuspendCheck\n"
+    "  4: Goto 1\n"
     "BasicBlock 1, pred: 0, succ: 2\n"
     "  0: Goto 2\n"
     "BasicBlock 2, pred: 1, succ: 3\n"
@@ -76,7 +78,8 @@
 TEST(PrettyPrinterTest, CFG2) {
   const char* expected =
     "BasicBlock 0, succ: 1\n"
-    "  4: Goto 1\n"
+    "  4: SuspendCheck\n"
+    "  5: Goto 1\n"
     "BasicBlock 1, pred: 0, succ: 2\n"
     "  0: Goto 2\n"
     "BasicBlock 2, pred: 1, succ: 3\n"
@@ -97,15 +100,17 @@
 TEST(PrettyPrinterTest, CFG3) {
   const char* expected =
     "BasicBlock 0, succ: 1\n"
-    "  4: Goto 1\n"
+    "  5: SuspendCheck\n"
+    "  6: Goto 1\n"
     "BasicBlock 1, pred: 0, succ: 3\n"
     "  0: Goto 3\n"
     "BasicBlock 2, pred: 3, succ: 4\n"
     "  1: ReturnVoid\n"
     "BasicBlock 3, pred: 1, succ: 2\n"
-    "  2: Goto 2\n"
+    "  2: SuspendCheck\n"
+    "  3: Goto 2\n"
     "BasicBlock 4, pred: 2\n"
-    "  3: Exit\n";
+    "  4: Exit\n";
 
   const uint16_t data1[] = ZERO_REGISTER_CODE_ITEM(
     Instruction::GOTO | 0x200,
@@ -132,11 +137,13 @@
 TEST(PrettyPrinterTest, CFG4) {
   const char* expected =
     "BasicBlock 0, succ: 1\n"
-    "  2: Goto 1\n"
+    "  3: SuspendCheck\n"
+    "  4: Goto 1\n"
     "BasicBlock 1, pred: 0, 1, succ: 1\n"
-    "  0: Goto 1\n"
+    "  0: SuspendCheck\n"
+    "  1: Goto 1\n"
     "BasicBlock 2\n"
-    "  1: Exit\n";
+    "  2: Exit\n";
 
   const uint16_t data1[] = ZERO_REGISTER_CODE_ITEM(
     Instruction::NOP,
@@ -153,13 +160,15 @@
 TEST(PrettyPrinterTest, CFG5) {
   const char* expected =
     "BasicBlock 0, succ: 1\n"
-    "  3: Goto 1\n"
+    "  4: SuspendCheck\n"
+    "  5: Goto 1\n"
     "BasicBlock 1, pred: 0, 2, succ: 3\n"
     "  0: ReturnVoid\n"
     "BasicBlock 2, succ: 1\n"
-    "  1: Goto 1\n"
+    "  1: SuspendCheck\n"
+    "  2: Goto 1\n"
     "BasicBlock 3, pred: 1\n"
-    "  2: Exit\n";
+    "  3: Exit\n";
 
   const uint16_t data[] = ZERO_REGISTER_CODE_ITEM(
     Instruction::RETURN_VOID,
@@ -174,7 +183,8 @@
     "BasicBlock 0, succ: 1\n"
     "  0: Local [4, 3, 2]\n"
     "  1: IntConstant [2]\n"
-    "  10: Goto 1\n"
+    "  10: SuspendCheck\n"
+    "  11: Goto 1\n"
     "BasicBlock 1, pred: 0, succ: 3, 2\n"
     "  2: StoreLocal(0, 1)\n"
     "  3: LoadLocal(0) [5]\n"
@@ -202,7 +212,8 @@
     "BasicBlock 0, succ: 1\n"
     "  0: Local [4, 3, 2]\n"
     "  1: IntConstant [2]\n"
-    "  10: Goto 1\n"
+    "  11: SuspendCheck\n"
+    "  12: Goto 1\n"
     "BasicBlock 1, pred: 0, succ: 3, 2\n"
     "  2: StoreLocal(0, 1)\n"
     "  3: LoadLocal(0) [5]\n"
@@ -212,9 +223,10 @@
     "BasicBlock 2, pred: 1, 3, succ: 3\n"
     "  7: Goto 3\n"
     "BasicBlock 3, pred: 1, 2, succ: 2\n"
-    "  8: Goto 2\n"
+    "  8: SuspendCheck\n"
+    "  9: Goto 2\n"
     "BasicBlock 4\n"
-    "  9: Exit\n";
+    "  10: Exit\n";
 
   const uint16_t data[] = ONE_REGISTER_CODE_ITEM(
     Instruction::CONST_4 | 0 | 0,
@@ -230,7 +242,8 @@
     "BasicBlock 0, succ: 1\n"
     "  0: Local [2]\n"
     "  1: IntConstant [2]\n"
-    "  5: Goto 1\n"
+    "  5: SuspendCheck\n"
+    "  6: Goto 1\n"
     "BasicBlock 1, pred: 0, succ: 2\n"
     "  2: StoreLocal(0, 1)\n"
     "  3: ReturnVoid\n"
diff --git a/compiler/optimizing/register_allocator.cc b/compiler/optimizing/register_allocator.cc
index b451ef4..7862611 100644
--- a/compiler/optimizing/register_allocator.cc
+++ b/compiler/optimizing/register_allocator.cc
@@ -440,7 +440,8 @@
     DCHECK(inactive->HasRegister());
     size_t next_intersection = inactive->FirstIntersectionWith(current);
     if (next_intersection != kNoLifetime) {
-      free_until[inactive->GetRegister()] = next_intersection;
+      free_until[inactive->GetRegister()] =
+          std::min(free_until[inactive->GetRegister()], next_intersection);
     }
   }
 
diff --git a/compiler/optimizing/register_allocator.h b/compiler/optimizing/register_allocator.h
index f737491..7d397e3 100644
--- a/compiler/optimizing/register_allocator.h
+++ b/compiler/optimizing/register_allocator.h
@@ -21,6 +21,8 @@
 #include "primitive.h"
 #include "utils/growable_array.h"
 
+#include "gtest/gtest.h"
+
 namespace art {
 
 class CodeGenerator;
@@ -177,6 +179,8 @@
   // Slots reserved for out arguments.
   size_t reserved_out_slots_;
 
+  FRIEND_TEST(RegisterAllocatorTest, FreeUntil);
+
   DISALLOW_COPY_AND_ASSIGN(RegisterAllocator);
 };
 
diff --git a/compiler/optimizing/register_allocator_test.cc b/compiler/optimizing/register_allocator_test.cc
index dcae46b..3e3b6b1 100644
--- a/compiler/optimizing/register_allocator_test.cc
+++ b/compiler/optimizing/register_allocator_test.cc
@@ -392,4 +392,59 @@
   ASSERT_TRUE(register_allocator.Validate(false));
 }
 
+/**
+ * Test that the TryAllocateFreeReg method works in the presence of inactive intervals
+ * that share the same register. It should split the interval it is currently
+ * allocating for at the minimum lifetime position between the two inactive intervals.
+ */
+TEST(RegisterAllocatorTest, FreeUntil) {
+  const uint16_t data[] = TWO_REGISTERS_CODE_ITEM(
+    Instruction::CONST_4 | 0 | 0,
+    Instruction::RETURN);
+
+  ArenaPool pool;
+  ArenaAllocator allocator(&pool);
+  HGraph* graph = BuildSSAGraph(data, &allocator);
+  SsaDeadPhiElimination(graph).Run();
+  x86::CodeGeneratorX86 codegen(graph);
+  SsaLivenessAnalysis liveness(*graph, &codegen);
+  liveness.Analyze();
+  RegisterAllocator register_allocator(&allocator, &codegen, liveness);
+
+  // Add an artifical range to cover the temps that will be put in the unhandled list.
+  LiveInterval* unhandled = graph->GetEntryBlock()->GetFirstInstruction()->GetLiveInterval();
+  unhandled->AddLoopRange(0, 60);
+
+  // Add three temps holding the same register, and starting at different positions.
+  // Put the one that should be picked in the middle of the inactive list to ensure
+  // we do not depend on an order.
+  LiveInterval* interval = LiveInterval::MakeTempInterval(&allocator, nullptr, Primitive::kPrimInt);
+  interval->SetRegister(0);
+  interval->AddRange(40, 50);
+  register_allocator.inactive_.Add(interval);
+
+  interval = LiveInterval::MakeTempInterval(&allocator, nullptr, Primitive::kPrimInt);
+  interval->SetRegister(0);
+  interval->AddRange(20, 30);
+  register_allocator.inactive_.Add(interval);
+
+  interval = LiveInterval::MakeTempInterval(&allocator, nullptr, Primitive::kPrimInt);
+  interval->SetRegister(0);
+  interval->AddRange(60, 70);
+  register_allocator.inactive_.Add(interval);
+
+  register_allocator.number_of_registers_ = 1;
+  register_allocator.registers_array_ = allocator.AllocArray<size_t>(1);
+  register_allocator.processing_core_registers_ = true;
+  register_allocator.unhandled_ = &register_allocator.unhandled_core_intervals_;
+
+  register_allocator.TryAllocateFreeReg(unhandled);
+
+  // Check that we have split the interval.
+  ASSERT_EQ(1u, register_allocator.unhandled_->Size());
+  // Check that we know need to find a new register where the next interval
+  // that uses the register starts.
+  ASSERT_EQ(20u, register_allocator.unhandled_->Get(0)->GetStart());
+}
+
 }  // namespace art
diff --git a/compiler/optimizing/ssa_test.cc b/compiler/optimizing/ssa_test.cc
index 088a5c4..99fd9eb 100644
--- a/compiler/optimizing/ssa_test.cc
+++ b/compiler/optimizing/ssa_test.cc
@@ -83,6 +83,9 @@
   HGraph* graph = builder.BuildGraph(*item);
   ASSERT_NE(graph, nullptr);
 
+  // Suspend checks implementation may change in the future, and this test relies
+  // on how instructions are ordered.
+  RemoveSuspendChecks(graph);
   graph->BuildDominatorTree();
   graph->TransformToSSA();
   ReNumberInstructions(graph);
diff --git a/compiler/optimizing/suspend_check_test.cc b/compiler/optimizing/suspend_check_test.cc
new file mode 100644
index 0000000..2e48ee8
--- /dev/null
+++ b/compiler/optimizing/suspend_check_test.cc
@@ -0,0 +1,95 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "builder.h"
+#include "dex_instruction.h"
+#include "nodes.h"
+#include "optimizing_unit_test.h"
+
+#include "gtest/gtest.h"
+
+namespace art {
+
+/**
+ * Check that the HGraphBuilder adds suspend checks to backward branches.
+ */
+
+static void TestCode(const uint16_t* data) {
+  ArenaPool pool;
+  ArenaAllocator allocator(&pool);
+  HGraphBuilder builder(&allocator);
+  const DexFile::CodeItem* item = reinterpret_cast<const DexFile::CodeItem*>(data);
+  HGraph* graph = builder.BuildGraph(*item);
+  ASSERT_NE(graph, nullptr);
+
+  HBasicBlock* first_block = graph->GetEntryBlock()->GetSuccessors().Get(0);
+  HInstruction* first_instruction = first_block->GetFirstInstruction();
+  // Account for some tests having a store local as first instruction.
+  ASSERT_TRUE(first_instruction->IsSuspendCheck()
+              || first_instruction->GetNext()->IsSuspendCheck());
+}
+
+TEST(CodegenTest, CFG1) {
+  const uint16_t data[] = ZERO_REGISTER_CODE_ITEM(
+    Instruction::NOP,
+    Instruction::GOTO | 0xFF00);
+
+  TestCode(data);
+}
+
+TEST(CodegenTest, CFG2) {
+  const uint16_t data[] = ZERO_REGISTER_CODE_ITEM(
+    Instruction::GOTO_32, 0, 0);
+
+  TestCode(data);
+}
+
+TEST(CodegenTest, CFG3) {
+  const uint16_t data[] = ONE_REGISTER_CODE_ITEM(
+    Instruction::CONST_4 | 0 | 0,
+    Instruction::IF_EQ, 0xFFFF,
+    Instruction::RETURN_VOID);
+
+  TestCode(data);
+}
+
+TEST(CodegenTest, CFG4) {
+  const uint16_t data[] = ONE_REGISTER_CODE_ITEM(
+    Instruction::CONST_4 | 0 | 0,
+    Instruction::IF_NE, 0xFFFF,
+    Instruction::RETURN_VOID);
+
+  TestCode(data);
+}
+
+TEST(CodegenTest, CFG5) {
+  const uint16_t data[] = ONE_REGISTER_CODE_ITEM(
+    Instruction::CONST_4 | 0 | 0,
+    Instruction::IF_EQZ, 0xFFFF,
+    Instruction::RETURN_VOID);
+
+  TestCode(data);
+}
+
+TEST(CodegenTest, CFG6) {
+  const uint16_t data[] = ONE_REGISTER_CODE_ITEM(
+    Instruction::CONST_4 | 0 | 0,
+    Instruction::IF_NEZ, 0xFFFF,
+    Instruction::RETURN_VOID);
+
+  TestCode(data);
+}
+}  // namespace art
diff --git a/dex2oat/dex2oat.cc b/dex2oat/dex2oat.cc
index 0e7da55..be6f097 100644
--- a/dex2oat/dex2oat.cc
+++ b/dex2oat/dex2oat.cc
@@ -1029,6 +1029,7 @@
       include_debug_symbols = true;
     } else if (option == "--no-include-debug-symbols" || option == "--strip-symbols") {
       include_debug_symbols = false;
+      generate_gdb_information = false;  // Depends on debug symbols, see above.
     } else if (option.starts_with("--profile-file=")) {
       profile_file = option.substr(strlen("--profile-file=")).data();
       VLOG(compiler) << "dex2oat: profile file is " << profile_file;
diff --git a/disassembler/disassembler.cc b/disassembler/disassembler.cc
index 41ee213..c97bf64 100644
--- a/disassembler/disassembler.cc
+++ b/disassembler/disassembler.cc
@@ -19,6 +19,7 @@
 #include <iostream>
 
 #include "base/logging.h"
+#include "base/stringprintf.h"
 #include "disassembler_arm.h"
 #include "disassembler_arm64.h"
 #include "disassembler_mips.h"
@@ -26,21 +27,30 @@
 
 namespace art {
 
-Disassembler* Disassembler::Create(InstructionSet instruction_set) {
+Disassembler* Disassembler::Create(InstructionSet instruction_set, DisassemblerOptions* options) {
   if (instruction_set == kArm || instruction_set == kThumb2) {
-    return new arm::DisassemblerArm();
+    return new arm::DisassemblerArm(options);
   } else if (instruction_set == kArm64) {
-    return new arm64::DisassemblerArm64();
+    return new arm64::DisassemblerArm64(options);
   } else if (instruction_set == kMips) {
-    return new mips::DisassemblerMips();
+    return new mips::DisassemblerMips(options);
   } else if (instruction_set == kX86) {
-    return new x86::DisassemblerX86(false);
+    return new x86::DisassemblerX86(options, false);
   } else if (instruction_set == kX86_64) {
-    return new x86::DisassemblerX86(true);
+    return new x86::DisassemblerX86(options, true);
   } else {
     UNIMPLEMENTED(FATAL) << "no disassembler for " << instruction_set;
     return NULL;
   }
 }
 
+std::string Disassembler::FormatInstructionPointer(const uint8_t* begin) {
+  if (disassembler_options_->absolute_addresses_) {
+    return StringPrintf("%p", begin);
+  } else {
+    size_t offset = begin - disassembler_options_->base_address_;
+    return StringPrintf("0x%08zx", offset);
+  }
+}
+
 }  // namespace art
diff --git a/disassembler/disassembler.h b/disassembler/disassembler.h
index 183e692..487f433 100644
--- a/disassembler/disassembler.h
+++ b/disassembler/disassembler.h
@@ -26,10 +26,31 @@
 
 namespace art {
 
+class DisassemblerOptions {
+ public:
+  // Should the disassembler print absolute or relative addresses.
+  const bool absolute_addresses_;
+
+  // Base addess for calculating relative code offsets when absolute_addresses_ is false.
+  const uint8_t* const base_address_;
+
+  DisassemblerOptions(bool absolute_addresses, const uint8_t* base_address)
+      : absolute_addresses_(absolute_addresses), base_address_(base_address) {}
+
+ private:
+  DISALLOW_COPY_AND_ASSIGN(DisassemblerOptions);
+};
+
 class Disassembler {
  public:
-  static Disassembler* Create(InstructionSet instruction_set);
-  virtual ~Disassembler() {}
+  // Creates a Disassembler for the given InstructionSet with the
+  // non-null DisassemblerOptions which become owned by the
+  // Disassembler.
+  static Disassembler* Create(InstructionSet instruction_set, DisassemblerOptions* options);
+
+  virtual ~Disassembler() {
+    delete disassembler_options_;
+  }
 
   // Dump a single instruction returning the length of that instruction.
   virtual size_t Dump(std::ostream& os, const uint8_t* begin) = 0;
@@ -37,9 +58,15 @@
   virtual void Dump(std::ostream& os, const uint8_t* begin, const uint8_t* end) = 0;
 
  protected:
-  Disassembler() {}
+  explicit Disassembler(DisassemblerOptions* disassembler_options)
+      : disassembler_options_(disassembler_options) {
+    CHECK(disassembler_options_ != nullptr);
+  }
+
+  std::string FormatInstructionPointer(const uint8_t* begin);
 
  private:
+  DisassemblerOptions* disassembler_options_;
   DISALLOW_COPY_AND_ASSIGN(Disassembler);
 };
 
diff --git a/disassembler/disassembler_arm.cc b/disassembler/disassembler_arm.cc
index 56023c1..54e7761 100644
--- a/disassembler/disassembler_arm.cc
+++ b/disassembler/disassembler_arm.cc
@@ -94,7 +94,7 @@
 }
 
 void DisassemblerArm::DumpBranchTarget(std::ostream& os, const uint8_t* instr_ptr, int32_t imm32) {
-  os << StringPrintf("%+d (%p)", imm32, instr_ptr + imm32);
+  os << StringPrintf("%+d (", imm32) << FormatInstructionPointer(instr_ptr + imm32) << ")";
 }
 
 static uint32_t ReadU16(const uint8_t* ptr) {
@@ -356,7 +356,9 @@
     opcode += kConditionCodeNames[cond];
     opcode += suffixes;
     // TODO: a more complete ARM disassembler could generate wider opcodes.
-    os << StringPrintf("%p: %08x\t%-7s ", instr_ptr, instruction, opcode.c_str()) << args.str() << '\n';
+    os << FormatInstructionPointer(instr_ptr)
+       << StringPrintf(": %08x\t%-7s ", instruction, opcode.c_str())
+       << args.str() << '\n';
 }
 
 int32_t ThumbExpand(int32_t imm12) {
@@ -1608,7 +1610,9 @@
     opcode << "UNKNOWN " << op2;
   }
 
-  os << StringPrintf("%p: %08x\t%-7s ", instr_ptr, instr, opcode.str().c_str()) << args.str() << '\n';
+  os << FormatInstructionPointer(instr_ptr)
+     << StringPrintf(": %08x\t%-7s ", instr, opcode.str().c_str())
+     << args.str() << '\n';
   return 4;
 }  // NOLINT(readability/fn_size)
 
@@ -1936,7 +1940,9 @@
       it_conditions_.pop_back();
     }
 
-    os << StringPrintf("%p: %04x    \t%-7s ", instr_ptr, instr, opcode.str().c_str()) << args.str() << '\n';
+    os << FormatInstructionPointer(instr_ptr)
+       << StringPrintf(": %04x    \t%-7s ", instr, opcode.str().c_str())
+       << args.str() << '\n';
   }
   return 2;
 }
diff --git a/disassembler/disassembler_arm.h b/disassembler/disassembler_arm.h
index f6d7fda..f870e8e 100644
--- a/disassembler/disassembler_arm.h
+++ b/disassembler/disassembler_arm.h
@@ -26,8 +26,7 @@
 
 class DisassemblerArm FINAL : public Disassembler {
  public:
-  DisassemblerArm() {
-  }
+  explicit DisassemblerArm(DisassemblerOptions* options) : Disassembler(options) {}
 
   size_t Dump(std::ostream& os, const uint8_t* begin) OVERRIDE;
   void Dump(std::ostream& os, const uint8_t* begin, const uint8_t* end) OVERRIDE;
diff --git a/disassembler/disassembler_arm64.cc b/disassembler/disassembler_arm64.cc
index 864d22d..5d0c218 100644
--- a/disassembler/disassembler_arm64.cc
+++ b/disassembler/disassembler_arm64.cc
@@ -34,7 +34,8 @@
 size_t DisassemblerArm64::Dump(std::ostream& os, const uint8_t* begin) {
   uint32_t instruction = ReadU32(begin);
   decoder.Decode(reinterpret_cast<vixl::Instruction*>(&instruction));
-  os << StringPrintf("%p: %08x\t%s\n", begin, instruction, disasm.GetOutput());
+  os << FormatInstructionPointer(begin)
+     << StringPrintf(": %08x\t%s\n", instruction, disasm.GetOutput());
   return vixl::kInstructionSize;
 }
 
diff --git a/disassembler/disassembler_arm64.h b/disassembler/disassembler_arm64.h
index 28c0fa7..ad20c70 100644
--- a/disassembler/disassembler_arm64.h
+++ b/disassembler/disassembler_arm64.h
@@ -27,7 +27,7 @@
 
 class DisassemblerArm64 FINAL : public Disassembler {
  public:
-  DisassemblerArm64() {
+  explicit DisassemblerArm64(DisassemblerOptions* options) : Disassembler(options) {
     decoder.AppendVisitor(&disasm);
   }
 
diff --git a/disassembler/disassembler_mips.cc b/disassembler/disassembler_mips.cc
index 5e89f6f..bd5fac7 100644
--- a/disassembler/disassembler_mips.cc
+++ b/disassembler/disassembler_mips.cc
@@ -168,7 +168,7 @@
   return ptr[0] | (ptr[1] << 8) | (ptr[2] << 16) | (ptr[3] << 24);
 }
 
-static void DumpMips(std::ostream& os, const uint8_t* instr_ptr) {
+size_t DisassemblerMips::Dump(std::ostream& os, const uint8_t* instr_ptr) {
   uint32_t instruction = ReadU32(instr_ptr);
 
   uint32_t rs = (instruction >> 21) & 0x1f;  // I-type, R-type.
@@ -197,7 +197,8 @@
               int32_t offset = static_cast<int16_t>(instruction & 0xffff);
               offset <<= 2;
               offset += 4;  // Delay slot.
-              args << StringPrintf("%p  ; %+d", instr_ptr + offset, offset);
+              args << FormatInstructionPointer(instr_ptr + offset)
+                   << StringPrintf("  ; %+d", offset);
             }
             break;
           case 'D': args << 'r' << rd; break;
@@ -254,17 +255,15 @@
     }
   }
 
-  os << StringPrintf("%p: %08x\t%-7s ", instr_ptr, instruction, opcode.c_str()) << args.str() << '\n';
-}
-
-size_t DisassemblerMips::Dump(std::ostream& os, const uint8_t* begin) {
-  DumpMips(os, begin);
+  os << FormatInstructionPointer(instr_ptr)
+     << StringPrintf(": %08x\t%-7s ", instruction, opcode.c_str())
+     << args.str() << '\n';
   return 4;
 }
 
 void DisassemblerMips::Dump(std::ostream& os, const uint8_t* begin, const uint8_t* end) {
   for (const uint8_t* cur = begin; cur < end; cur += 4) {
-    DumpMips(os, cur);
+    Dump(os, cur);
   }
 }
 
diff --git a/disassembler/disassembler_mips.h b/disassembler/disassembler_mips.h
index e1fb034..00b2f8d 100644
--- a/disassembler/disassembler_mips.h
+++ b/disassembler/disassembler_mips.h
@@ -26,8 +26,7 @@
 
 class DisassemblerMips FINAL : public Disassembler {
  public:
-  DisassemblerMips() {
-  }
+  explicit DisassemblerMips(DisassemblerOptions* options) : Disassembler(options) {}
 
   size_t Dump(std::ostream& os, const uint8_t* begin) OVERRIDE;
   void Dump(std::ostream& os, const uint8_t* begin, const uint8_t* end) OVERRIDE;
diff --git a/disassembler/disassembler_x86.cc b/disassembler/disassembler_x86.cc
index 1848abe..1d29765 100644
--- a/disassembler/disassembler_x86.cc
+++ b/disassembler/disassembler_x86.cc
@@ -1215,7 +1215,9 @@
       displacement = *reinterpret_cast<const int32_t*>(instr);
       instr += 4;
     }
-    args << StringPrintf("%+d (%p)", displacement, instr + displacement);
+    args << StringPrintf("%+d (", displacement)
+         << FormatInstructionPointer(instr + displacement)
+         << ")";
   }
   if (prefix[1] == kFs && !supports_rex_) {
     args << "  ; ";
@@ -1238,8 +1240,8 @@
     default: LOG(FATAL) << "Unreachable";
   }
   prefixed_opcode << opcode.str();
-  os << StringPrintf("%p: %22s    \t%-7s ", begin_instr, hex.str().c_str(),
-                     prefixed_opcode.str().c_str())
+  os << FormatInstructionPointer(begin_instr)
+     << StringPrintf(": %22s    \t%-7s ", hex.str().c_str(), prefixed_opcode.str().c_str())
      << args.str() << '\n';
   return instr - begin_instr;
 }  // NOLINT(readability/fn_size)
diff --git a/disassembler/disassembler_x86.h b/disassembler/disassembler_x86.h
index 2565bb1..f448662 100644
--- a/disassembler/disassembler_x86.h
+++ b/disassembler/disassembler_x86.h
@@ -24,8 +24,8 @@
 
 class DisassemblerX86 FINAL : public Disassembler {
  public:
-  explicit DisassemblerX86(bool supports_rex) : supports_rex_(supports_rex) {
-  }
+  DisassemblerX86(DisassemblerOptions* options, bool supports_rex)
+      : Disassembler(options), supports_rex_(supports_rex) {}
 
   size_t Dump(std::ostream& os, const uint8_t* begin) OVERRIDE;
   void Dump(std::ostream& os, const uint8_t* begin, const uint8_t* end) OVERRIDE;
diff --git a/oatdump/oatdump.cc b/oatdump/oatdump.cc
index 6ca0bcd..bac3c33 100644
--- a/oatdump/oatdump.cc
+++ b/oatdump/oatdump.cc
@@ -79,8 +79,8 @@
           "      Example: --boot-image=/system/framework/boot.art\n"
           "\n");
   fprintf(stderr,
-          "  --instruction-set=(arm|arm64|mips|x86|x86_64): for locating the image file based on the image location\n"
-          "      set.\n"
+          "  --instruction-set=(arm|arm64|mips|x86|x86_64): for locating the image\n"
+          "      file based on the image location set.\n"
           "      Example: --instruction-set=x86\n"
           "      Default: %s\n"
           "\n",
@@ -90,9 +90,20 @@
           "      Example: --output=/tmp/oatdump.txt\n"
           "\n");
   fprintf(stderr,
-          "  --dump:[raw_mapping_table|raw_gc_map]\n"
-          "    Example: --dump:raw_gc_map\n"
-          "    Default: neither\n"
+          "  --dump:raw_mapping_table enables dumping of the mapping table.\n"
+          "      Example: --dump:raw_mapping_table\n"
+          "\n");
+  fprintf(stderr,
+          "  --dump:raw_mapping_table enables dumping of the GC map.\n"
+          "      Example: --dump:raw_gc_map\n"
+          "\n");
+  fprintf(stderr,
+          "  --no-dump:vmap may be used to disable vmap dumping.\n"
+          "      Example: --no-dump:vmap\n"
+          "\n");
+  fprintf(stderr,
+          "  --no-disassemble may be used to disable disassembly.\n"
+          "      Example: --no-disassemble\n"
           "\n");
   exit(EXIT_FAILURE);
 }
@@ -220,14 +231,14 @@
     while (it.HasNextDirectMethod()) {
       const OatFile::OatMethod oat_method = oat_class.GetOatMethod(class_method_idx);
       WalkOatMethod(class_def, class_method_idx, oat_method, dex_file, it.GetMemberIndex(),
-                    it.GetMethodCodeItem(), it.GetMemberAccessFlags(), callback);
+                    it.GetMethodCodeItem(), it.GetMethodAccessFlags(), callback);
       class_method_idx++;
       it.Next();
     }
     while (it.HasNextVirtualMethod()) {
       const OatFile::OatMethod oat_method = oat_class.GetOatMethod(class_method_idx);
       WalkOatMethod(class_def, class_method_idx, oat_method, dex_file, it.GetMemberIndex(),
-                    it.GetMethodCodeItem(), it.GetMemberAccessFlags(), callback);
+                    it.GetMethodCodeItem(), it.GetMethodAccessFlags(), callback);
       class_method_idx++;
       it.Next();
     }
@@ -326,18 +337,45 @@
   std::string output_name_;
 };
 
+class OatDumperOptions {
+ public:
+  OatDumperOptions(bool dump_raw_mapping_table,
+                   bool dump_raw_gc_map,
+                   bool dump_vmap,
+                   bool disassemble_code,
+                   bool absolute_addresses)
+    : dump_raw_mapping_table_(dump_raw_mapping_table),
+      dump_raw_gc_map_(dump_raw_gc_map),
+      dump_vmap_(dump_vmap),
+      disassemble_code_(disassemble_code),
+      absolute_addresses_(absolute_addresses) {}
+
+  const bool dump_raw_mapping_table_;
+  const bool dump_raw_gc_map_;
+  const bool dump_vmap_;
+  const bool disassemble_code_;
+  const bool absolute_addresses_;
+};
+
 class OatDumper {
  public:
-  explicit OatDumper(const OatFile& oat_file, bool dump_raw_mapping_table, bool dump_raw_gc_map)
+  explicit OatDumper(const OatFile& oat_file, OatDumperOptions* options)
     : oat_file_(oat_file),
       oat_dex_files_(oat_file.GetOatDexFiles()),
-      dump_raw_mapping_table_(dump_raw_mapping_table),
-      dump_raw_gc_map_(dump_raw_gc_map),
-      disassembler_(Disassembler::Create(oat_file_.GetOatHeader().GetInstructionSet())) {
+      options_(options),
+      disassembler_(Disassembler::Create(oat_file_.GetOatHeader().GetInstructionSet(),
+                                         new DisassemblerOptions(options_->absolute_addresses_,
+                                                                 oat_file.Begin()))) {
     AddAllOffsets();
   }
 
-  void Dump(std::ostream& os) {
+  ~OatDumper() {
+    delete options_;
+    delete disassembler_;
+  }
+
+  bool Dump(std::ostream& os) {
+    bool success = true;
     const OatHeader& oat_header = oat_file_.GetOatHeader();
 
     os << "MAGIC:\n";
@@ -358,7 +396,7 @@
 #define DUMP_OAT_HEADER_OFFSET(label, offset) \
     os << label " OFFSET:\n"; \
     os << StringPrintf("0x%08x", oat_header.offset()); \
-    if (oat_header.offset() != 0) { \
+    if (oat_header.offset() != 0 && options_->absolute_addresses_) { \
       os << StringPrintf(" (%p)", oat_file_.Begin() + oat_header.offset()); \
     } \
     os << StringPrintf("\n\n");
@@ -386,7 +424,10 @@
                            GetQuickToInterpreterBridgeOffset);
 #undef DUMP_OAT_HEADER_OFFSET
 
-    os << "IMAGE PATCH DELTA:\n" << oat_header.GetImagePatchDelta() << "\n\n";
+    os << "IMAGE PATCH DELTA:\n";
+    os << StringPrintf("%d (0x%08x)\n\n",
+                       oat_header.GetImagePatchDelta(),
+                       oat_header.GetImagePatchDelta());
 
     os << "IMAGE FILE LOCATION OAT CHECKSUM:\n";
     os << StringPrintf("0x%08x\n\n", oat_header.GetImageFileLocationOatChecksum());
@@ -407,19 +448,28 @@
       os << "\n";
     }
 
-    os << "BEGIN:\n";
-    os << reinterpret_cast<const void*>(oat_file_.Begin()) << "\n\n";
+    if (options_->absolute_addresses_) {
+      os << "BEGIN:\n";
+      os << reinterpret_cast<const void*>(oat_file_.Begin()) << "\n\n";
 
-    os << "END:\n";
-    os << reinterpret_cast<const void*>(oat_file_.End()) << "\n\n";
+      os << "END:\n";
+      os << reinterpret_cast<const void*>(oat_file_.End()) << "\n\n";
+    }
+
+    os << "SIZE:\n";
+    os << oat_file_.Size() << "\n\n";
 
     os << std::flush;
 
     for (size_t i = 0; i < oat_dex_files_.size(); i++) {
       const OatFile::OatDexFile* oat_dex_file = oat_dex_files_[i];
-      CHECK(oat_dex_file != NULL);
-      DumpOatDexFile(os, *oat_dex_file);
+      CHECK(oat_dex_file != nullptr);
+      if (!DumpOatDexFile(os, *oat_dex_file)) {
+        success = false;
+      }
     }
+    os << std::flush;
+    return success;
   }
 
   size_t ComputeSize(const void* oat_data) {
@@ -451,7 +501,7 @@
       } else {
         const DexFile::ClassDef* class_def =
             dex_file->FindClassDef(m->GetDeclaringClassDescriptor());
-        if (class_def != NULL) {
+        if (class_def != nullptr) {
           uint16_t class_def_index = dex_file->GetIndexForClassDef(*class_def);
           const OatFile::OatClass oat_class = oat_dex_file->GetOatClass(class_def_index);
           size_t method_index = m->GetMethodIndex();
@@ -459,7 +509,7 @@
         }
       }
     }
-    return NULL;
+    return nullptr;
   }
 
  private:
@@ -470,7 +520,7 @@
     // of a piece of code by using upper_bound to find the start of the next region.
     for (size_t i = 0; i < oat_dex_files_.size(); i++) {
       const OatFile::OatDexFile* oat_dex_file = oat_dex_files_[i];
-      CHECK(oat_dex_file != NULL);
+      CHECK(oat_dex_file != nullptr);
       std::string error_msg;
       std::unique_ptr<const DexFile> dex_file(oat_dex_file->OpenDexFile(&error_msg));
       if (dex_file.get() == nullptr) {
@@ -485,7 +535,7 @@
         const DexFile::ClassDef& class_def = dex_file->GetClassDef(class_def_index);
         const OatFile::OatClass oat_class = oat_dex_file->GetOatClass(class_def_index);
         const byte* class_data = dex_file->GetClassData(class_def);
-        if (class_data != NULL) {
+        if (class_data != nullptr) {
           ClassDataItemIterator it(*dex_file, class_data);
           SkipAllFields(it);
           uint32_t class_method_index = 0;
@@ -507,6 +557,10 @@
     offsets_.insert(oat_file_.Size());
   }
 
+  static uint32_t AlignCodeOffset(uint32_t maybe_thumb_offset) {
+    return maybe_thumb_offset & ~0x1;  // TODO: Make this Thumb2 specific.
+  }
+
   void AddOffsets(const OatFile::OatMethod& oat_method) {
     uint32_t code_offset = oat_method.GetCodeOffset();
     if (oat_file_.GetOatHeader().GetInstructionSet() == kThumb2) {
@@ -518,8 +572,9 @@
     offsets_.insert(oat_method.GetNativeGcMapOffset());
   }
 
-  void DumpOatDexFile(std::ostream& os, const OatFile::OatDexFile& oat_dex_file) {
-    os << "OAT DEX FILE:\n";
+  bool DumpOatDexFile(std::ostream& os, const OatFile::OatDexFile& oat_dex_file) {
+    bool success = true;
+    os << "OatDexFile:\n";
     os << StringPrintf("location: %s\n", oat_dex_file.GetDexFileLocation().c_str());
     os << StringPrintf("checksum: 0x%08x\n", oat_dex_file.GetDexFileLocationChecksum());
 
@@ -527,26 +582,32 @@
 
     std::string error_msg;
     std::unique_ptr<const DexFile> dex_file(oat_dex_file.OpenDexFile(&error_msg));
-    if (dex_file.get() == NULL) {
+    if (dex_file.get() == nullptr) {
       os << "NOT FOUND: " << error_msg << "\n\n";
-      return;
+      os << std::flush;
+      return false;
     }
     for (size_t class_def_index = 0;
          class_def_index < dex_file->NumClassDefs();
          class_def_index++) {
       const DexFile::ClassDef& class_def = dex_file->GetClassDef(class_def_index);
       const char* descriptor = dex_file->GetClassDescriptor(class_def);
+      uint32_t oat_class_offset = oat_dex_file.GetOatClassOffset(class_def_index);
       const OatFile::OatClass oat_class = oat_dex_file.GetOatClass(class_def_index);
-      os << StringPrintf("%zd: %s (type_idx=%d)", class_def_index, descriptor, class_def.class_idx_)
+      os << StringPrintf("%zd: %s (offset=0x%08x) (type_idx=%d)",
+                         class_def_index, descriptor, oat_class_offset, class_def.class_idx_)
          << " (" << oat_class.GetStatus() << ")"
          << " (" << oat_class.GetType() << ")\n";
       // TODO: include bitmap here if type is kOatClassSomeCompiled?
       Indenter indent_filter(os.rdbuf(), kIndentChar, kIndentBy1Count);
       std::ostream indented_os(&indent_filter);
-      DumpOatClass(indented_os, oat_class, *(dex_file.get()), class_def);
+      if (!DumpOatClass(indented_os, oat_class, *(dex_file.get()), class_def)) {
+        success = false;
+      }
     }
 
     os << std::flush;
+    return success;
   }
 
   static void SkipAllFields(ClassDataItemIterator& it) {
@@ -558,38 +619,51 @@
     }
   }
 
-  void DumpOatClass(std::ostream& os, const OatFile::OatClass& oat_class, const DexFile& dex_file,
+  bool DumpOatClass(std::ostream& os, const OatFile::OatClass& oat_class, const DexFile& dex_file,
                     const DexFile::ClassDef& class_def) {
+    bool success = true;
     const byte* class_data = dex_file.GetClassData(class_def);
-    if (class_data == NULL) {  // empty class such as a marker interface?
-      return;
+    if (class_data == nullptr) {  // empty class such as a marker interface?
+      os << std::flush;
+      return success;
     }
     ClassDataItemIterator it(dex_file, class_data);
     SkipAllFields(it);
-    uint32_t class_method_idx = 0;
+    uint32_t class_method_index = 0;
     while (it.HasNextDirectMethod()) {
-      const OatFile::OatMethod oat_method = oat_class.GetOatMethod(class_method_idx);
-      DumpOatMethod(os, class_def, class_method_idx, oat_method, dex_file,
-                    it.GetMemberIndex(), it.GetMethodCodeItem(), it.GetMemberAccessFlags());
-      class_method_idx++;
+      if (!DumpOatMethod(os, class_def, class_method_index, oat_class, dex_file,
+                         it.GetMemberIndex(), it.GetMethodCodeItem(),
+                         it.GetRawMemberAccessFlags())) {
+        success = false;
+      }
+      class_method_index++;
       it.Next();
     }
     while (it.HasNextVirtualMethod()) {
-      const OatFile::OatMethod oat_method = oat_class.GetOatMethod(class_method_idx);
-      DumpOatMethod(os, class_def, class_method_idx, oat_method, dex_file,
-                    it.GetMemberIndex(), it.GetMethodCodeItem(), it.GetMemberAccessFlags());
-      class_method_idx++;
+      if (!DumpOatMethod(os, class_def, class_method_index, oat_class, dex_file,
+                         it.GetMemberIndex(), it.GetMethodCodeItem(),
+                         it.GetRawMemberAccessFlags())) {
+        success = false;
+      }
+      class_method_index++;
       it.Next();
     }
     DCHECK(!it.HasNext());
     os << std::flush;
+    return success;
   }
 
-  void DumpOatMethod(std::ostream& os, const DexFile::ClassDef& class_def,
+  static constexpr uint32_t kPrologueBytes = 16;
+
+  // When this was picked, the largest arm method was 55,256 bytes and arm64 was 50,412 bytes.
+  static constexpr uint32_t kMaxCodeSize = 100 * 1000;
+
+  bool DumpOatMethod(std::ostream& os, const DexFile::ClassDef& class_def,
                      uint32_t class_method_index,
-                     const OatFile::OatMethod& oat_method, const DexFile& dex_file,
+                     const OatFile::OatClass& oat_class, const DexFile& dex_file,
                      uint32_t dex_method_idx, const DexFile::CodeItem* code_item,
                      uint32_t method_access_flags) {
+    bool success = true;
     os << StringPrintf("%d: %s (dex_method_idx=%d)\n",
                        class_method_index, PrettyMethod(dex_method_idx, dex_file, true).c_str(),
                        dex_method_idx);
@@ -601,72 +675,199 @@
       *indent1_os << "DEX CODE:\n";
       DumpDexCode(*indent2_os, dex_file, code_item);
     }
-    if (Runtime::Current() != NULL) {
+
+    std::unique_ptr<verifier::MethodVerifier> verifier;
+    if (Runtime::Current() != nullptr) {
       *indent1_os << "VERIFIER TYPE ANALYSIS:\n";
-      DumpVerifier(*indent2_os, dex_method_idx, &dex_file, class_def, code_item,
-                   method_access_flags);
+      verifier.reset(DumpVerifier(*indent2_os, dex_method_idx, &dex_file, class_def, code_item,
+                                  method_access_flags));
     }
+
+    uint32_t oat_method_offsets_offset = oat_class.GetOatMethodOffsetsOffset(class_method_index);
+    const OatMethodOffsets* oat_method_offsets = oat_class.GetOatMethodOffsets(class_method_index);
+    const OatFile::OatMethod oat_method = oat_class.GetOatMethod(class_method_index);
     {
-      *indent1_os << "OAT DATA:\n";
-
-      *indent2_os << StringPrintf("frame_size_in_bytes: %zd\n", oat_method.GetFrameSizeInBytes());
-      *indent2_os << StringPrintf("core_spill_mask: 0x%08x ", oat_method.GetCoreSpillMask());
-      DumpSpillMask(*indent2_os, oat_method.GetCoreSpillMask(), false);
-      *indent2_os << StringPrintf("\nfp_spill_mask: 0x%08x ", oat_method.GetFpSpillMask());
-      DumpSpillMask(*indent2_os, oat_method.GetFpSpillMask(), true);
-      *indent2_os << StringPrintf("\nvmap_table: %p (offset=0x%08x)\n",
-                                  oat_method.GetVmapTable(), oat_method.GetVmapTableOffset());
-
-      if (oat_method.GetNativeGcMap() != nullptr) {
-        // The native GC map is null for methods compiled with the optimizing compiler.
-        DumpVmap(*indent2_os, oat_method);
+      *indent1_os << "OatMethodOffsets ";
+      if (options_->absolute_addresses_) {
+        *indent1_os << StringPrintf("%p ", oat_method_offsets);
       }
-      DumpVregLocations(*indent2_os, oat_method, code_item);
-      *indent2_os << StringPrintf("mapping_table: %p (offset=0x%08x)\n",
-                                  oat_method.GetMappingTable(), oat_method.GetMappingTableOffset());
-      if (dump_raw_mapping_table_) {
-        Indenter indent3_filter(indent2_os->rdbuf(), kIndentChar, kIndentBy1Count);
-        std::ostream indent3_os(&indent3_filter);
-        DumpMappingTable(indent3_os, oat_method);
+      *indent1_os << StringPrintf("(offset=0x%08x)\n", oat_method_offsets_offset);
+      if (oat_method_offsets_offset > oat_file_.Size()) {
+        *indent1_os << StringPrintf(
+            "WARNING: oat method offsets offset 0x%08x is past end of file 0x%08zx.\n",
+            oat_method_offsets_offset, oat_file_.Size());
+        // If we can't read OatMethodOffsets, the rest of the data is dangerous to read.
+        os << std::flush;
+        return false;
       }
-      *indent2_os << StringPrintf("gc_map: %p (offset=0x%08x)\n",
-                                  oat_method.GetNativeGcMap(), oat_method.GetNativeGcMapOffset());
-      if (dump_raw_gc_map_) {
+
+      uint32_t code_offset = oat_method.GetCodeOffset();
+      *indent2_os << StringPrintf("code_offset: 0x%08x ", code_offset);
+      uint32_t aligned_code_begin = AlignCodeOffset(oat_method.GetCodeOffset());
+      if (aligned_code_begin > oat_file_.Size()) {
+        *indent2_os << StringPrintf("WARNING: "
+                                    "code offset 0x%08x is past end of file 0x%08zx.\n",
+                                    aligned_code_begin, oat_file_.Size());
+        success = false;
+      }
+      *indent2_os << "\n";
+
+      *indent2_os << "gc_map: ";
+      if (options_->absolute_addresses_) {
+        *indent2_os << StringPrintf("%p ", oat_method.GetNativeGcMap());
+      }
+      uint32_t gc_map_offset = oat_method.GetNativeGcMapOffset();
+      *indent2_os << StringPrintf("(offset=0x%08x)\n", gc_map_offset);
+      if (gc_map_offset > oat_file_.Size()) {
+        *indent2_os << StringPrintf("WARNING: "
+                                    "gc map table offset 0x%08x is past end of file 0x%08zx.\n",
+                                    gc_map_offset, oat_file_.Size());
+        success = false;
+      } else if (options_->dump_raw_gc_map_) {
         Indenter indent3_filter(indent2_os->rdbuf(), kIndentChar, kIndentBy1Count);
         std::ostream indent3_os(&indent3_filter);
         DumpGcMap(indent3_os, oat_method, code_item);
       }
     }
     {
-      const void* code = oat_method.GetQuickCode();
-      uint32_t code_size = oat_method.GetQuickCodeSize();
-      if (code == nullptr) {
-        code = oat_method.GetPortableCode();
-        code_size = oat_method.GetPortableCodeSize();
-      }
-      *indent1_os << StringPrintf("CODE: %p (offset=0x%08x size=%d)%s\n",
-                                 code,
-                                 oat_method.GetCodeOffset(),
-                                 code_size,
-                                 code != nullptr ? "..." : "");
+      *indent1_os << "OatQuickMethodHeader ";
+      uint32_t method_header_offset = oat_method.GetOatQuickMethodHeaderOffset();
+      const OatQuickMethodHeader* method_header = oat_method.GetOatQuickMethodHeader();
 
-      Runtime* runtime = Runtime::Current();
-      if (runtime != nullptr) {
-        ScopedObjectAccess soa(Thread::Current());
-        StackHandleScope<1> hs(soa.Self());
-        Handle<mirror::DexCache> dex_cache(
-            hs.NewHandle(runtime->GetClassLinker()->FindDexCache(dex_file)));
-        verifier::MethodVerifier verifier(soa.Self(), &dex_file, dex_cache,
-                                          NullHandle<mirror::ClassLoader>(),
-                                          &class_def, code_item, dex_method_idx,
-                                          NullHandle<mirror::ArtMethod>(), method_access_flags,
-                                          true, true, true);
-        verifier.Verify();
-        DumpCode(*indent2_os, &verifier, oat_method, code_item);
-      } else {
-        DumpCode(*indent2_os, nullptr, oat_method, code_item);
+      if (options_->absolute_addresses_) {
+        *indent1_os << StringPrintf("%p ", method_header);
+      }
+      *indent1_os << StringPrintf("(offset=0x%08x)\n", method_header_offset);
+      if (method_header_offset > oat_file_.Size()) {
+        *indent1_os << StringPrintf(
+            "WARNING: oat quick method header offset 0x%08x is past end of file 0x%08zx.\n",
+            method_header_offset, oat_file_.Size());
+        // If we can't read the OatQuickMethodHeader, the rest of the data is dangerous to read.
+        os << std::flush;
+        return false;
+      }
+
+      *indent2_os << "mapping_table: ";
+      if (options_->absolute_addresses_) {
+        *indent2_os << StringPrintf("%p ", oat_method.GetMappingTable());
+      }
+      uint32_t mapping_table_offset = oat_method.GetMappingTableOffset();
+      *indent2_os << StringPrintf("(offset=0x%08x)\n", oat_method.GetMappingTableOffset());
+      if (mapping_table_offset > oat_file_.Size()) {
+        *indent2_os << StringPrintf("WARNING: "
+                                    "mapping table offset 0x%08x is past end of file 0x%08zx. "
+                                    "mapping table offset was loaded from offset 0x%08x.\n",
+                                    mapping_table_offset, oat_file_.Size(),
+                                    oat_method.GetMappingTableOffsetOffset());
+        success = false;
+      } else if (options_->dump_raw_mapping_table_) {
+        Indenter indent3_filter(indent2_os->rdbuf(), kIndentChar, kIndentBy1Count);
+        std::ostream indent3_os(&indent3_filter);
+        DumpMappingTable(indent3_os, oat_method);
+      }
+
+      *indent2_os << "vmap_table: ";
+      if (options_->absolute_addresses_) {
+        *indent2_os << StringPrintf("%p ", oat_method.GetVmapTable());
+      }
+      uint32_t vmap_table_offset = oat_method.GetVmapTableOffset();
+      *indent2_os << StringPrintf("(offset=0x%08x)\n", vmap_table_offset);
+      if (vmap_table_offset > oat_file_.Size()) {
+        *indent2_os << StringPrintf("WARNING: "
+                                    "vmap table offset 0x%08x is past end of file 0x%08zx. "
+                                    "vmap table offset was loaded from offset 0x%08x.\n",
+                                    vmap_table_offset, oat_file_.Size(),
+                                    oat_method.GetVmapTableOffsetOffset());
+        success = false;
+      } else if (options_->dump_vmap_) {
+        if (oat_method.GetNativeGcMap() != nullptr) {
+          // The native GC map is null for methods compiled with the optimizing compiler.
+          DumpVmap(*indent2_os, oat_method);
+        }
       }
     }
+    {
+      *indent1_os << "QuickMethodFrameInfo\n";
+
+      *indent2_os << StringPrintf("frame_size_in_bytes: %zd\n", oat_method.GetFrameSizeInBytes());
+      *indent2_os << StringPrintf("core_spill_mask: 0x%08x ", oat_method.GetCoreSpillMask());
+      DumpSpillMask(*indent2_os, oat_method.GetCoreSpillMask(), false);
+      *indent2_os << "\n";
+      *indent2_os << StringPrintf("fp_spill_mask: 0x%08x ", oat_method.GetFpSpillMask());
+      DumpSpillMask(*indent2_os, oat_method.GetFpSpillMask(), true);
+      *indent2_os << "\n";
+    }
+    {
+        // Based on spill masks from QuickMethodFrameInfo so placed
+        // after it is dumped, but useful for understanding quick
+        // code, so dumped here.
+        DumpVregLocations(*indent2_os, oat_method, code_item);
+    }
+    {
+      *indent1_os << "CODE: ";
+      uint32_t code_size_offset = oat_method.GetQuickCodeSizeOffset();
+      if (code_size_offset > oat_file_.Size()) {
+        *indent2_os << StringPrintf("WARNING: "
+                                    "code size offset 0x%08x is past end of file 0x%08zx.",
+                                    code_size_offset, oat_file_.Size());
+        success = false;
+      } else {
+        const void* code = oat_method.GetQuickCode();
+        uint32_t code_size = oat_method.GetQuickCodeSize();
+        if (code == nullptr) {
+          code = oat_method.GetPortableCode();
+          code_size = oat_method.GetPortableCodeSize();
+          code_size_offset = 0;
+        }
+        uint32_t code_offset = oat_method.GetCodeOffset();
+        uint32_t aligned_code_begin = AlignCodeOffset(code_offset);
+        uint64_t aligned_code_end = aligned_code_begin + code_size;
+
+        if (options_->absolute_addresses_) {
+          *indent1_os << StringPrintf("%p ", code);
+        }
+        *indent1_os << StringPrintf("(code_offset=0x%08x size_offset=0x%08x size=%u)%s\n",
+                                    code_offset,
+                                    code_size_offset,
+                                    code_size,
+                                    code != nullptr ? "..." : "");
+
+        if (aligned_code_begin > oat_file_.Size()) {
+          *indent2_os << StringPrintf("WARNING: "
+                                      "start of code at 0x%08x is past end of file 0x%08zx.",
+                                      aligned_code_begin, oat_file_.Size());
+          success = false;
+        } else if (aligned_code_end > oat_file_.Size()) {
+          *indent2_os << StringPrintf("WARNING: "
+                                      "end of code at 0x%08" PRIx64 " is past end of file 0x%08zx. "
+                                      "code size is 0x%08x loaded from offset 0x%08x.\n",
+                                      aligned_code_end, oat_file_.Size(),
+                                      code_size, code_size_offset);
+          success = false;
+          if (options_->disassemble_code_) {
+            if (code_size_offset + kPrologueBytes <= oat_file_.Size()) {
+              DumpCode(*indent2_os, verifier.get(), oat_method, code_item, true, kPrologueBytes);
+            }
+          }
+        } else if (code_size > kMaxCodeSize) {
+          *indent2_os << StringPrintf("WARNING: "
+                                      "code size %d is bigger than max expected threshold of %d. "
+                                      "code size is 0x%08x loaded from offset 0x%08x.\n",
+                                      code_size, kMaxCodeSize,
+                                      code_size, code_size_offset);
+          success = false;
+          if (options_->disassemble_code_) {
+            if (code_size_offset + kPrologueBytes <= oat_file_.Size()) {
+              DumpCode(*indent2_os, verifier.get(), oat_method, code_item, true, kPrologueBytes);
+            }
+          }
+        } else if (options_->disassemble_code_) {
+          DumpCode(*indent2_os, verifier.get(), oat_method, code_item, !success, 0);
+        }
+      }
+    }
+    os << std::flush;
+    return success;
   }
 
   void DumpSpillMask(std::ostream& os, uint32_t spill_mask, bool is_float) {
@@ -694,7 +895,7 @@
 
   void DumpVmap(std::ostream& os, const OatFile::OatMethod& oat_method) {
     const uint8_t* raw_table = oat_method.GetVmapTable();
-    if (raw_table != NULL) {
+    if (raw_table != nullptr) {
       const VmapTable vmap_table(raw_table);
       bool first = true;
       bool processing_fp = false;
@@ -761,7 +962,7 @@
   void DescribeVReg(std::ostream& os, const OatFile::OatMethod& oat_method,
                     const DexFile::CodeItem* code_item, size_t reg, VRegKind kind) {
     const uint8_t* raw_table = oat_method.GetVmapTable();
-    if (raw_table != NULL) {
+    if (raw_table != nullptr) {
       const VmapTable vmap_table(raw_table);
       uint32_t vmap_offset;
       if (vmap_table.IsInContext(reg, kind, &vmap_offset)) {
@@ -884,7 +1085,7 @@
   void DumpGcMapAtNativePcOffset(std::ostream& os, const OatFile::OatMethod& oat_method,
                                  const DexFile::CodeItem* code_item, size_t native_pc_offset) {
     const uint8_t* gc_map_raw = oat_method.GetNativeGcMap();
-    if (gc_map_raw != NULL) {
+    if (gc_map_raw != nullptr) {
       NativePcOffsetToReferenceMap map(gc_map_raw);
       if (map.HasEntry(native_pc_offset)) {
         size_t num_regs = map.RegWidth() * 8;
@@ -949,7 +1150,7 @@
 
 
   void DumpDexCode(std::ostream& os, const DexFile& dex_file, const DexFile::CodeItem* code_item) {
-    if (code_item != NULL) {
+    if (code_item != nullptr) {
       size_t i = 0;
       while (i < code_item->insns_size_in_code_units_) {
         const Instruction* instruction = Instruction::At(&code_item->insns_[i]);
@@ -959,28 +1160,36 @@
     }
   }
 
-  void DumpVerifier(std::ostream& os, uint32_t dex_method_idx, const DexFile* dex_file,
-                    const DexFile::ClassDef& class_def, const DexFile::CodeItem* code_item,
-                    uint32_t method_access_flags) {
+  verifier::MethodVerifier* DumpVerifier(std::ostream& os, uint32_t dex_method_idx,
+                                         const DexFile* dex_file,
+                                         const DexFile::ClassDef& class_def,
+                                         const DexFile::CodeItem* code_item,
+                                         uint32_t method_access_flags) {
     if ((method_access_flags & kAccNative) == 0) {
       ScopedObjectAccess soa(Thread::Current());
       StackHandleScope<1> hs(soa.Self());
       Handle<mirror::DexCache> dex_cache(
           hs.NewHandle(Runtime::Current()->GetClassLinker()->FindDexCache(*dex_file)));
-      verifier::MethodVerifier::VerifyMethodAndDump(soa.Self(), os, dex_method_idx, dex_file,
-                                                    dex_cache, NullHandle<mirror::ClassLoader>(),
-                                                    &class_def, code_item,
-                                                    NullHandle<mirror::ArtMethod>(),
-                                                    method_access_flags);
+      return verifier::MethodVerifier::VerifyMethodAndDump(soa.Self(), os, dex_method_idx, dex_file,
+                                                           dex_cache,
+                                                           NullHandle<mirror::ClassLoader>(),
+                                                           &class_def, code_item,
+                                                           NullHandle<mirror::ArtMethod>(),
+                                                           method_access_flags);
     }
+
+    return nullptr;
   }
 
   void DumpCode(std::ostream& os, verifier::MethodVerifier* verifier,
-                const OatFile::OatMethod& oat_method, const DexFile::CodeItem* code_item) {
+                const OatFile::OatMethod& oat_method, const DexFile::CodeItem* code_item,
+                bool bad_input, size_t code_size) {
     const void* portable_code = oat_method.GetPortableCode();
     const void* quick_code = oat_method.GetQuickCode();
 
-    size_t code_size = oat_method.GetQuickCodeSize();
+    if (code_size == 0) {
+      code_size = oat_method.GetQuickCodeSize();
+    }
     if ((code_size == 0) || ((portable_code == nullptr) && (quick_code == nullptr))) {
       os << "NO CODE!\n";
       return;
@@ -988,13 +1197,17 @@
       const uint8_t* quick_native_pc = reinterpret_cast<const uint8_t*>(quick_code);
       size_t offset = 0;
       while (offset < code_size) {
-        DumpMappingAtOffset(os, oat_method, offset, false);
+        if (!bad_input) {
+          DumpMappingAtOffset(os, oat_method, offset, false);
+        }
         offset += disassembler_->Dump(os, quick_native_pc + offset);
-        uint32_t dex_pc = DumpMappingAtOffset(os, oat_method, offset, true);
-        if (dex_pc != DexFile::kDexNoIndex) {
-          DumpGcMapAtNativePcOffset(os, oat_method, code_item, offset);
-          if (verifier != nullptr) {
-            DumpVRegsAtDexPc(os, verifier, oat_method, code_item, dex_pc);
+        if (!bad_input) {
+          uint32_t dex_pc = DumpMappingAtOffset(os, oat_method, offset, true);
+          if (dex_pc != DexFile::kDexNoIndex) {
+            DumpGcMapAtNativePcOffset(os, oat_method, code_item, offset);
+            if (verifier != nullptr) {
+              DumpVRegsAtDexPc(os, verifier, oat_method, code_item, dex_pc);
+            }
           }
         }
       }
@@ -1005,23 +1218,22 @@
   }
 
   const OatFile& oat_file_;
-  std::vector<const OatFile::OatDexFile*> oat_dex_files_;
-  bool dump_raw_mapping_table_;
-  bool dump_raw_gc_map_;
+  const std::vector<const OatFile::OatDexFile*> oat_dex_files_;
+  const OatDumperOptions* options_;
   std::set<uintptr_t> offsets_;
-  std::unique_ptr<Disassembler> disassembler_;
+  Disassembler* disassembler_;
 };
 
 class ImageDumper {
  public:
   explicit ImageDumper(std::ostream* os, gc::space::ImageSpace& image_space,
-                       const ImageHeader& image_header, bool dump_raw_mapping_table,
-                       bool dump_raw_gc_map)
-      : os_(os), image_space_(image_space), image_header_(image_header),
-        dump_raw_mapping_table_(dump_raw_mapping_table),
-        dump_raw_gc_map_(dump_raw_gc_map) {}
+                       const ImageHeader& image_header, OatDumperOptions* oat_dumper_options)
+      : os_(os),
+        image_space_(image_space),
+        image_header_(image_header),
+        oat_dumper_options_(oat_dumper_options) {}
 
-  void Dump() SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
+  bool Dump() SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
     std::ostream& os = *os_;
     os << "MAGIC: " << image_header_.GetMagic() << "\n\n";
 
@@ -1073,7 +1285,7 @@
               indent2_os << StringPrintf("%d to %zd: ", i, i + run);
               i = i + run;
             }
-            if (value != NULL) {
+            if (value != nullptr) {
               PrettyObjectValue(indent2_os, value->GetClass(), value);
             } else {
               indent2_os << i << ": null\n";
@@ -1092,21 +1304,20 @@
     std::string error_msg;
     const OatFile* oat_file = class_linker->FindOpenedOatFileFromOatLocation(oat_location);
     if (oat_file == nullptr) {
-      oat_file = OatFile::Open(oat_location, oat_location, NULL, false, &error_msg);
+      oat_file = OatFile::Open(oat_location, oat_location, nullptr, false, &error_msg);
       if (oat_file == nullptr) {
         os << "NOT FOUND: " << error_msg << "\n";
-        return;
+        return false;
       }
     }
     os << "\n";
 
     stats_.oat_file_bytes = oat_file->Size();
 
-    oat_dumper_.reset(new OatDumper(*oat_file, dump_raw_mapping_table_,
-        dump_raw_gc_map_));
+    oat_dumper_.reset(new OatDumper(*oat_file, oat_dumper_options_.release()));
 
     for (const OatFile::OatDexFile* oat_dex_file : oat_file->GetOatDexFiles()) {
-      CHECK(oat_dex_file != NULL);
+      CHECK(oat_dex_file != nullptr);
       stats_.oat_dex_file_sizes.push_back(std::make_pair(oat_dex_file->GetDexFileLocation(),
                                                          oat_dex_file->FileSize()));
     }
@@ -1154,10 +1365,10 @@
     }
     os << "STATS:\n" << std::flush;
     std::unique_ptr<File> file(OS::OpenFileForReading(image_filename.c_str()));
-    if (file.get() == NULL) {
+    if (file.get() == nullptr) {
       LOG(WARNING) << "Failed to find image in " << image_filename;
     }
-    if (file.get() != NULL) {
+    if (file.get() != nullptr) {
       stats_.file_bytes = file->GetLength();
     }
     size_t header_bytes = sizeof(ImageHeader);
@@ -1171,14 +1382,14 @@
 
     os << std::flush;
 
-    oat_dumper_->Dump(os);
+    return oat_dumper_->Dump(os);
   }
 
  private:
   static void PrettyObjectValue(std::ostream& os, mirror::Class* type, mirror::Object* value)
       SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
-    CHECK(type != NULL);
-    if (value == NULL) {
+    CHECK(type != nullptr);
+    if (value == nullptr) {
       os << StringPrintf("null   %s\n", PrettyDescriptor(type).c_str());
     } else if (type->IsStringClass()) {
       mirror::String* string = value->AsString();
@@ -1231,14 +1442,14 @@
       // Get the value, don't compute the type unless it is non-null as we don't want
       // to cause class loading.
       mirror::Object* value = field->GetObj(obj);
-      if (value == NULL) {
+      if (value == nullptr) {
         os << StringPrintf("null   %s\n", PrettyDescriptor(descriptor).c_str());
       } else {
         // Grab the field type without causing resolution.
         StackHandleScope<1> hs(Thread::Current());
         FieldHelper fh(hs.NewHandle(field));
         mirror::Class* field_type = fh.GetType(false);
-        if (field_type != NULL) {
+        if (field_type != nullptr) {
           PrettyObjectValue(os, field_type, value);
         } else {
           os << StringPrintf("%p   %s\n", value, PrettyDescriptor(descriptor).c_str());
@@ -1250,11 +1461,11 @@
   static void DumpFields(std::ostream& os, mirror::Object* obj, mirror::Class* klass)
       SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
     mirror::Class* super = klass->GetSuperClass();
-    if (super != NULL) {
+    if (super != nullptr) {
       DumpFields(os, obj, super);
     }
     mirror::ObjectArray<mirror::ArtField>* fields = klass->GetIFields();
-    if (fields != NULL) {
+    if (fields != nullptr) {
       for (int32_t i = 0; i < fields->GetLength(); i++) {
         mirror::ArtField* field = fields->Get(i);
         PrintField(os, field, obj);
@@ -1290,16 +1501,16 @@
   const void* GetQuickOatCodeEnd(mirror::ArtMethod* m)
       SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
     const uint8_t* oat_code_begin = reinterpret_cast<const uint8_t*>(GetQuickOatCodeBegin(m));
-    if (oat_code_begin == NULL) {
-      return NULL;
+    if (oat_code_begin == nullptr) {
+      return nullptr;
     }
     return oat_code_begin + GetQuickOatCodeSize(m);
   }
 
   static void Callback(mirror::Object* obj, void* arg)
       SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
-    DCHECK(obj != NULL);
-    DCHECK(arg != NULL);
+    DCHECK(obj != nullptr);
+    DCHECK(arg != nullptr);
     ImageDumper* state = reinterpret_cast<ImageDumper*>(arg);
     if (!state->InDumpSpace(obj)) {
       return;
@@ -1354,12 +1565,12 @@
           i = i + run;
         }
         mirror::Class* value_class =
-            (value == NULL) ? obj_class->GetComponentType() : value->GetClass();
+            (value == nullptr) ? obj_class->GetComponentType() : value->GetClass();
         PrettyObjectValue(indent_os, value_class, value);
       }
     } else if (obj->IsClass()) {
       mirror::ObjectArray<mirror::ArtField>* sfields = obj->AsClass()->GetSFields();
-      if (sfields != NULL) {
+      if (sfields != nullptr) {
         indent_os << "STATICS:\n";
         Indenter indent2_filter(indent_os.rdbuf(), kIndentChar, kIndentBy1Count);
         std::ostream indent2_os(&indent2_filter);
@@ -1387,8 +1598,8 @@
       } else if (method->IsAbstract() || method->IsCalleeSaveMethod() ||
           method->IsResolutionMethod() || method->IsImtConflictMethod() ||
           method->IsClassInitializer()) {
-        DCHECK(method->GetNativeGcMap() == NULL) << PrettyMethod(method);
-        DCHECK(method->GetMappingTable() == NULL) << PrettyMethod(method);
+        DCHECK(method->GetNativeGcMap() == nullptr) << PrettyMethod(method);
+        DCHECK(method->GetMappingTable() == nullptr) << PrettyMethod(method);
       } else {
         const DexFile::CodeItem* code_item = method->GetCodeItem();
         size_t dex_instruction_bytes = code_item->insns_size_in_code_units_ * 2;
@@ -1735,12 +1946,11 @@
     // threshold, we assume 2 bytes per instruction and 2 instructions per block.
     kLargeMethodDexBytes = 16000
   };
-  std::unique_ptr<OatDumper> oat_dumper_;
   std::ostream* os_;
   gc::space::ImageSpace& image_space_;
   const ImageHeader& image_header_;
-  bool dump_raw_mapping_table_;
-  bool dump_raw_gc_map_;
+  std::unique_ptr<OatDumper> oat_dumper_;
+  std::unique_ptr<OatDumperOptions> oat_dumper_options_;
 
   DISALLOW_COPY_AND_ASSIGN(ImageDumper);
 };
@@ -1757,9 +1967,9 @@
     usage();
   }
 
-  const char* oat_filename = NULL;
-  const char* image_location = NULL;
-  const char* boot_image_location = NULL;
+  const char* oat_filename = nullptr;
+  const char* image_location = nullptr;
+  const char* boot_image_location = nullptr;
   InstructionSet instruction_set = kRuntimeISA;
   std::string elf_filename_prefix;
   std::ostream* os = &std::cout;
@@ -1767,6 +1977,8 @@
   std::string output_name;
   bool dump_raw_mapping_table = false;
   bool dump_raw_gc_map = false;
+  bool dump_vmap = true;
+  bool disassemble_code = true;
   bool symbolize = false;
 
   for (int i = 0; i < argc; i++) {
@@ -1790,15 +2002,14 @@
       } else if (instruction_set_str == "x86_64") {
         instruction_set = kX86_64;
       }
-    } else if (option.starts_with("--dump:")) {
-        if (option == "--dump:raw_mapping_table") {
-          dump_raw_mapping_table = true;
-        } else if (option == "--dump:raw_gc_map") {
-          dump_raw_gc_map = true;
-        } else {
-          fprintf(stderr, "Unknown argument %s\n", option.data());
-          usage();
-        }
+    } else if (option =="--dump:raw_mapping_table") {
+      dump_raw_mapping_table = true;
+    } else if (option == "--dump:raw_gc_map") {
+      dump_raw_gc_map = true;
+    } else if (option == "--no-dump:vmap") {
+      dump_vmap = false;
+    } else if (option == "--no-disassemble") {
+      disassemble_code = false;
     } else if (option.starts_with("--output=")) {
       output_name = option.substr(strlen("--output=")).ToString();
       const char* filename = output_name.c_str();
@@ -1817,21 +2028,28 @@
     }
   }
 
-  if (image_location == NULL && oat_filename == NULL) {
+  if (image_location == nullptr && oat_filename == nullptr) {
     fprintf(stderr, "Either --image or --oat must be specified\n");
     return EXIT_FAILURE;
   }
 
-  if (image_location != NULL && oat_filename != NULL) {
+  if (image_location != nullptr && oat_filename != nullptr) {
     fprintf(stderr, "Either --image or --oat must be specified but not both\n");
     return EXIT_FAILURE;
   }
 
-  if (oat_filename != NULL) {
+  // If we are only doing the oat file, disable absolute_addresses. Keep them for image dumping.
+  bool absolute_addresses = (oat_filename == nullptr);
+  std::unique_ptr<OatDumperOptions> oat_dumper_options(new OatDumperOptions(dump_raw_mapping_table,
+                                                                            dump_raw_gc_map,
+                                                                            dump_vmap,
+                                                                            disassemble_code,
+                                                                            absolute_addresses));
+  if (oat_filename != nullptr) {
     std::string error_msg;
     OatFile* oat_file =
-        OatFile::Open(oat_filename, oat_filename, NULL, false, &error_msg);
-    if (oat_file == NULL) {
+        OatFile::Open(oat_filename, oat_filename, nullptr, false, &error_msg);
+    if (oat_file == nullptr) {
       fprintf(stderr, "Failed to open oat file from '%s': %s\n", oat_filename, error_msg.c_str());
       return EXIT_FAILURE;
     }
@@ -1846,8 +2064,9 @@
         return EXIT_FAILURE;
       }
     } else {
-      OatDumper oat_dumper(*oat_file, dump_raw_mapping_table, dump_raw_gc_map);
-      oat_dumper.Dump(*os);
+      OatDumper oat_dumper(*oat_file, oat_dumper_options.release());
+      bool success = oat_dumper.Dump(*os);
+      return (success) ? EXIT_SUCCESS : EXIT_FAILURE;
     }
     return EXIT_SUCCESS;
   }
@@ -1862,15 +2081,15 @@
   NoopCompilerCallbacks callbacks;
   options.push_back(std::make_pair("compilercallbacks", &callbacks));
 
-  if (boot_image_location != NULL) {
+  if (boot_image_location != nullptr) {
     boot_image_option += "-Ximage:";
     boot_image_option += boot_image_location;
-    options.push_back(std::make_pair(boot_image_option.c_str(), reinterpret_cast<void*>(NULL)));
+    options.push_back(std::make_pair(boot_image_option.c_str(), nullptr));
   }
-  if (image_location != NULL) {
+  if (image_location != nullptr) {
     image_option += "-Ximage:";
     image_option += image_location;
-    options.push_back(std::make_pair(image_option.c_str(), reinterpret_cast<void*>(NULL)));
+    options.push_back(std::make_pair(image_option.c_str(), nullptr));
   }
   options.push_back(
       std::make_pair("imageinstructionset",
@@ -1887,16 +2106,15 @@
   ScopedObjectAccess soa(Thread::Current());
   gc::Heap* heap = Runtime::Current()->GetHeap();
   gc::space::ImageSpace* image_space = heap->GetImageSpace();
-  CHECK(image_space != NULL);
+  CHECK(image_space != nullptr);
   const ImageHeader& image_header = image_space->GetImageHeader();
   if (!image_header.IsValid()) {
     fprintf(stderr, "Invalid image header %s\n", image_location);
     return EXIT_FAILURE;
   }
-  ImageDumper image_dumper(os, *image_space, image_header,
-                           dump_raw_mapping_table, dump_raw_gc_map);
-  image_dumper.Dump();
-  return EXIT_SUCCESS;
+  ImageDumper image_dumper(os, *image_space, image_header, oat_dumper_options.release());
+  bool success = image_dumper.Dump();
+  return (success) ? EXIT_SUCCESS : EXIT_FAILURE;
 }
 
 }  // namespace art
diff --git a/patchoat/patchoat.cc b/patchoat/patchoat.cc
index bbdf3a3..f89a4f7 100644
--- a/patchoat/patchoat.cc
+++ b/patchoat/patchoat.cc
@@ -522,14 +522,15 @@
   t.NewTiming("Fixup Elf Headers");
   // Fixup Phdr's
   for (unsigned int i = 0; i < oat_file_->GetProgramHeaderNum(); i++) {
-    Elf32_Phdr& hdr = oat_file_->GetProgramHeader(i);
-    if (hdr.p_vaddr != 0 && hdr.p_vaddr != hdr.p_offset) {
+    Elf32_Phdr* hdr = oat_file_->GetProgramHeader(i);
+    CHECK(hdr != nullptr);
+    if (hdr->p_vaddr != 0 && hdr->p_vaddr != hdr->p_offset) {
       need_fixup = true;
-      hdr.p_vaddr += delta_;
+      hdr->p_vaddr += delta_;
     }
-    if (hdr.p_paddr != 0 && hdr.p_paddr != hdr.p_offset) {
+    if (hdr->p_paddr != 0 && hdr->p_paddr != hdr->p_offset) {
       need_fixup = true;
-      hdr.p_paddr += delta_;
+      hdr->p_paddr += delta_;
     }
   }
   if (!need_fixup) {
@@ -539,9 +540,10 @@
   }
   t.NewTiming("Fixup Section Headers");
   for (unsigned int i = 0; i < oat_file_->GetSectionHeaderNum(); i++) {
-    Elf32_Shdr& hdr = oat_file_->GetSectionHeader(i);
-    if (hdr.sh_addr != 0) {
-      hdr.sh_addr += delta_;
+    Elf32_Shdr* hdr = oat_file_->GetSectionHeader(i);
+    CHECK(hdr != nullptr);
+    if (hdr->sh_addr != 0) {
+      hdr->sh_addr += delta_;
     }
   }
 
diff --git a/runtime/Android.mk b/runtime/Android.mk
index 5065c58..61bc9ff 100644
--- a/runtime/Android.mk
+++ b/runtime/Android.mk
@@ -120,6 +120,7 @@
   native/java_lang_Thread.cc \
   native/java_lang_Throwable.cc \
   native/java_lang_VMClassLoader.cc \
+  native/java_lang_ref_FinalizerReference.cc \
   native/java_lang_ref_Reference.cc \
   native/java_lang_reflect_Array.cc \
   native/java_lang_reflect_Constructor.cc \
diff --git a/runtime/base/mutex.cc b/runtime/base/mutex.cc
index 52a3dea..455680b 100644
--- a/runtime/base/mutex.cc
+++ b/runtime/base/mutex.cc
@@ -37,19 +37,25 @@
 ReaderWriterMutex* Locks::classlinker_classes_lock_ = nullptr;
 Mutex* Locks::deoptimization_lock_ = nullptr;
 ReaderWriterMutex* Locks::heap_bitmap_lock_ = nullptr;
+Mutex* Locks::intern_table_lock_ = nullptr;
 Mutex* Locks::jni_libraries_lock_ = nullptr;
 Mutex* Locks::logging_lock_ = nullptr;
 Mutex* Locks::mem_maps_lock_ = nullptr;
 Mutex* Locks::modify_ldt_lock_ = nullptr;
 ReaderWriterMutex* Locks::mutator_lock_ = nullptr;
 Mutex* Locks::profiler_lock_ = nullptr;
+Mutex* Locks::reference_processor_lock_ = nullptr;
+Mutex* Locks::reference_queue_cleared_references_lock_ = nullptr;
+Mutex* Locks::reference_queue_finalizer_references_lock_ = nullptr;
+Mutex* Locks::reference_queue_phantom_references_lock_ = nullptr;
+Mutex* Locks::reference_queue_soft_references_lock_ = nullptr;
+Mutex* Locks::reference_queue_weak_references_lock_ = nullptr;
 Mutex* Locks::runtime_shutdown_lock_ = nullptr;
 Mutex* Locks::thread_list_lock_ = nullptr;
 Mutex* Locks::thread_list_suspend_thread_lock_ = nullptr;
 Mutex* Locks::thread_suspend_count_lock_ = nullptr;
 Mutex* Locks::trace_lock_ = nullptr;
 Mutex* Locks::unexpected_signal_lock_ = nullptr;
-Mutex* Locks::intern_table_lock_ = nullptr;
 
 struct AllMutexData {
   // A guard for all_mutexes_ that's not a mutex (Mutexes must CAS to acquire and busy wait).
@@ -933,6 +939,30 @@
     DCHECK(intern_table_lock_ == nullptr);
     intern_table_lock_ = new Mutex("InternTable lock", current_lock_level);
 
+    UPDATE_CURRENT_LOCK_LEVEL(kReferenceProcessorLock);
+    DCHECK(reference_processor_lock_ == nullptr);
+    reference_processor_lock_ = new Mutex("ReferenceProcessor lock", current_lock_level);
+
+    UPDATE_CURRENT_LOCK_LEVEL(kReferenceQueueClearedReferencesLock);
+    DCHECK(reference_queue_cleared_references_lock_ == nullptr);
+    reference_queue_cleared_references_lock_ = new Mutex("ReferenceQueue cleared references lock", current_lock_level);
+
+    UPDATE_CURRENT_LOCK_LEVEL(kReferenceQueueWeakReferencesLock);
+    DCHECK(reference_queue_weak_references_lock_ == nullptr);
+    reference_queue_weak_references_lock_ = new Mutex("ReferenceQueue cleared references lock", current_lock_level);
+
+    UPDATE_CURRENT_LOCK_LEVEL(kReferenceQueueFinalizerReferencesLock);
+    DCHECK(reference_queue_finalizer_references_lock_ == nullptr);
+    reference_queue_finalizer_references_lock_ = new Mutex("ReferenceQueue finalizer references lock", current_lock_level);
+
+    UPDATE_CURRENT_LOCK_LEVEL(kReferenceQueuePhantomReferencesLock);
+    DCHECK(reference_queue_phantom_references_lock_ == nullptr);
+    reference_queue_phantom_references_lock_ = new Mutex("ReferenceQueue phantom references lock", current_lock_level);
+
+    UPDATE_CURRENT_LOCK_LEVEL(kReferenceQueueSoftReferencesLock);
+    DCHECK(reference_queue_soft_references_lock_ == nullptr);
+    reference_queue_soft_references_lock_ = new Mutex("ReferenceQueue soft references lock", current_lock_level);
+
     UPDATE_CURRENT_LOCK_LEVEL(kAbortLock);
     DCHECK(abort_lock_ == nullptr);
     abort_lock_ = new Mutex("abort lock", current_lock_level, true);
diff --git a/runtime/base/mutex.h b/runtime/base/mutex.h
index 354298e..20f58de 100644
--- a/runtime/base/mutex.h
+++ b/runtime/base/mutex.h
@@ -60,11 +60,16 @@
   kThreadSuspendCountLock,
   kAbortLock,
   kJdwpSocketLock,
+  kReferenceQueueSoftReferencesLock,
+  kReferenceQueuePhantomReferencesLock,
+  kReferenceQueueFinalizerReferencesLock,
+  kReferenceQueueWeakReferencesLock,
+  kReferenceQueueClearedReferencesLock,
+  kReferenceProcessorLock,
   kRosAllocGlobalLock,
   kRosAllocBracketLock,
   kRosAllocBulkFreeLock,
   kAllocSpaceLock,
-  kReferenceProcessorLock,
   kDexFileMethodInlinerLock,
   kDexFileToMethodInlinerMapLock,
   kMarkSweepMarkStackLock,
@@ -594,8 +599,26 @@
   // Guards intern table.
   static Mutex* intern_table_lock_ ACQUIRED_AFTER(modify_ldt_lock_);
 
+  // Guards reference processor.
+  static Mutex* reference_processor_lock_ ACQUIRED_AFTER(intern_table_lock_);
+
+  // Guards cleared references queue.
+  static Mutex* reference_queue_cleared_references_lock_ ACQUIRED_AFTER(reference_processor_lock_);
+
+  // Guards weak references queue.
+  static Mutex* reference_queue_weak_references_lock_ ACQUIRED_AFTER(reference_queue_cleared_references_lock_);
+
+  // Guards finalizer references queue.
+  static Mutex* reference_queue_finalizer_references_lock_ ACQUIRED_AFTER(reference_queue_weak_references_lock_);
+
+  // Guards phantom references queue.
+  static Mutex* reference_queue_phantom_references_lock_ ACQUIRED_AFTER(reference_queue_finalizer_references_lock_);
+
+  // Guards soft references queue.
+  static Mutex* reference_queue_soft_references_lock_ ACQUIRED_AFTER(reference_queue_phantom_references_lock_);
+
   // Have an exclusive aborting thread.
-  static Mutex* abort_lock_ ACQUIRED_AFTER(intern_table_lock_);
+  static Mutex* abort_lock_ ACQUIRED_AFTER(reference_queue_soft_references_lock_);
 
   // Allow mutual exclusion when manipulating Thread::suspend_count_.
   // TODO: Does the trade-off of a per-thread lock make sense?
diff --git a/runtime/base/stringprintf_test.cc b/runtime/base/stringprintf_test.cc
new file mode 100644
index 0000000..0bfde33
--- /dev/null
+++ b/runtime/base/stringprintf_test.cc
@@ -0,0 +1,29 @@
+/*
+ * Copyright (C) 2011 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "stringprintf.h"
+
+#include "gtest/gtest.h"
+
+namespace art {
+
+TEST(StringPrintfTest, HexSizeT) {
+  size_t size = 0x00107e59;
+  EXPECT_STREQ("00107e59", StringPrintf("%08zx", size).c_str());
+  EXPECT_STREQ("0x00107e59", StringPrintf("0x%08zx", size).c_str());
+}
+
+}  // namespace art
diff --git a/runtime/check_reference_map_visitor.h b/runtime/check_reference_map_visitor.h
new file mode 100644
index 0000000..1a78d72
--- /dev/null
+++ b/runtime/check_reference_map_visitor.h
@@ -0,0 +1,111 @@
+/*
+ * Copyright (C) 2011 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef ART_RUNTIME_CHECK_REFERENCE_MAP_VISITOR_H_
+#define ART_RUNTIME_CHECK_REFERENCE_MAP_VISITOR_H_
+
+#include "gc_map.h"
+#include "mirror/art_method-inl.h"
+#include "scoped_thread_state_change.h"
+#include "stack_map.h"
+
+namespace art {
+
+// Helper class for tests checking that the compiler keeps track of dex registers
+// holding references.
+class CheckReferenceMapVisitor : public StackVisitor {
+ public:
+  explicit CheckReferenceMapVisitor(Thread* thread) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_)
+      : StackVisitor(thread, nullptr) {}
+
+  bool VisitFrame() SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
+    mirror::ArtMethod* m = GetMethod();
+    if (m->IsCalleeSaveMethod() || m->IsNative()) {
+      CHECK_EQ(GetDexPc(), DexFile::kDexNoIndex);
+    }
+
+    if (!m || m->IsNative() || m->IsRuntimeMethod() || IsShadowFrame()) {
+      return true;
+    }
+
+    LOG(INFO) << "At " << PrettyMethod(m, false);
+
+    if (m->IsCalleeSaveMethod()) {
+      LOG(WARNING) << "no PC for " << PrettyMethod(m);
+      return true;
+    }
+
+    return false;
+  }
+
+  void CheckReferences(int* registers, int number_of_references, uint32_t native_pc_offset)
+      SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
+    if (GetMethod()->IsOptimized()) {
+      CheckOptimizedMethod(registers, number_of_references, native_pc_offset);
+    } else {
+      CheckQuickMethod(registers, number_of_references, native_pc_offset);
+    }
+  }
+
+ private:
+  void CheckOptimizedMethod(int* registers, int number_of_references, uint32_t native_pc_offset)
+      SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
+    mirror::ArtMethod* m = GetMethod();
+    CodeInfo code_info = m->GetOptimizedCodeInfo();
+    StackMap stack_map = code_info.GetStackMapForNativePcOffset(native_pc_offset);
+    DexRegisterMap dex_register_map = code_info.GetDexRegisterMapOf(stack_map, m->GetCodeItem()->registers_size_);
+    MemoryRegion stack_mask = stack_map.GetStackMask();
+    uint32_t register_mask = stack_map.GetRegisterMask();
+    for (int i = 0; i < number_of_references; ++i) {
+      int reg = registers[i];
+      CHECK(reg < m->GetCodeItem()->registers_size_);
+      DexRegisterMap::LocationKind location = dex_register_map.GetLocationKind(reg);
+      switch (location) {
+        case DexRegisterMap::kNone:
+          // Not set, should not be a reference.
+          CHECK(false);
+          break;
+        case DexRegisterMap::kInStack:
+          CHECK(stack_mask.LoadBit(dex_register_map.GetValue(reg) >> 2));
+          break;
+        case DexRegisterMap::kInRegister:
+          CHECK_NE(register_mask & dex_register_map.GetValue(reg), 0u);
+          break;
+        case DexRegisterMap::kConstant:
+          CHECK_EQ(dex_register_map.GetValue(0), 0);
+          break;
+      }
+    }
+  }
+
+  void CheckQuickMethod(int* registers, int number_of_references, uint32_t native_pc_offset)
+      SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
+    mirror::ArtMethod* m = GetMethod();
+    NativePcOffsetToReferenceMap map(m->GetNativeGcMap());
+    const uint8_t* ref_bitmap = map.FindBitMap(native_pc_offset);
+    CHECK(ref_bitmap);
+    for (int i = 0; i < number_of_references; ++i) {
+      int reg = registers[i];
+      CHECK(reg < m->GetCodeItem()->registers_size_);
+      CHECK((*((ref_bitmap) + reg / 8) >> (reg % 8) ) & 0x01)
+          << "Error: Reg @" << i << " is not in GC map";
+    }
+  }
+};
+
+}  // namespace art
+
+#endif  // ART_RUNTIME_CHECK_REFERENCE_MAP_VISITOR_H_
diff --git a/runtime/class_linker.cc b/runtime/class_linker.cc
index 4474f1b..1686c27 100644
--- a/runtime/class_linker.cc
+++ b/runtime/class_linker.cc
@@ -120,7 +120,7 @@
   JNIEnv* env = self->GetJniEnv();
 
   ScopedLocalRef<jthrowable> cause(env, env->ExceptionOccurred());
-  CHECK(cause.get() != NULL);
+  CHECK(cause.get() != nullptr);
 
   env->ExceptionClear();
   bool is_error = env->IsInstanceOf(cause.get(), WellKnownClasses::java_lang_Error);
@@ -129,7 +129,8 @@
   // We only wrap non-Error exceptions; an Error can just be used as-is.
   if (!is_error) {
     ThrowLocation throw_location = self->GetCurrentLocationForThrow();
-    self->ThrowNewWrappedException(throw_location, "Ljava/lang/ExceptionInInitializerError;", NULL);
+    self->ThrowNewWrappedException(throw_location, "Ljava/lang/ExceptionInInitializerError;",
+                                   nullptr);
   }
 }
 
@@ -306,7 +307,7 @@
       heap->AllocNonMovableObject<true>(self, nullptr,
                                         mirror::Class::ClassClassSize(),
                                         VoidFunctor()))));
-  CHECK(java_lang_Class.Get() != NULL);
+  CHECK(java_lang_Class.Get() != nullptr);
   mirror::Class::SetClassClass(java_lang_Class.Get());
   java_lang_Class->SetClass(java_lang_Class.Get());
   if (kUseBakerOrBrooksReadBarrier) {
@@ -324,7 +325,7 @@
   // java_lang_Object comes next so that object_array_class can be created.
   Handle<mirror::Class> java_lang_Object(hs.NewHandle(
       AllocClass(self, java_lang_Class.Get(), mirror::Object::ClassSize())));
-  CHECK(java_lang_Object.Get() != NULL);
+  CHECK(java_lang_Object.Get() != nullptr);
   // backfill Object as the super class of Class.
   java_lang_Class->SetSuperClass(java_lang_Object.Get());
   java_lang_Object->SetStatus(mirror::Class::kStatusLoaded, self);
@@ -405,7 +406,7 @@
   // that FindClass can link members.
   Handle<mirror::Class> java_lang_reflect_ArtField(hs.NewHandle(
       AllocClass(self, java_lang_Class.Get(), mirror::ArtField::ClassSize())));
-  CHECK(java_lang_reflect_ArtField.Get() != NULL);
+  CHECK(java_lang_reflect_ArtField.Get() != nullptr);
   java_lang_reflect_ArtField->SetObjectSize(mirror::ArtField::InstanceSize());
   SetClassRoot(kJavaLangReflectArtField, java_lang_reflect_ArtField.Get());
   java_lang_reflect_ArtField->SetStatus(mirror::Class::kStatusResolved, self);
@@ -413,7 +414,7 @@
 
   Handle<mirror::Class> java_lang_reflect_ArtMethod(hs.NewHandle(
     AllocClass(self, java_lang_Class.Get(), mirror::ArtMethod::ClassSize())));
-  CHECK(java_lang_reflect_ArtMethod.Get() != NULL);
+  CHECK(java_lang_reflect_ArtMethod.Get() != nullptr);
   java_lang_reflect_ArtMethod->SetObjectSize(mirror::ArtMethod::InstanceSize());
   SetClassRoot(kJavaLangReflectArtMethod, java_lang_reflect_ArtMethod.Get());
   java_lang_reflect_ArtMethod->SetStatus(mirror::Class::kStatusResolved, self);
@@ -445,7 +446,7 @@
   CHECK_NE(0U, boot_class_path.size());
   for (size_t i = 0; i != boot_class_path.size(); ++i) {
     const DexFile* dex_file = boot_class_path[i];
-    CHECK(dex_file != NULL);
+    CHECK(dex_file != nullptr);
     AppendToBootClassPath(self, *dex_file);
   }
 
@@ -522,9 +523,9 @@
 
   // Setup the single, global copy of "iftable".
   mirror::Class* java_lang_Cloneable = FindSystemClass(self, "Ljava/lang/Cloneable;");
-  CHECK(java_lang_Cloneable != NULL);
+  CHECK(java_lang_Cloneable != nullptr);
   mirror::Class* java_io_Serializable = FindSystemClass(self, "Ljava/io/Serializable;");
-  CHECK(java_io_Serializable != NULL);
+  CHECK(java_io_Serializable != nullptr);
   // We assume that Cloneable/Serializable don't have superinterfaces -- normally we'd have to
   // crawl up and explicitly list all of the supers as well.
   {
@@ -652,8 +653,8 @@
   for (size_t i = 0; i < kClassRootsMax; i++) {
     ClassRoot class_root = static_cast<ClassRoot>(i);
     mirror::Class* klass = GetClassRoot(class_root);
-    CHECK(klass != NULL);
-    DCHECK(klass->IsArrayClass() || klass->IsPrimitive() || klass->GetDexCache() != NULL);
+    CHECK(klass != nullptr);
+    DCHECK(klass->IsArrayClass() || klass->IsPrimitive() || klass->GetDexCache() != nullptr);
     // note SetClassRoot does additional validation.
     // if possible add new checks there to catch errors early
   }
@@ -1051,7 +1052,7 @@
                                                                uint32_t dex_location_checksum,
                                                                const char* oat_location,
                                                                std::string* error_msg) {
-  std::unique_ptr<OatFile> oat_file(OatFile::Open(oat_location, oat_location, NULL,
+  std::unique_ptr<OatFile> oat_file(OatFile::Open(oat_location, oat_location, nullptr,
                                             !Runtime::Current()->IsCompiler(),
                                             error_msg));
   if (oat_file.get() == nullptr) {
@@ -1123,7 +1124,7 @@
     error_msgs->push_back(error_msg);
     return nullptr;
   }
-  std::unique_ptr<OatFile> oat_file(OatFile::Open(oat_location, oat_location, NULL,
+  std::unique_ptr<OatFile> oat_file(OatFile::Open(oat_location, oat_location, nullptr,
                                             !Runtime::Current()->IsCompiler(),
                                             &error_msg));
   if (oat_file.get() == nullptr) {
@@ -1209,7 +1210,7 @@
 
   const OatFile::OatDexFile* oat_dex_file = oat_file->GetOatDexFile(dex_location,
                                                                     &dex_location_checksum);
-  if (oat_dex_file == NULL) {
+  if (oat_dex_file == nullptr) {
     *error_msg = StringPrintf("oat file '%s' does not contain contents for '%s' with checksum 0x%x",
                               oat_file->GetLocation().c_str(), dex_location, dex_location_checksum);
     for (const OatFile::OatDexFile* oat_dex_file : oat_file->GetOatDexFiles()) {
@@ -1236,7 +1237,7 @@
     // If no classes.dex found in dex_location, it has been stripped or is corrupt, assume oat is
     // up-to-date. This is the common case in user builds for jar's and apk's in the /system
     // directory.
-    const OatFile::OatDexFile* oat_dex_file = oat_file->GetOatDexFile(dex_location, NULL);
+    const OatFile::OatDexFile* oat_dex_file = oat_file->GetOatDexFile(dex_location, nullptr);
     if (oat_dex_file == nullptr) {
       *error_msg = StringPrintf("Dex checksum mismatch for location '%s' and failed to find oat "
                                 "dex file '%s': %s", oat_file->GetLocation().c_str(), dex_location,
@@ -1369,7 +1370,7 @@
   {
     // There is a high probability that these both these oat files map similar/the same address
     // spaces so we must scope them like this so they each gets its turn.
-    std::unique_ptr<OatFile> odex_oat_file(OatFile::Open(odex_filename, odex_filename, NULL,
+    std::unique_ptr<OatFile> odex_oat_file(OatFile::Open(odex_filename, odex_filename, nullptr,
                                                          executable, &odex_error_msg));
     if (odex_oat_file.get() != nullptr && CheckOatFile(odex_oat_file.get(), isa,
                                                        &odex_checksum_verified,
@@ -1391,7 +1392,7 @@
   bool should_patch_cache = false;
   bool cache_checksum_verified = false;
   if (have_dalvik_cache) {
-    std::unique_ptr<OatFile> cache_oat_file(OatFile::Open(cache_filename, cache_filename, NULL,
+    std::unique_ptr<OatFile> cache_oat_file(OatFile::Open(cache_filename, cache_filename, nullptr,
                                                           executable, &cache_error_msg));
     if (cache_oat_file.get() != nullptr && CheckOatFile(cache_oat_file.get(), isa,
                                                         &cache_checksum_verified,
@@ -1468,7 +1469,7 @@
                                                   InstructionSet isa,
                                                   std::string* error_msg) {
   // We open it non-executable
-  std::unique_ptr<OatFile> output(OatFile::Open(oat_path, oat_path, NULL, false, error_msg));
+  std::unique_ptr<OatFile> output(OatFile::Open(oat_path, oat_path, nullptr, false, error_msg));
   if (output.get() == nullptr) {
     return nullptr;
   }
@@ -1523,7 +1524,7 @@
   LOG(INFO) << "Relocate Oat File: " << command_line;
   bool success = Exec(argv, error_msg);
   if (success) {
-    std::unique_ptr<OatFile> output(OatFile::Open(output_oat, output_oat, NULL,
+    std::unique_ptr<OatFile> output(OatFile::Open(output_oat, output_oat, nullptr,
                                                   !Runtime::Current()->IsCompiler(), error_msg));
     bool checksum_verified = false;
     if (output.get() != nullptr && CheckOatFile(output.get(), isa, &checksum_verified, error_msg)) {
@@ -1632,20 +1633,16 @@
     return oat_file;
   }
 
-  oat_file = OatFile::Open(oat_location, oat_location, NULL, !Runtime::Current()->IsCompiler(),
-                           error_msg);
-  if (oat_file == NULL) {
-    return NULL;
-  }
-  return oat_file;
+  return OatFile::Open(oat_location, oat_location, nullptr, !Runtime::Current()->IsCompiler(),
+                       error_msg);
 }
 
 static void InitFromImageInterpretOnlyCallback(mirror::Object* obj, void* arg)
     SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
   ClassLinker* class_linker = reinterpret_cast<ClassLinker*>(arg);
 
-  DCHECK(obj != NULL);
-  DCHECK(class_linker != NULL);
+  DCHECK(obj != nullptr);
+  DCHECK(class_linker != nullptr);
 
   if (obj->IsArtMethod()) {
     mirror::ArtMethod* method = obj->AsArtMethod();
@@ -1667,7 +1664,7 @@
   gc::Heap* heap = Runtime::Current()->GetHeap();
   gc::space::ImageSpace* space = heap->GetImageSpace();
   dex_cache_image_class_lookup_required_ = true;
-  CHECK(space != NULL);
+  CHECK(space != nullptr);
   OatFile& oat_file = GetImageOatFile(space);
   CHECK_EQ(oat_file.GetOatHeader().GetImageFileLocationOatChecksum(), 0U);
   CHECK_EQ(oat_file.GetOatHeader().GetImageFileLocationOatDataBegin(), 0U);
@@ -1702,10 +1699,10 @@
     const std::string& dex_file_location(dex_cache->GetLocation()->ToModifiedUtf8());
     const OatFile::OatDexFile* oat_dex_file = oat_file.GetOatDexFile(dex_file_location.c_str(),
                                                                      nullptr);
-    CHECK(oat_dex_file != NULL) << oat_file.GetLocation() << " " << dex_file_location;
+    CHECK(oat_dex_file != nullptr) << oat_file.GetLocation() << " " << dex_file_location;
     std::string error_msg;
     const DexFile* dex_file = oat_dex_file->OpenDexFile(&error_msg);
-    if (dex_file == NULL) {
+    if (dex_file == nullptr) {
       LOG(FATAL) << "Failed to open dex file " << dex_file_location
                  << " from within oat file " << oat_file.GetLocation()
                  << " error '" << error_msg << "'";
@@ -1878,7 +1875,7 @@
   } else {
     Thread* self = Thread::Current();
     StackHandleScope<1> hs(self);
-    Handle<mirror::ObjectArray<mirror::Class>> classes =
+    MutableHandle<mirror::ObjectArray<mirror::Class>> classes =
         hs.NewHandle<mirror::ObjectArray<mirror::Class>>(nullptr);
     GetClassesVisitorArrayArg local_arg;
     local_arg.classes = &classes;
@@ -1940,33 +1937,33 @@
       hs.NewHandle(down_cast<mirror::DexCache*>(
           heap->AllocObject<true>(self, dex_cache_class.Get(), dex_cache_class->GetObjectSize(),
                                   VoidFunctor()))));
-  if (dex_cache.Get() == NULL) {
-    return NULL;
+  if (dex_cache.Get() == nullptr) {
+    return nullptr;
   }
   Handle<mirror::String>
       location(hs.NewHandle(intern_table_->InternStrong(dex_file.GetLocation().c_str())));
-  if (location.Get() == NULL) {
-    return NULL;
+  if (location.Get() == nullptr) {
+    return nullptr;
   }
   Handle<mirror::ObjectArray<mirror::String>>
       strings(hs.NewHandle(AllocStringArray(self, dex_file.NumStringIds())));
-  if (strings.Get() == NULL) {
-    return NULL;
+  if (strings.Get() == nullptr) {
+    return nullptr;
   }
   Handle<mirror::ObjectArray<mirror::Class>>
       types(hs.NewHandle(AllocClassArray(self, dex_file.NumTypeIds())));
-  if (types.Get() == NULL) {
-    return NULL;
+  if (types.Get() == nullptr) {
+    return nullptr;
   }
   Handle<mirror::ObjectArray<mirror::ArtMethod>>
       methods(hs.NewHandle(AllocArtMethodArray(self, dex_file.NumMethodIds())));
-  if (methods.Get() == NULL) {
-    return NULL;
+  if (methods.Get() == nullptr) {
+    return nullptr;
   }
   Handle<mirror::ObjectArray<mirror::ArtField>>
       fields(hs.NewHandle(AllocArtFieldArray(self, dex_file.NumFieldIds())));
-  if (fields.Get() == NULL) {
-    return NULL;
+  if (fields.Get() == nullptr) {
+    return nullptr;
   }
   dex_cache->Init(&dex_file, location.Get(), strings.Get(), types.Get(), methods.Get(),
                   fields.Get());
@@ -2010,7 +2007,7 @@
 
 mirror::Class* ClassLinker::EnsureResolved(Thread* self, const char* descriptor,
                                            mirror::Class* klass) {
-  DCHECK(klass != NULL);
+  DCHECK(klass != nullptr);
 
   // For temporary classes we must wait for them to be retired.
   if (init_done_ && klass->IsTemp()) {
@@ -2070,18 +2067,18 @@
   for (size_t i = 0; i != class_path.size(); ++i) {
     const DexFile* dex_file = class_path[i];
     const DexFile::ClassDef* dex_class_def = dex_file->FindClassDef(descriptor);
-    if (dex_class_def != NULL) {
+    if (dex_class_def != nullptr) {
       return ClassPathEntry(dex_file, dex_class_def);
     }
   }
   // TODO: remove reinterpret_cast when issue with -std=gnu++0x host issue resolved
-  return ClassPathEntry(reinterpret_cast<const DexFile*>(NULL),
-                        reinterpret_cast<const DexFile::ClassDef*>(NULL));
+  return ClassPathEntry(static_cast<const DexFile*>(nullptr),
+                        static_cast<const DexFile::ClassDef*>(nullptr));
 }
 
 mirror::Class* ClassLinker::FindClassInPathClassLoader(ScopedObjectAccessAlreadyRunnable& soa,
                                                        Thread* self, const char* descriptor,
-                                                       ConstHandle<mirror::ClassLoader> class_loader) {
+                                                       Handle<mirror::ClassLoader> class_loader) {
   if (class_loader->GetClass() !=
       soa.Decode<mirror::Class*>(WellKnownClasses::dalvik_system_PathClassLoader) ||
       class_loader->GetParent()->GetClass() !=
@@ -2165,7 +2162,7 @@
 }
 
 mirror::Class* ClassLinker::FindClass(Thread* self, const char* descriptor,
-                                      ConstHandle<mirror::ClassLoader> class_loader) {
+                                      Handle<mirror::ClassLoader> class_loader) {
   DCHECK_NE(*descriptor, '\0') << "descriptor is empty string";
   DCHECK(self != nullptr);
   self->AssertNoPendingException();
@@ -2270,7 +2267,7 @@
 }
 
 mirror::Class* ClassLinker::DefineClass(Thread* self, const char* descriptor,
-                                        ConstHandle<mirror::ClassLoader> class_loader,
+                                        Handle<mirror::ClassLoader> class_loader,
                                         const DexFile& dex_file,
                                         const DexFile::ClassDef& dex_class_def) {
   StackHandleScope<3> hs(self);
@@ -2386,7 +2383,7 @@
   size_t num_16 = 0;
   size_t num_32 = 0;
   size_t num_64 = 0;
-  if (class_data != NULL) {
+  if (class_data != nullptr) {
     for (ClassDataItemIterator it(dex_file, class_data); it.HasNextStaticField(); it.Next()) {
       const DexFile::FieldId& field_id = dex_file.GetFieldId(it.GetMemberIndex());
       const char* descriptor = dex_file.GetFieldTypeDescriptor(field_id);
@@ -2436,7 +2433,7 @@
                                                  uint32_t method_idx) {
   const DexFile::ClassDef& class_def = dex_file.GetClassDef(class_def_idx);
   const byte* class_data = dex_file.GetClassData(class_def);
-  CHECK(class_data != NULL);
+  CHECK(class_data != nullptr);
   ClassDataItemIterator it(dex_file, class_data);
   // Skip fields
   while (it.HasNextStaticField()) {
@@ -2697,7 +2694,7 @@
   // Ignore virtual methods on the iterator.
 }
 
-void ClassLinker::LinkCode(ConstHandle<mirror::ArtMethod> method,
+void ClassLinker::LinkCode(Handle<mirror::ArtMethod> method,
                            const OatFile::OatClass* oat_class,
                            const DexFile& dex_file, uint32_t dex_method_index,
                            uint32_t method_index) {
@@ -2780,31 +2777,30 @@
 
 void ClassLinker::LoadClass(Thread* self, const DexFile& dex_file,
                             const DexFile::ClassDef& dex_class_def,
-                            ConstHandle<mirror::Class> klass,
+                            Handle<mirror::Class> klass,
                             mirror::ClassLoader* class_loader) {
-  CHECK(klass.Get() != NULL);
-  CHECK(klass->GetDexCache() != NULL);
+  CHECK(klass.Get() != nullptr);
+  CHECK(klass->GetDexCache() != nullptr);
   CHECK_EQ(mirror::Class::kStatusNotReady, klass->GetStatus());
   const char* descriptor = dex_file.GetClassDescriptor(dex_class_def);
-  CHECK(descriptor != NULL);
+  CHECK(descriptor != nullptr);
 
   klass->SetClass(GetClassRoot(kJavaLangClass));
   if (kUseBakerOrBrooksReadBarrier) {
     klass->AssertReadBarrierPointer();
   }
-  uint32_t access_flags = dex_class_def.access_flags_;
-  // Make sure that none of our runtime-only flags are set.
+  uint32_t access_flags = dex_class_def.GetJavaAccessFlags();
   CHECK_EQ(access_flags & ~kAccJavaFlagsMask, 0U);
   klass->SetAccessFlags(access_flags);
   klass->SetClassLoader(class_loader);
   DCHECK_EQ(klass->GetPrimitiveType(), Primitive::kPrimNot);
-  klass->SetStatus(mirror::Class::kStatusIdx, NULL);
+  klass->SetStatus(mirror::Class::kStatusIdx, nullptr);
 
   klass->SetDexClassDefIndex(dex_file.GetIndexForClassDef(dex_class_def));
   klass->SetDexTypeIndex(dex_class_def.class_idx_);
 
   const byte* class_data = dex_file.GetClassData(dex_class_def);
-  if (class_data == NULL) {
+  if (class_data == nullptr) {
     return;  // no fields or methods - for example a marker interface
   }
 
@@ -2824,14 +2820,14 @@
 
 void ClassLinker::LoadClassMembers(Thread* self, const DexFile& dex_file,
                                    const byte* class_data,
-                                   ConstHandle<mirror::Class> klass,
+                                   Handle<mirror::Class> klass,
                                    mirror::ClassLoader* class_loader,
                                    const OatFile::OatClass* oat_class) {
   // Load fields.
   ClassDataItemIterator it(dex_file, class_data);
   if (it.NumStaticFields() != 0) {
     mirror::ObjectArray<mirror::ArtField>* statics = AllocArtFieldArray(self, it.NumStaticFields());
-    if (UNLIKELY(statics == NULL)) {
+    if (UNLIKELY(statics == nullptr)) {
       CHECK(self->IsExceptionPending());  // OOME.
       return;
     }
@@ -2840,7 +2836,7 @@
   if (it.NumInstanceFields() != 0) {
     mirror::ObjectArray<mirror::ArtField>* fields =
         AllocArtFieldArray(self, it.NumInstanceFields());
-    if (UNLIKELY(fields == NULL)) {
+    if (UNLIKELY(fields == nullptr)) {
       CHECK(self->IsExceptionPending());  // OOME.
       return;
     }
@@ -2850,7 +2846,7 @@
     self->AllowThreadSuspension();
     StackHandleScope<1> hs(self);
     Handle<mirror::ArtField> sfield(hs.NewHandle(AllocArtField(self)));
-    if (UNLIKELY(sfield.Get() == NULL)) {
+    if (UNLIKELY(sfield.Get() == nullptr)) {
       CHECK(self->IsExceptionPending());  // OOME.
       return;
     }
@@ -2861,7 +2857,7 @@
     self->AllowThreadSuspension();
     StackHandleScope<1> hs(self);
     Handle<mirror::ArtField> ifield(hs.NewHandle(AllocArtField(self)));
-    if (UNLIKELY(ifield.Get() == NULL)) {
+    if (UNLIKELY(ifield.Get() == nullptr)) {
       CHECK(self->IsExceptionPending());  // OOME.
       return;
     }
@@ -2874,7 +2870,7 @@
     // TODO: append direct methods to class object
     mirror::ObjectArray<mirror::ArtMethod>* directs =
          AllocArtMethodArray(self, it.NumDirectMethods());
-    if (UNLIKELY(directs == NULL)) {
+    if (UNLIKELY(directs == nullptr)) {
       CHECK(self->IsExceptionPending());  // OOME.
       return;
     }
@@ -2884,7 +2880,7 @@
     // TODO: append direct methods to class object
     mirror::ObjectArray<mirror::ArtMethod>* virtuals =
         AllocArtMethodArray(self, it.NumVirtualMethods());
-    if (UNLIKELY(virtuals == NULL)) {
+    if (UNLIKELY(virtuals == nullptr)) {
       CHECK(self->IsExceptionPending());  // OOME.
       return;
     }
@@ -2897,7 +2893,7 @@
     self->AllowThreadSuspension();
     StackHandleScope<1> hs(self);
     Handle<mirror::ArtMethod> method(hs.NewHandle(LoadMethod(self, dex_file, it, klass)));
-    if (UNLIKELY(method.Get() == NULL)) {
+    if (UNLIKELY(method.Get() == nullptr)) {
       CHECK(self->IsExceptionPending());  // OOME.
       return;
     }
@@ -2918,7 +2914,7 @@
     self->AllowThreadSuspension();
     StackHandleScope<1> hs(self);
     Handle<mirror::ArtMethod> method(hs.NewHandle(LoadMethod(self, dex_file, it, klass)));
-    if (UNLIKELY(method.Get() == NULL)) {
+    if (UNLIKELY(method.Get() == nullptr)) {
       CHECK(self->IsExceptionPending());  // OOME.
       return;
     }
@@ -2931,25 +2927,25 @@
 }
 
 void ClassLinker::LoadField(const DexFile& /*dex_file*/, const ClassDataItemIterator& it,
-                            ConstHandle<mirror::Class> klass,
-                            ConstHandle<mirror::ArtField> dst) {
+                            Handle<mirror::Class> klass,
+                            Handle<mirror::ArtField> dst) {
   uint32_t field_idx = it.GetMemberIndex();
   dst->SetDexFieldIndex(field_idx);
   dst->SetDeclaringClass(klass.Get());
-  dst->SetAccessFlags(it.GetMemberAccessFlags());
+  dst->SetAccessFlags(it.GetFieldAccessFlags());
 }
 
 mirror::ArtMethod* ClassLinker::LoadMethod(Thread* self, const DexFile& dex_file,
                                            const ClassDataItemIterator& it,
-                                           ConstHandle<mirror::Class> klass) {
+                                           Handle<mirror::Class> klass) {
   uint32_t dex_method_idx = it.GetMemberIndex();
   const DexFile::MethodId& method_id = dex_file.GetMethodId(dex_method_idx);
   const char* method_name = dex_file.StringDataByIdx(method_id.name_idx_);
 
   mirror::ArtMethod* dst = AllocArtMethod(self);
-  if (UNLIKELY(dst == NULL)) {
+  if (UNLIKELY(dst == nullptr)) {
     CHECK(self->IsExceptionPending());  // OOME.
-    return NULL;
+    return nullptr;
   }
   DCHECK(dst->IsArtMethod()) << PrettyDescriptor(dst->GetClass());
 
@@ -2962,13 +2958,13 @@
   dst->SetDexCacheResolvedMethods(klass->GetDexCache()->GetResolvedMethods());
   dst->SetDexCacheResolvedTypes(klass->GetDexCache()->GetResolvedTypes());
 
-  uint32_t access_flags = it.GetMemberAccessFlags();
+  uint32_t access_flags = it.GetMethodAccessFlags();
 
   if (UNLIKELY(strcmp("finalize", method_name) == 0)) {
     // Set finalizable flag on declaring class.
     if (strcmp("V", dex_file.GetShorty(method_id.proto_idx_)) == 0) {
       // Void return type.
-      if (klass->GetClassLoader() != NULL) {  // All non-boot finalizer methods are flagged.
+      if (klass->GetClassLoader() != nullptr) {  // All non-boot finalizer methods are flagged.
         klass->SetFinalizable();
       } else {
         std::string temp;
@@ -3007,13 +3003,14 @@
 void ClassLinker::AppendToBootClassPath(Thread* self, const DexFile& dex_file) {
   StackHandleScope<1> hs(self);
   Handle<mirror::DexCache> dex_cache(hs.NewHandle(AllocDexCache(self, dex_file)));
-  CHECK(dex_cache.Get() != NULL) << "Failed to allocate dex cache for " << dex_file.GetLocation();
+  CHECK(dex_cache.Get() != nullptr) << "Failed to allocate dex cache for "
+                                    << dex_file.GetLocation();
   AppendToBootClassPath(dex_file, dex_cache);
 }
 
 void ClassLinker::AppendToBootClassPath(const DexFile& dex_file,
-                                        ConstHandle<mirror::DexCache> dex_cache) {
-  CHECK(dex_cache.Get() != NULL) << dex_file.GetLocation();
+                                        Handle<mirror::DexCache> dex_cache) {
+  CHECK(dex_cache.Get() != nullptr) << dex_file.GetLocation();
   boot_class_path_.push_back(&dex_file);
   RegisterDexFile(dex_file, dex_cache);
 }
@@ -3035,9 +3032,9 @@
 }
 
 void ClassLinker::RegisterDexFileLocked(const DexFile& dex_file,
-                                        ConstHandle<mirror::DexCache> dex_cache) {
+                                        Handle<mirror::DexCache> dex_cache) {
   dex_lock_.AssertExclusiveHeld(Thread::Current());
-  CHECK(dex_cache.Get() != NULL) << dex_file.GetLocation();
+  CHECK(dex_cache.Get() != nullptr) << dex_file.GetLocation();
   CHECK(dex_cache->GetLocation()->Equals(dex_file.GetLocation()))
       << dex_cache->GetLocation()->ToModifiedUtf8() << " " << dex_file.GetLocation();
   dex_caches_.push_back(GcRoot<mirror::DexCache>(dex_cache.Get()));
@@ -3061,7 +3058,8 @@
   // get to a suspend point.
   StackHandleScope<1> hs(self);
   Handle<mirror::DexCache> dex_cache(hs.NewHandle(AllocDexCache(self, dex_file)));
-  CHECK(dex_cache.Get() != NULL) << "Failed to allocate dex cache for " << dex_file.GetLocation();
+  CHECK(dex_cache.Get() != nullptr) << "Failed to allocate dex cache for "
+                                    << dex_file.GetLocation();
   {
     WriterMutexLock mu(self, dex_lock_);
     if (IsDexFileRegisteredLocked(dex_file)) {
@@ -3072,7 +3070,7 @@
 }
 
 void ClassLinker::RegisterDexFile(const DexFile& dex_file,
-                                  ConstHandle<mirror::DexCache> dex_cache) {
+                                  Handle<mirror::DexCache> dex_cache) {
   WriterMutexLock mu(Thread::Current(), dex_lock_);
   RegisterDexFileLocked(dex_file, dex_cache);
 }
@@ -3100,7 +3098,7 @@
     LOG(ERROR) << "Registered dex file " << i << " = " << dex_cache->GetDexFile()->GetLocation();
   }
   LOG(FATAL) << "Failed to find DexCache for DexFile " << location;
-  return NULL;
+  return nullptr;
 }
 
 void ClassLinker::FixupDexCaches(mirror::ArtMethod* resolution_method) {
@@ -3113,15 +3111,15 @@
 
 mirror::Class* ClassLinker::CreatePrimitiveClass(Thread* self, Primitive::Type type) {
   mirror::Class* klass = AllocClass(self, mirror::Class::PrimitiveClassSize());
-  if (UNLIKELY(klass == NULL)) {
-    return NULL;
+  if (UNLIKELY(klass == nullptr)) {
+    return nullptr;
   }
   return InitializePrimitiveClass(klass, type);
 }
 
 mirror::Class* ClassLinker::InitializePrimitiveClass(mirror::Class* primitive_class,
                                                      Primitive::Type type) {
-  CHECK(primitive_class != NULL);
+  CHECK(primitive_class != nullptr);
   // Must hold lock on object when initializing.
   Thread* self = Thread::Current();
   StackHandleScope<1> hs(self);
@@ -3132,7 +3130,7 @@
   primitive_class->SetStatus(mirror::Class::kStatusInitialized, self);
   const char* descriptor = Primitive::Descriptor(type);
   mirror::Class* existing = InsertClass(descriptor, primitive_class, Hash(descriptor));
-  CHECK(existing == NULL) << "InitPrimitiveClass(" << type << ") failed";
+  CHECK(existing == nullptr) << "InitPrimitiveClass(" << type << ") failed";
   return primitive_class;
 }
 
@@ -3148,13 +3146,14 @@
 // the right context.  It does NOT become the class loader for the
 // array class; that always comes from the base element class.
 //
-// Returns NULL with an exception raised on failure.
+// Returns nullptr with an exception raised on failure.
 mirror::Class* ClassLinker::CreateArrayClass(Thread* self, const char* descriptor,
-                                             ConstHandle<mirror::ClassLoader> class_loader) {
+                                             Handle<mirror::ClassLoader> class_loader) {
   // Identify the underlying component type
   CHECK_EQ('[', descriptor[0]);
   StackHandleScope<2> hs(self);
-  Handle<mirror::Class> component_type(hs.NewHandle(FindClass(self, descriptor + 1, class_loader)));
+  MutableHandle<mirror::Class> component_type(hs.NewHandle(FindClass(self, descriptor + 1,
+                                                                     class_loader)));
   if (component_type.Get() == nullptr) {
     DCHECK(self->IsExceptionPending());
     // We need to accept erroneous classes as component types.
@@ -3189,7 +3188,7 @@
   // other threads.)
   if (class_loader.Get() != component_type->GetClassLoader()) {
     mirror::Class* new_class = LookupClass(self, descriptor, component_type->GetClassLoader());
-    if (new_class != NULL) {
+    if (new_class != nullptr) {
       return new_class;
     }
   }
@@ -3231,7 +3230,7 @@
     new_class->SetComponentType(component_type.Get());
   }
   ObjectLock<mirror::Class> lock(self, new_class);  // Must hold lock on object when initializing.
-  DCHECK(new_class->GetComponentType() != NULL);
+  DCHECK(new_class->GetComponentType() != nullptr);
   mirror::Class* java_lang_Object = GetClassRoot(kJavaLangObject);
   new_class->SetSuperClass(java_lang_Object);
   new_class->SetVTable(java_lang_Object->GetVTable());
@@ -3311,7 +3310,7 @@
   }
   std::string printable_type(PrintableChar(type));
   ThrowNoClassDefFoundError("Not a primitive type: %s", printable_type.c_str());
-  return NULL;
+  return nullptr;
 }
 
 mirror::Class* ClassLinker::InsertClass(const char* descriptor, mirror::Class* klass,
@@ -3319,7 +3318,7 @@
   if (VLOG_IS_ON(class_linker)) {
     mirror::DexCache* dex_cache = klass->GetDexCache();
     std::string source;
-    if (dex_cache != NULL) {
+    if (dex_cache != nullptr) {
       source += " from ";
       source += dex_cache->GetLocation()->ToModifiedUtf8();
     }
@@ -3328,15 +3327,15 @@
   WriterMutexLock mu(Thread::Current(), *Locks::classlinker_classes_lock_);
   mirror::Class* existing =
       LookupClassFromTableLocked(descriptor, klass->GetClassLoader(), hash);
-  if (existing != NULL) {
+  if (existing != nullptr) {
     return existing;
   }
-  if (kIsDebugBuild && !klass->IsTemp() && klass->GetClassLoader() == NULL &&
+  if (kIsDebugBuild && !klass->IsTemp() && klass->GetClassLoader() == nullptr &&
       dex_cache_image_class_lookup_required_) {
     // Check a class loaded with the system class loader matches one in the image if the class
     // is in the image.
     existing = LookupClassFromImage(descriptor);
-    if (existing != NULL) {
+    if (existing != nullptr) {
       CHECK(klass == existing);
     }
   }
@@ -3345,7 +3344,7 @@
   if (log_new_class_table_roots_) {
     new_class_roots_.push_back(std::make_pair(hash, GcRoot<mirror::Class>(klass)));
   }
-  return NULL;
+  return nullptr;
 }
 
 mirror::Class* ClassLinker::UpdateClass(const char* descriptor, mirror::Class* klass,
@@ -3363,8 +3362,8 @@
   CHECK(!existing->IsResolved()) << descriptor;
   CHECK_EQ(klass->GetStatus(), mirror::Class::kStatusResolving) << descriptor;
 
-  for (auto it = class_table_.lower_bound(hash), end = class_table_.end(); it != end && it->first == hash;
-       ++it) {
+  for (auto it = class_table_.lower_bound(hash), end = class_table_.end();
+       it != end && it->first == hash; ++it) {
     mirror::Class* klass = it->second.Read();
     if (klass == existing) {
       class_table_.erase(it);
@@ -3413,16 +3412,16 @@
   {
     ReaderMutexLock mu(self, *Locks::classlinker_classes_lock_);
     mirror::Class* result = LookupClassFromTableLocked(descriptor, class_loader, hash);
-    if (result != NULL) {
+    if (result != nullptr) {
       return result;
     }
   }
-  if (class_loader != NULL || !dex_cache_image_class_lookup_required_) {
-    return NULL;
+  if (class_loader != nullptr || !dex_cache_image_class_lookup_required_) {
+    return nullptr;
   } else {
     // Lookup failed but need to search dex_caches_.
     mirror::Class* result = LookupClassFromImage(descriptor);
-    if (result != NULL) {
+    if (result != nullptr) {
       InsertClass(descriptor, result, hash);
     } else {
       // Searching the image dex files/caches failed, we don't want to get into this situation
@@ -3457,13 +3456,13 @@
       return klass;
     }
   }
-  return NULL;
+  return nullptr;
 }
 
 static mirror::ObjectArray<mirror::DexCache>* GetImageDexCaches()
     SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
   gc::space::ImageSpace* image = Runtime::Current()->GetHeap()->GetImageSpace();
-  CHECK(image != NULL);
+  CHECK(image != nullptr);
   mirror::Object* root = image->GetImageHeader().GetImageRoot(ImageHeader::kDexCaches);
   return root->AsObjectArray<mirror::DexCache>();
 }
@@ -3483,12 +3482,12 @@
     mirror::ObjectArray<mirror::Class>* types = dex_cache->GetResolvedTypes();
     for (int32_t j = 0; j < types->GetLength(); j++) {
       mirror::Class* klass = types->Get(j);
-      if (klass != NULL) {
-        DCHECK(klass->GetClassLoader() == NULL);
+      if (klass != nullptr) {
+        DCHECK(klass->GetClassLoader() == nullptr);
         const char* descriptor = klass->GetDescriptor(&temp);
         size_t hash = Hash(descriptor);
-        mirror::Class* existing = LookupClassFromTableLocked(descriptor, NULL, hash);
-        if (existing != NULL) {
+        mirror::Class* existing = LookupClassFromTableLocked(descriptor, nullptr, hash);
+        if (existing != nullptr) {
           CHECK(existing == klass) << PrettyClassAndClassLoader(existing) << " != "
               << PrettyClassAndClassLoader(klass);
         } else {
@@ -3514,13 +3513,13 @@
     const DexFile* dex_file = dex_cache->GetDexFile();
     // Try binary searching the string/type index.
     const DexFile::StringId* string_id = dex_file->FindStringId(descriptor);
-    if (string_id != NULL) {
+    if (string_id != nullptr) {
       const DexFile::TypeId* type_id =
           dex_file->FindTypeId(dex_file->GetIndexForStringId(*string_id));
-      if (type_id != NULL) {
+      if (type_id != nullptr) {
         uint16_t type_idx = dex_file->GetIndexForTypeId(*type_id);
         mirror::Class* klass = dex_cache->GetResolvedType(type_idx);
-        if (klass != NULL) {
+        if (klass != nullptr) {
           self->EndAssertNoThreadSuspension(old_no_suspend_cause);
           return klass;
         }
@@ -3528,7 +3527,7 @@
     }
   }
   self->EndAssertNoThreadSuspension(old_no_suspend_cause);
-  return NULL;
+  return nullptr;
 }
 
 void ClassLinker::LookupClasses(const char* descriptor, std::vector<mirror::Class*>& result) {
@@ -3547,7 +3546,7 @@
   }
 }
 
-void ClassLinker::VerifyClass(Thread* self, ConstHandle<mirror::Class> klass) {
+void ClassLinker::VerifyClass(Thread* self, Handle<mirror::Class> klass) {
   // TODO: assert that the monitor on the Class is held
   ObjectLock<mirror::Class> lock(self, klass);
 
@@ -3586,7 +3585,7 @@
   // Verify super class.
   StackHandleScope<2> hs(self);
   Handle<mirror::Class> super(hs.NewHandle(klass->GetSuperClass()));
-  if (super.Get() != NULL) {
+  if (super.Get() != nullptr) {
     // Acquire lock to prevent races on verifying the super class.
     ObjectLock<mirror::Class> lock(self, super);
 
@@ -3648,7 +3647,7 @@
     if (verifier_failure == verifier::MethodVerifier::kNoFailure) {
       // Even though there were no verifier failures we need to respect whether the super-class
       // was verified or requiring runtime reverification.
-      if (super.Get() == NULL || super->IsVerified()) {
+      if (super.Get() == nullptr || super->IsVerified()) {
         klass->SetStatus(mirror::Class::kStatusVerified, self);
       } else {
         CHECK_EQ(super->GetStatus(), mirror::Class::kStatusRetryVerificationAtRuntime);
@@ -3689,7 +3688,7 @@
   }
 }
 
-void ClassLinker::EnsurePreverifiedMethods(ConstHandle<mirror::Class> klass) {
+void ClassLinker::EnsurePreverifiedMethods(Handle<mirror::Class> klass) {
   if (!klass->IsPreverified()) {
     klass->SetPreverifiedFlagOnAllMethods();
     klass->SetPreverified();
@@ -3710,19 +3709,17 @@
     // We are compiling an app (not the image).
 
     // Is this an app class? (I.e. not a bootclasspath class)
-    if (klass->GetClassLoader() != NULL) {
+    if (klass->GetClassLoader() != nullptr) {
       return false;
     }
   }
 
   const OatFile::OatDexFile* oat_dex_file = FindOpenedOatDexFileForDexFile(dex_file);
-  // Make this work with gtests, which do not set up the image properly.
-  // TODO: we should clean up gtests to set up the image path properly.
-  if (Runtime::Current()->IsCompiler() || (oat_dex_file == nullptr)) {
+  // In case we run without an image there won't be a backing oat file.
+  if (oat_dex_file == nullptr) {
     return false;
   }
 
-  CHECK(oat_dex_file != NULL) << dex_file.GetLocation() << " " << PrettyClass(klass);
   uint16_t class_def_index = klass->GetDexClassDefIndex();
   oat_file_class_status = oat_dex_file->GetOatClass(class_def_index).GetStatus();
   if (oat_file_class_status == mirror::Class::kStatusVerified ||
@@ -3770,7 +3767,7 @@
 }
 
 void ClassLinker::ResolveClassExceptionHandlerTypes(const DexFile& dex_file,
-                                                    ConstHandle<mirror::Class> klass) {
+                                                    Handle<mirror::Class> klass) {
   for (size_t i = 0; i < klass->NumDirectMethods(); i++) {
     ResolveMethodExceptionHandlerTypes(dex_file, klass->GetDirectMethod(i));
   }
@@ -3783,7 +3780,7 @@
                                                      mirror::ArtMethod* method) {
   // similar to DexVerifier::ScanTryCatchBlocks and dex2oat's ResolveExceptionsForMethod.
   const DexFile::CodeItem* code_item = dex_file.GetCodeItem(method->GetCodeItemOffset());
-  if (code_item == NULL) {
+  if (code_item == nullptr) {
     return;  // native or abstract method
   }
   if (code_item->tries_size_ == 0) {
@@ -3799,7 +3796,7 @@
       // unresolved exception types will be ignored by exception delivery
       if (iterator.GetHandlerTypeIndex() != DexFile::kDexNoIndex16) {
         mirror::Class* exception_type = linker->ResolveType(iterator.GetHandlerTypeIndex(), method);
-        if (exception_type == NULL) {
+        if (exception_type == nullptr) {
           DCHECK(Thread::Current()->IsExceptionPending());
           Thread::Current()->ClearException();
         }
@@ -3810,21 +3807,21 @@
 }
 
 static void CheckProxyConstructor(mirror::ArtMethod* constructor);
-static void CheckProxyMethod(ConstHandle<mirror::ArtMethod> method,
-                             ConstHandle<mirror::ArtMethod> prototype);
+static void CheckProxyMethod(Handle<mirror::ArtMethod> method,
+                             Handle<mirror::ArtMethod> prototype);
 
 mirror::Class* ClassLinker::CreateProxyClass(ScopedObjectAccessAlreadyRunnable& soa, jstring name,
                                              jobjectArray interfaces, jobject loader,
                                              jobjectArray methods, jobjectArray throws) {
   Thread* self = soa.Self();
   StackHandleScope<8> hs(self);
-  Handle<mirror::Class> klass(hs.NewHandle(
+  MutableHandle<mirror::Class> klass(hs.NewHandle(
       AllocClass(self, GetClassRoot(kJavaLangClass), sizeof(mirror::Class))));
-  if (klass.Get() == NULL) {
+  if (klass.Get() == nullptr) {
     CHECK(self->IsExceptionPending());  // OOME.
-    return NULL;
+    return nullptr;
   }
-  DCHECK(klass->GetClass() != NULL);
+  DCHECK(klass->GetClass() != nullptr);
   klass->SetObjectSize(sizeof(mirror::Proxy));
   // Set the class access flags incl. preverified, so we do not try to set the flag on the methods.
   klass->SetAccessFlags(kAccClassIsProxy | kAccPublic | kAccFinal | kAccPreverified);
@@ -3838,9 +3835,9 @@
   // Instance fields are inherited, but we add a couple of static fields...
   {
     mirror::ObjectArray<mirror::ArtField>* sfields = AllocArtFieldArray(self, 2);
-    if (UNLIKELY(sfields == NULL)) {
+    if (UNLIKELY(sfields == nullptr)) {
       CHECK(self->IsExceptionPending());  // OOME.
-      return NULL;
+      return nullptr;
     }
     klass->SetSFields(sfields);
   }
@@ -3888,9 +3885,9 @@
   {
     mirror::ObjectArray<mirror::ArtMethod>* virtuals = AllocArtMethodArray(self,
                                                                            num_virtual_methods);
-    if (UNLIKELY(virtuals == NULL)) {
+    if (UNLIKELY(virtuals == nullptr)) {
       CHECK(self->IsExceptionPending());  // OOME.
-      return NULL;
+      return nullptr;
     }
     klass->SetVirtualMethods(virtuals);
   }
@@ -3914,7 +3911,8 @@
   std::string descriptor(GetDescriptorForProxy(klass.Get()));
   mirror::Class* new_class = nullptr;
   {
-    ObjectLock<mirror::Class> resolution_lock(self, klass);  // Must hold lock on object when resolved.
+    // Must hold lock on object when resolved.
+    ObjectLock<mirror::Class> resolution_lock(self, klass);
     // Link the fields and virtual methods, creating vtable and iftables
     Handle<mirror::ObjectArray<mirror::Class> > h_interfaces(
         hs.NewHandle(soa.Decode<mirror::ObjectArray<mirror::Class>*>(interfaces)));
@@ -3929,9 +3927,11 @@
   klass.Assign(new_class);
 
   CHECK_EQ(interfaces_sfield->GetDeclaringClass(), new_class);
-  interfaces_sfield->SetObject<false>(klass.Get(), soa.Decode<mirror::ObjectArray<mirror::Class>*>(interfaces));
+  interfaces_sfield->SetObject<false>(klass.Get(),
+                                      soa.Decode<mirror::ObjectArray<mirror::Class>*>(interfaces));
   CHECK_EQ(throws_sfield->GetDeclaringClass(), new_class);
-  throws_sfield->SetObject<false>(klass.Get(), soa.Decode<mirror::ObjectArray<mirror::ObjectArray<mirror::Class> >*>(throws));
+  throws_sfield->SetObject<false>(klass.Get(),
+      soa.Decode<mirror::ObjectArray<mirror::ObjectArray<mirror::Class> >*>(throws));
 
   {
     // Lock on klass is released. Lock new class object.
@@ -3974,7 +3974,7 @@
 std::string ClassLinker::GetDescriptorForProxy(mirror::Class* proxy_class) {
   DCHECK(proxy_class->IsProxyClass());
   mirror::String* name = proxy_class->GetName();
-  DCHECK(name != NULL);
+  DCHECK(name != nullptr);
   return DotToDescriptor(name->ToModifiedUtf8().c_str());
 }
 
@@ -4003,7 +4003,7 @@
 
 
 mirror::ArtMethod* ClassLinker::CreateProxyConstructor(Thread* self,
-                                                       ConstHandle<mirror::Class> klass,
+                                                       Handle<mirror::Class> klass,
                                                        mirror::Class* proxy_class) {
   // Create constructor for Proxy that must initialize h
   mirror::ObjectArray<mirror::ArtMethod>* proxy_direct_methods =
@@ -4037,8 +4037,8 @@
 }
 
 mirror::ArtMethod* ClassLinker::CreateProxyMethod(Thread* self,
-                                                  ConstHandle<mirror::Class> klass,
-                                                  ConstHandle<mirror::ArtMethod> prototype) {
+                                                  Handle<mirror::Class> klass,
+                                                  Handle<mirror::ArtMethod> prototype) {
   // Ensure prototype is in dex cache so that we can use the dex cache to look up the overridden
   // prototype method
   prototype->GetDeclaringClass()->GetDexCache()->SetResolvedMethod(prototype->GetDexMethodIndex(),
@@ -4046,9 +4046,9 @@
   // We steal everything from the prototype (such as DexCache, invoke stub, etc.) then specialize
   // as necessary
   mirror::ArtMethod* method = down_cast<mirror::ArtMethod*>(prototype->Clone(self));
-  if (UNLIKELY(method == NULL)) {
+  if (UNLIKELY(method == nullptr)) {
     CHECK(self->IsExceptionPending());  // OOME.
-    return NULL;
+    return nullptr;
   }
 
   // Set class to be the concrete proxy class and clear the abstract flag, modify exceptions to
@@ -4065,8 +4065,8 @@
   return method;
 }
 
-static void CheckProxyMethod(ConstHandle<mirror::ArtMethod> method,
-                             ConstHandle<mirror::ArtMethod> prototype)
+static void CheckProxyMethod(Handle<mirror::ArtMethod> method,
+                             Handle<mirror::ArtMethod> prototype)
     SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
   // Basic sanity
   CHECK(!prototype->IsFinal());
@@ -4098,13 +4098,13 @@
   if (!can_init_statics) {
     // Check if there's a class initializer.
     mirror::ArtMethod* clinit = klass->FindClassInitializer();
-    if (clinit != NULL) {
+    if (clinit != nullptr) {
       return false;
     }
     // Check if there are encoded static values needing initialization.
     if (klass->NumStaticFields() != 0) {
       const DexFile::ClassDef* dex_class_def = klass->GetClassDef();
-      DCHECK(dex_class_def != NULL);
+      DCHECK(dex_class_def != nullptr);
       if (dex_class_def->static_values_off_ != 0) {
         return false;
       }
@@ -4123,7 +4123,7 @@
   return true;
 }
 
-bool ClassLinker::InitializeClass(Thread* self, ConstHandle<mirror::Class> klass,
+bool ClassLinker::InitializeClass(Thread* self, Handle<mirror::Class> klass,
                                   bool can_init_statics, bool can_init_parents) {
   // see JLS 3rd edition, 12.4.2 "Detailed Initialization Procedure" for the locking protocol
 
@@ -4226,7 +4226,7 @@
             << PrettyDescriptor(handle_scope_super.Get())
             << " that has unexpected status " << handle_scope_super->GetStatus()
             << "\nPending exception:\n"
-            << (self->GetException(NULL) != NULL ? self->GetException(NULL)->Dump() : "");
+            << (self->GetException(nullptr) != nullptr ? self->GetException(nullptr)->Dump() : "");
         ObjectLock<mirror::Class> lock(self, klass);
         // Initialization failed because the super-class is erroneous.
         klass->SetStatus(mirror::Class::kStatusError, self);
@@ -4237,7 +4237,7 @@
 
   if (klass->NumStaticFields() > 0) {
     const DexFile::ClassDef* dex_class_def = klass->GetClassDef();
-    CHECK(dex_class_def != NULL);
+    CHECK(dex_class_def != nullptr);
     const DexFile& dex_file = klass->GetDexFile();
     StackHandleScope<3> hs(self);
     Handle<mirror::ClassLoader> class_loader(hs.NewHandle(klass->GetClassLoader()));
@@ -4264,10 +4264,10 @@
   }
 
   mirror::ArtMethod* clinit = klass->FindClassInitializer();
-  if (clinit != NULL) {
+  if (clinit != nullptr) {
     CHECK(can_init_statics);
     JValue result;
-    clinit->Invoke(self, NULL, 0, &result, "V");
+    clinit->Invoke(self, nullptr, 0, &result, "V");
   }
 
   self->AllowThreadSuspension();
@@ -4302,7 +4302,7 @@
   return success;
 }
 
-bool ClassLinker::WaitForInitializeClass(ConstHandle<mirror::Class> klass, Thread* self,
+bool ClassLinker::WaitForInitializeClass(Handle<mirror::Class> klass, Thread* self,
                                          ObjectLock<mirror::Class>& lock)
     SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
   while (true) {
@@ -4342,14 +4342,14 @@
   LOG(FATAL) << "Not Reached" << PrettyClass(klass.Get());
 }
 
-bool ClassLinker::ValidateSuperClassDescriptors(ConstHandle<mirror::Class> klass) {
+bool ClassLinker::ValidateSuperClassDescriptors(Handle<mirror::Class> klass) {
   if (klass->IsInterface()) {
     return true;
   }
   // Begin with the methods local to the superclass.
   StackHandleScope<2> hs(Thread::Current());
-  MethodHelper mh(hs.NewHandle<mirror::ArtMethod>(nullptr));
-  MethodHelper super_mh(hs.NewHandle<mirror::ArtMethod>(nullptr));
+  MutableMethodHelper mh(hs.NewHandle<mirror::ArtMethod>(nullptr));
+  MutableMethodHelper super_mh(hs.NewHandle<mirror::ArtMethod>(nullptr));
   if (klass->HasSuperClass() &&
       klass->GetClassLoader() != klass->GetSuperClass()->GetClassLoader()) {
     for (int i = klass->GetSuperClass()->GetVTableLength() - 1; i >= 0; --i) {
@@ -4387,8 +4387,8 @@
   return true;
 }
 
-bool ClassLinker::EnsureInitialized(Thread* self, ConstHandle<mirror::Class> c,
-                                    bool can_init_fields, bool can_init_parents) {
+bool ClassLinker::EnsureInitialized(Thread* self, Handle<mirror::Class> c, bool can_init_fields,
+                                    bool can_init_parents) {
   DCHECK(c.Get() != nullptr);
   if (c->IsInitialized()) {
     EnsurePreverifiedMethods(c);
@@ -4443,8 +4443,8 @@
   }
 }
 
-bool ClassLinker::LinkClass(Thread* self, const char* descriptor, ConstHandle<mirror::Class> klass,
-                            ConstHandle<mirror::ObjectArray<mirror::Class>> interfaces,
+bool ClassLinker::LinkClass(Thread* self, const char* descriptor, Handle<mirror::Class> klass,
+                            Handle<mirror::ObjectArray<mirror::Class>> interfaces,
                             mirror::Class** new_class) {
   CHECK_EQ(mirror::Class::kStatusLoaded, klass->GetStatus());
 
@@ -4481,7 +4481,7 @@
     CHECK(!klass->IsResolved());
     // Retire the temporary class and create the correctly sized resolved class.
     *new_class = klass->CopyOf(self, class_size);
-    if (UNLIKELY(*new_class == NULL)) {
+    if (UNLIKELY(*new_class == nullptr)) {
       CHECK(self->IsExceptionPending());  // Expect an OOME.
       klass->SetStatus(mirror::Class::kStatusError, self);
       return false;
@@ -4495,7 +4495,7 @@
     FixupTemporaryDeclaringClass(klass.Get(), new_class_h.Get());
 
     mirror::Class* existing = UpdateClass(descriptor, new_class_h.Get(), Hash(descriptor));
-    CHECK(existing == NULL || existing == klass.Get());
+    CHECK(existing == nullptr || existing == klass.Get());
 
     // This will notify waiters on temp class that saw the not yet resolved class in the
     // class_table_ during EnsureResolved.
@@ -4509,13 +4509,13 @@
   return true;
 }
 
-bool ClassLinker::LoadSuperAndInterfaces(ConstHandle<mirror::Class> klass, const DexFile& dex_file) {
+bool ClassLinker::LoadSuperAndInterfaces(Handle<mirror::Class> klass, const DexFile& dex_file) {
   CHECK_EQ(mirror::Class::kStatusIdx, klass->GetStatus());
   const DexFile::ClassDef& class_def = dex_file.GetClassDef(klass->GetDexClassDefIndex());
   uint16_t super_class_idx = class_def.superclass_idx_;
   if (super_class_idx != DexFile::kDexNoIndex16) {
     mirror::Class* super_class = ResolveType(dex_file, super_class_idx, klass.Get());
-    if (super_class == NULL) {
+    if (super_class == nullptr) {
       DCHECK(Thread::Current()->IsExceptionPending());
       return false;
     }
@@ -4530,11 +4530,11 @@
     klass->SetSuperClass(super_class);
   }
   const DexFile::TypeList* interfaces = dex_file.GetInterfacesList(class_def);
-  if (interfaces != NULL) {
+  if (interfaces != nullptr) {
     for (size_t i = 0; i < interfaces->Size(); i++) {
       uint16_t idx = interfaces->GetTypeItem(i).type_idx_;
       mirror::Class* interface = ResolveType(dex_file, idx, klass.Get());
-      if (interface == NULL) {
+      if (interface == nullptr) {
         DCHECK(Thread::Current()->IsExceptionPending());
         return false;
       }
@@ -4549,21 +4549,21 @@
     }
   }
   // Mark the class as loaded.
-  klass->SetStatus(mirror::Class::kStatusLoaded, NULL);
+  klass->SetStatus(mirror::Class::kStatusLoaded, nullptr);
   return true;
 }
 
-bool ClassLinker::LinkSuperClass(ConstHandle<mirror::Class> klass) {
+bool ClassLinker::LinkSuperClass(Handle<mirror::Class> klass) {
   CHECK(!klass->IsPrimitive());
   mirror::Class* super = klass->GetSuperClass();
   if (klass.Get() == GetClassRoot(kJavaLangObject)) {
-    if (super != NULL) {
+    if (super != nullptr) {
       ThrowClassFormatError(klass.Get(), "java.lang.Object must not have a superclass");
       return false;
     }
     return true;
   }
-  if (super == NULL) {
+  if (super == nullptr) {
     ThrowLinkageError(klass.Get(), "No superclass defined for class %s",
                       PrettyDescriptor(klass.Get()).c_str());
     return false;
@@ -4604,7 +4604,7 @@
 
   if (kIsDebugBuild) {
     // Ensure super classes are fully resolved prior to resolving fields..
-    while (super != NULL) {
+    while (super != nullptr) {
       CHECK(super->IsResolved());
       super = super->GetSuperClass();
     }
@@ -4613,8 +4613,8 @@
 }
 
 // Populate the class vtable and itable. Compute return type indices.
-bool ClassLinker::LinkMethods(Thread* self, ConstHandle<mirror::Class> klass,
-                              ConstHandle<mirror::ObjectArray<mirror::Class>> interfaces) {
+bool ClassLinker::LinkMethods(Thread* self, Handle<mirror::Class> klass,
+                              Handle<mirror::ObjectArray<mirror::Class>> interfaces) {
   self->AllowThreadSuspension();
   if (klass->IsInterface()) {
     // No vtable.
@@ -4635,7 +4635,7 @@
   return true;
 }
 
-bool ClassLinker::LinkVirtualMethods(Thread* self, ConstHandle<mirror::Class> klass) {
+bool ClassLinker::LinkVirtualMethods(Thread* self, Handle<mirror::Class> klass) {
   if (klass->HasSuperClass()) {
     uint32_t max_count = klass->NumVirtualMethods() +
         klass->GetSuperClass()->GetVTableLength();
@@ -4643,7 +4643,7 @@
     CHECK_LE(actual_count, max_count);
     StackHandleScope<4> hs(self);
     Handle<mirror::Class> super_class(hs.NewHandle(klass->GetSuperClass()));
-    Handle<mirror::ObjectArray<mirror::ArtMethod>> vtable;
+    MutableHandle<mirror::ObjectArray<mirror::ArtMethod>> vtable;
     if (super_class->ShouldHaveEmbeddedImtAndVTable()) {
       vtable = hs.NewHandle(AllocArtMethodArray(self, max_count));
       if (UNLIKELY(vtable.Get() == nullptr)) {
@@ -4664,8 +4664,8 @@
     }
 
     // See if any of our virtual methods override the superclass.
-    MethodHelper local_mh(hs.NewHandle<mirror::ArtMethod>(nullptr));
-    MethodHelper super_mh(hs.NewHandle<mirror::ArtMethod>(nullptr));
+    MutableMethodHelper local_mh(hs.NewHandle<mirror::ArtMethod>(nullptr));
+    MutableMethodHelper super_mh(hs.NewHandle<mirror::ArtMethod>(nullptr));
     for (size_t i = 0; i < klass->NumVirtualMethods(); ++i) {
       mirror::ArtMethod* local_method = klass->GetVirtualMethodDuringLinking(i);
       local_mh.ChangeMethod(local_method);
@@ -4707,7 +4707,7 @@
     CHECK_LE(actual_count, max_count);
     if (actual_count < max_count) {
       vtable.Assign(vtable->CopyOf(self, actual_count));
-      if (UNLIKELY(vtable.Get() == NULL)) {
+      if (UNLIKELY(vtable.Get() == nullptr)) {
         CHECK(self->IsExceptionPending());  // OOME.
         return false;
       }
@@ -4723,7 +4723,7 @@
     StackHandleScope<1> hs(self);
     Handle<mirror::ObjectArray<mirror::ArtMethod>>
         vtable(hs.NewHandle(AllocArtMethodArray(self, num_virtual_methods)));
-    if (UNLIKELY(vtable.Get() == NULL)) {
+    if (UNLIKELY(vtable.Get() == nullptr)) {
       CHECK(self->IsExceptionPending());  // OOME.
       return false;
     }
@@ -4737,8 +4737,8 @@
   return true;
 }
 
-bool ClassLinker::LinkInterfaceMethods(ConstHandle<mirror::Class> klass,
-                                       ConstHandle<mirror::ObjectArray<mirror::Class>> interfaces) {
+bool ClassLinker::LinkInterfaceMethods(Handle<mirror::Class> klass,
+                                       Handle<mirror::ObjectArray<mirror::Class>> interfaces) {
   Thread* const self = Thread::Current();
   Runtime* const runtime = Runtime::Current();
   // Set the imt table to be all conflicts by default.
@@ -4761,7 +4761,7 @@
   if (ifcount == 0) {
     // Class implements no interfaces.
     DCHECK_EQ(klass->GetIfTableCount(), 0);
-    DCHECK(klass->GetIfTable() == NULL);
+    DCHECK(klass->GetIfTable() == nullptr);
     return true;
   }
   if (ifcount == super_ifcount) {
@@ -4781,8 +4781,8 @@
     }
   }
   StackHandleScope<5> hs(self);
-  Handle<mirror::IfTable> iftable(hs.NewHandle(AllocIfTable(self, ifcount)));
-  if (UNLIKELY(iftable.Get() == NULL)) {
+  MutableHandle<mirror::IfTable> iftable(hs.NewHandle(AllocIfTable(self, ifcount)));
+  if (UNLIKELY(iftable.Get() == nullptr)) {
     CHECK(self->IsExceptionPending());  // OOME.
     return false;
   }
@@ -4800,7 +4800,7 @@
     mirror::Class* interface =
         interfaces.Get() == nullptr ? mirror::Class::GetDirectInterface(self, klass, i) :
             interfaces->Get(i);
-    DCHECK(interface != NULL);
+    DCHECK(interface != nullptr);
     if (!interface->IsInterface()) {
       std::string temp;
       ThrowIncompatibleClassChangeError(klass.Get(), "Class %s implements non-interface class %s",
@@ -4841,7 +4841,7 @@
   // Shrink iftable in case duplicates were found
   if (idx < ifcount) {
     iftable.Assign(down_cast<mirror::IfTable*>(iftable->CopyOf(self, idx * mirror::IfTable::kMax)));
-    if (UNLIKELY(iftable.Get() == NULL)) {
+    if (UNLIKELY(iftable.Get() == nullptr)) {
       CHECK(self->IsExceptionPending());  // OOME.
       return false;
     }
@@ -4860,12 +4860,12 @@
   bool imtable_changed = false;
   Handle<mirror::ObjectArray<mirror::ArtMethod>> imtable(
       hs.NewHandle(AllocArtMethodArray(self, mirror::Class::kImtSize)));
-  if (UNLIKELY(imtable.Get() == NULL)) {
+  if (UNLIKELY(imtable.Get() == nullptr)) {
     CHECK(self->IsExceptionPending());  // OOME.
     return false;
   }
-  MethodHelper interface_mh(hs.NewHandle<mirror::ArtMethod>(nullptr));
-  MethodHelper vtable_mh(hs.NewHandle<mirror::ArtMethod>(nullptr));
+  MutableMethodHelper interface_mh(hs.NewHandle<mirror::ArtMethod>(nullptr));
+  MutableMethodHelper vtable_mh(hs.NewHandle<mirror::ArtMethod>(nullptr));
   size_t max_miranda_methods = 0;  // The max size of miranda_list.
   for (size_t i = 0; i < ifcount; ++i) {
     max_miranda_methods += iftable->GetInterface(i)->NumVirtualMethods();
@@ -4912,7 +4912,7 @@
             method_array->Set<false>(j, vtable_mh.Get());
             // Place method in imt if entry is empty, place conflict otherwise.
             uint32_t imt_index = interface_mh.Get()->GetDexMethodIndex() % mirror::Class::kImtSize;
-            if (imtable->Get(imt_index) == NULL) {
+            if (imtable->Get(imt_index) == nullptr) {
               imtable->Set<false>(imt_index, vtable_mh.Get());
               imtable_changed = true;
             } else {
@@ -4933,10 +4933,10 @@
               break;
             }
           }
-          if (miranda_method.Get() == NULL) {
+          if (miranda_method.Get() == nullptr) {
             // Point the interface table at a phantom slot.
             miranda_method.Assign(down_cast<mirror::ArtMethod*>(interface_mh.Get()->Clone(self)));
-            if (UNLIKELY(miranda_method.Get() == NULL)) {
+            if (UNLIKELY(miranda_method.Get() == nullptr)) {
               CHECK(self->IsExceptionPending());  // OOME.
               return false;
             }
@@ -4952,7 +4952,7 @@
     // Fill in empty entries in interface method table with conflict.
     mirror::ArtMethod* imt_conflict_method = runtime->GetImtConflictMethod();
     for (size_t i = 0; i < mirror::Class::kImtSize; i++) {
-      if (imtable->Get(i) == NULL) {
+      if (imtable->Get(i) == nullptr) {
         imtable->Set<false>(i, imt_conflict_method);
       }
     }
@@ -4967,20 +4967,20 @@
     } else {
       virtuals = klass->GetVirtualMethods()->CopyOf(self, new_method_count);
     }
-    if (UNLIKELY(virtuals == NULL)) {
+    if (UNLIKELY(virtuals == nullptr)) {
       CHECK(self->IsExceptionPending());  // OOME.
       return false;
     }
     klass->SetVirtualMethods(virtuals);
 
     StackHandleScope<1> hs(self);
-    Handle<mirror::ObjectArray<mirror::ArtMethod>> vtable(
+    MutableHandle<mirror::ObjectArray<mirror::ArtMethod>> vtable(
         hs.NewHandle(klass->GetVTableDuringLinking()));
-    CHECK(vtable.Get() != NULL);
+    CHECK(vtable.Get() != nullptr);
     int old_vtable_count = vtable->GetLength();
     int new_vtable_count = old_vtable_count + miranda_list_size;
     vtable.Assign(vtable->CopyOf(self, new_vtable_count));
-    if (UNLIKELY(vtable.Get() == NULL)) {
+    if (UNLIKELY(vtable.Get() == nullptr)) {
       CHECK(self->IsExceptionPending());  // OOME.
       return false;
     }
@@ -4998,7 +4998,7 @@
 
   mirror::ObjectArray<mirror::ArtMethod>* vtable = klass->GetVTableDuringLinking();
   for (int i = 0; i < vtable->GetLength(); ++i) {
-    CHECK(vtable->Get(i) != NULL);
+    CHECK(vtable->Get(i) != nullptr);
   }
 
   self->AllowThreadSuspension();
@@ -5006,13 +5006,13 @@
   return true;
 }
 
-bool ClassLinker::LinkInstanceFields(Thread* self, ConstHandle<mirror::Class> klass) {
-  CHECK(klass.Get() != NULL);
+bool ClassLinker::LinkInstanceFields(Thread* self, Handle<mirror::Class> klass) {
+  CHECK(klass.Get() != nullptr);
   return LinkFields(self, klass, false, nullptr);
 }
 
-bool ClassLinker::LinkStaticFields(Thread* self, ConstHandle<mirror::Class> klass, size_t* class_size) {
-  CHECK(klass.Get() != NULL);
+bool ClassLinker::LinkStaticFields(Thread* self, Handle<mirror::Class> klass, size_t* class_size) {
+  CHECK(klass.Get() != nullptr);
   return LinkFields(self, klass, true, class_size);
 }
 
@@ -5043,7 +5043,7 @@
   }
 };
 
-bool ClassLinker::LinkFields(Thread* self, ConstHandle<mirror::Class> klass, bool is_static,
+bool ClassLinker::LinkFields(Thread* self, Handle<mirror::Class> klass, bool is_static,
                              size_t* class_size) {
   self->AllowThreadSuspension();
   size_t num_fields =
@@ -5064,14 +5064,14 @@
     field_offset = MemberOffset(base);
   } else {
     mirror::Class* super_class = klass->GetSuperClass();
-    if (super_class != NULL) {
+    if (super_class != nullptr) {
       CHECK(super_class->IsResolved())
           << PrettyClass(klass.Get()) << " " << PrettyClass(super_class);
       field_offset = MemberOffset(super_class->GetObjectSize());
     }
   }
 
-  CHECK_EQ(num_fields == 0, fields == NULL) << PrettyClass(klass.Get());
+  CHECK_EQ(num_fields == 0, fields == nullptr) << PrettyClass(klass.Get());
 
   // we want a relatively stable order so that adding new fields
   // minimizes disruption of C++ version such as Class and Method.
@@ -5080,7 +5080,7 @@
       "Naked ArtField references in deque");
   for (size_t i = 0; i < num_fields; i++) {
     mirror::ArtField* f = fields->Get(i);
-    CHECK(f != NULL) << PrettyClass(klass.Get());
+    CHECK(f != nullptr) << PrettyClass(klass.Get());
     grouped_and_sorted_fields.push_back(f);
   }
   std::sort(grouped_and_sorted_fields.begin(), grouped_and_sorted_fields.end(),
@@ -5189,10 +5189,10 @@
 
 //  Set the bitmap of reference offsets, refOffsets, from the ifields
 //  list.
-void ClassLinker::CreateReferenceInstanceOffsets(ConstHandle<mirror::Class> klass) {
+void ClassLinker::CreateReferenceInstanceOffsets(Handle<mirror::Class> klass) {
   uint32_t reference_offsets = 0;
   mirror::Class* super_class = klass->GetSuperClass();
-  if (super_class != NULL) {
+  if (super_class != nullptr) {
     reference_offsets = super_class->GetReferenceInstanceOffsets();
     // If our superclass overflowed, we don't stand a chance.
     if (reference_offsets == CLASS_WALK_SUPER) {
@@ -5203,7 +5203,7 @@
   CreateReferenceOffsets(klass, reference_offsets);
 }
 
-void ClassLinker::CreateReferenceOffsets(ConstHandle<mirror::Class> klass,
+void ClassLinker::CreateReferenceOffsets(Handle<mirror::Class> klass,
                                          uint32_t reference_offsets) {
   size_t num_reference_fields = klass->NumReferenceInstanceFieldsDuringLinking();
   mirror::ObjectArray<mirror::ArtField>* fields = klass->GetIFields();
@@ -5228,10 +5228,10 @@
 }
 
 mirror::String* ClassLinker::ResolveString(const DexFile& dex_file, uint32_t string_idx,
-                                           ConstHandle<mirror::DexCache> dex_cache) {
+                                           Handle<mirror::DexCache> dex_cache) {
   DCHECK(dex_cache.Get() != nullptr);
   mirror::String* resolved = dex_cache->GetResolvedString(string_idx);
-  if (resolved != NULL) {
+  if (resolved != nullptr) {
     return resolved;
   }
   uint32_t utf16_length;
@@ -5250,15 +5250,15 @@
 }
 
 mirror::Class* ClassLinker::ResolveType(const DexFile& dex_file, uint16_t type_idx,
-                                        ConstHandle<mirror::DexCache> dex_cache,
-                                        ConstHandle<mirror::ClassLoader> class_loader) {
-  DCHECK(dex_cache.Get() != NULL);
+                                        Handle<mirror::DexCache> dex_cache,
+                                        Handle<mirror::ClassLoader> class_loader) {
+  DCHECK(dex_cache.Get() != nullptr);
   mirror::Class* resolved = dex_cache->GetResolvedType(type_idx);
-  if (resolved == NULL) {
+  if (resolved == nullptr) {
     Thread* self = Thread::Current();
     const char* descriptor = dex_file.StringByTypeIdx(type_idx);
     resolved = FindClass(self, descriptor, class_loader);
-    if (resolved != NULL) {
+    if (resolved != nullptr) {
       // TODO: we used to throw here if resolved's class loader was not the
       //       boot class loader. This was to permit different classes with the
       //       same name to be loaded simultaneously by different loaders
@@ -5270,22 +5270,22 @@
       StackHandleScope<1> hs(self);
       Handle<mirror::Throwable> cause(hs.NewHandle(self->GetException(nullptr)));
       if (cause->InstanceOf(GetClassRoot(kJavaLangClassNotFoundException))) {
-        DCHECK(resolved == NULL);  // No Handle needed to preserve resolved.
+        DCHECK(resolved == nullptr);  // No Handle needed to preserve resolved.
         self->ClearException();
         ThrowNoClassDefFoundError("Failed resolution of: %s", descriptor);
-        self->GetException(NULL)->SetCause(cause.Get());
+        self->GetException(nullptr)->SetCause(cause.Get());
       }
     }
   }
-  DCHECK((resolved == NULL) || resolved->IsResolved() || resolved->IsErroneous())
+  DCHECK((resolved == nullptr) || resolved->IsResolved() || resolved->IsErroneous())
           << PrettyDescriptor(resolved) << " " << resolved->GetStatus();
   return resolved;
 }
 
 mirror::ArtMethod* ClassLinker::ResolveMethod(const DexFile& dex_file, uint32_t method_idx,
-                                              ConstHandle<mirror::DexCache> dex_cache,
-                                              ConstHandle<mirror::ClassLoader> class_loader,
-                                              ConstHandle<mirror::ArtMethod> referrer,
+                                              Handle<mirror::DexCache> dex_cache,
+                                              Handle<mirror::ClassLoader> class_loader,
+                                              Handle<mirror::ArtMethod> referrer,
                                               InvokeType type) {
   DCHECK(dex_cache.Get() != nullptr);
   // Check for hit in the dex cache.
@@ -5436,8 +5436,8 @@
 }
 
 mirror::ArtField* ClassLinker::ResolveField(const DexFile& dex_file, uint32_t field_idx,
-                                            ConstHandle<mirror::DexCache> dex_cache,
-                                            ConstHandle<mirror::ClassLoader> class_loader,
+                                            Handle<mirror::DexCache> dex_cache,
+                                            Handle<mirror::ClassLoader> class_loader,
                                             bool is_static) {
   DCHECK(dex_cache.Get() != nullptr);
   mirror::ArtField* resolved = dex_cache->GetResolvedField(field_idx);
@@ -5470,7 +5470,7 @@
     }
     if (resolved == nullptr) {
       ThrowNoSuchFieldError(is_static ? "static " : "instance ", klass.Get(), type, name);
-      return NULL;
+      return nullptr;
     }
   }
   dex_cache->SetResolvedField(field_idx, resolved);
@@ -5479,8 +5479,8 @@
 
 mirror::ArtField* ClassLinker::ResolveFieldJLS(const DexFile& dex_file,
                                                uint32_t field_idx,
-                                               ConstHandle<mirror::DexCache> dex_cache,
-                                               ConstHandle<mirror::ClassLoader> class_loader) {
+                                               Handle<mirror::DexCache> dex_cache,
+                                               Handle<mirror::ClassLoader> class_loader) {
   DCHECK(dex_cache.Get() != nullptr);
   mirror::ArtField* resolved = dex_cache->GetResolvedField(field_idx);
   if (resolved != nullptr) {
@@ -5491,16 +5491,16 @@
   StackHandleScope<1> hs(self);
   Handle<mirror::Class> klass(
       hs.NewHandle(ResolveType(dex_file, field_id.class_idx_, dex_cache, class_loader)));
-  if (klass.Get() == NULL) {
+  if (klass.Get() == nullptr) {
     DCHECK(Thread::Current()->IsExceptionPending());
-    return NULL;
+    return nullptr;
   }
 
   StringPiece name(dex_file.StringDataByIdx(field_id.name_idx_));
   StringPiece type(dex_file.StringDataByIdx(
       dex_file.GetTypeId(field_id.type_idx_).descriptor_idx_));
   resolved = mirror::Class::FindField(self, klass, name, type);
-  if (resolved != NULL) {
+  if (resolved != nullptr) {
     dex_cache->SetResolvedField(field_idx, resolved);
   } else {
     ThrowNoSuchFieldError("", klass.Get(), type, name);
@@ -5566,12 +5566,12 @@
 void ClassLinker::SetClassRoot(ClassRoot class_root, mirror::Class* klass) {
   DCHECK(!init_done_);
 
-  DCHECK(klass != NULL);
-  DCHECK(klass->GetClassLoader() == NULL);
+  DCHECK(klass != nullptr);
+  DCHECK(klass->GetClassLoader() == nullptr);
 
   mirror::ObjectArray<mirror::Class>* class_roots = class_roots_.Read();
-  DCHECK(class_roots != NULL);
-  DCHECK(class_roots->Get(class_root) == NULL);
+  DCHECK(class_roots != nullptr);
+  DCHECK(class_roots->Get(class_root) == nullptr);
   class_roots->Set<false>(class_root, klass);
 }
 
diff --git a/runtime/class_linker.h b/runtime/class_linker.h
index b6c62a9..3ea74e0 100644
--- a/runtime/class_linker.h
+++ b/runtime/class_linker.h
@@ -48,7 +48,7 @@
   class StackTraceElement;
 }  // namespace mirror
 
-template<class T> class ConstHandle;
+template<class T> class Handle;
 class InternTable;
 template<class T> class ObjectLock;
 class ScopedObjectAccessAlreadyRunnable;
@@ -73,13 +73,13 @@
   // Finds a class by its descriptor, loading it if necessary.
   // If class_loader is null, searches boot_class_path_.
   mirror::Class* FindClass(Thread* self, const char* descriptor,
-                           ConstHandle<mirror::ClassLoader> class_loader)
+                           Handle<mirror::ClassLoader> class_loader)
       SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
 
   // Find a class in the path class loader, loading it if necessary.
   mirror::Class* FindClassInPathClassLoader(ScopedObjectAccessAlreadyRunnable& soa,
                                             Thread* self, const char* descriptor,
-                                            ConstHandle<mirror::ClassLoader> class_loader)
+                                            Handle<mirror::ClassLoader> class_loader)
       SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
 
   // Finds a class by its descriptor using the "system" class loader, ie by searching the
@@ -98,7 +98,7 @@
 
   // Define a new a class based on a ClassDef from a DexFile
   mirror::Class* DefineClass(Thread* self, const char* descriptor,
-                             ConstHandle<mirror::ClassLoader> class_loader,
+                             Handle<mirror::ClassLoader> class_loader,
                              const DexFile& dex_file, const DexFile::ClassDef& dex_class_def)
       SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
 
@@ -142,7 +142,7 @@
   // Resolve a String with the given index from the DexFile, storing the
   // result in the DexCache.
   mirror::String* ResolveString(const DexFile& dex_file, uint32_t string_idx,
-                                ConstHandle<mirror::DexCache> dex_cache)
+                                Handle<mirror::DexCache> dex_cache)
       SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
 
   // Resolve a Type with the given index from the DexFile, storing the
@@ -165,8 +165,8 @@
   // type, since it may be referenced from but not contained within
   // the given DexFile.
   mirror::Class* ResolveType(const DexFile& dex_file, uint16_t type_idx,
-                             ConstHandle<mirror::DexCache> dex_cache,
-                             ConstHandle<mirror::ClassLoader> class_loader)
+                             Handle<mirror::DexCache> dex_cache,
+                             Handle<mirror::ClassLoader> class_loader)
       SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
 
   // Resolve a method with a given ID from the DexFile, storing the
@@ -176,9 +176,9 @@
   // virtual method.
   mirror::ArtMethod* ResolveMethod(const DexFile& dex_file,
                                    uint32_t method_idx,
-                                   ConstHandle<mirror::DexCache> dex_cache,
-                                   ConstHandle<mirror::ClassLoader> class_loader,
-                                   ConstHandle<mirror::ArtMethod> referrer,
+                                   Handle<mirror::DexCache> dex_cache,
+                                   Handle<mirror::ClassLoader> class_loader,
+                                   Handle<mirror::ArtMethod> referrer,
                                    InvokeType type)
       SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
 
@@ -202,8 +202,8 @@
   // field.
   mirror::ArtField* ResolveField(const DexFile& dex_file,
                                  uint32_t field_idx,
-                                 ConstHandle<mirror::DexCache> dex_cache,
-                                 ConstHandle<mirror::ClassLoader> class_loader,
+                                 Handle<mirror::DexCache> dex_cache,
+                                 Handle<mirror::ClassLoader> class_loader,
                                  bool is_static)
       SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
 
@@ -212,8 +212,8 @@
   // in ResolveType. No is_static argument is provided so that Java
   // field resolution semantics are followed.
   mirror::ArtField* ResolveFieldJLS(const DexFile& dex_file, uint32_t field_idx,
-                                    ConstHandle<mirror::DexCache> dex_cache,
-                                    ConstHandle<mirror::ClassLoader> class_loader)
+                                    Handle<mirror::DexCache> dex_cache,
+                                    Handle<mirror::ClassLoader> class_loader)
       SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
 
   // Get shorty from method index without resolution. Used to do handlerization.
@@ -223,7 +223,7 @@
   // Returns true on success, false if there's an exception pending.
   // can_run_clinit=false allows the compiler to attempt to init a class,
   // given the restriction that no <clinit> execution is possible.
-  bool EnsureInitialized(Thread* self, ConstHandle<mirror::Class> c, bool can_init_fields,
+  bool EnsureInitialized(Thread* self, Handle<mirror::Class> c, bool can_init_fields,
                          bool can_init_parents)
       SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
 
@@ -234,7 +234,7 @@
   void RegisterDexFile(const DexFile& dex_file)
       LOCKS_EXCLUDED(dex_lock_)
       SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
-  void RegisterDexFile(const DexFile& dex_file, ConstHandle<mirror::DexCache> dex_cache)
+  void RegisterDexFile(const DexFile& dex_file, Handle<mirror::DexCache> dex_cache)
       LOCKS_EXCLUDED(dex_lock_)
       SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
 
@@ -326,13 +326,13 @@
                                                                               size_t length)
       SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
 
-  void VerifyClass(Thread* self, ConstHandle<mirror::Class> klass)
+  void VerifyClass(Thread* self, Handle<mirror::Class> klass)
       SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
   bool VerifyClassUsingOatFile(const DexFile& dex_file, mirror::Class* klass,
                                mirror::Class::Status& oat_file_class_status)
       SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
   void ResolveClassExceptionHandlerTypes(const DexFile& dex_file,
-                                         ConstHandle<mirror::Class> klass)
+                                         Handle<mirror::Class> klass)
       SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
   void ResolveMethodExceptionHandlerTypes(const DexFile& dex_file, mirror::ArtMethod* klass)
       SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
@@ -445,12 +445,12 @@
 
 
   mirror::Class* CreateArrayClass(Thread* self, const char* descriptor,
-                                  ConstHandle<mirror::ClassLoader> class_loader)
+                                  Handle<mirror::ClassLoader> class_loader)
       SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
 
   void AppendToBootClassPath(Thread* self, const DexFile& dex_file)
       SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
-  void AppendToBootClassPath(const DexFile& dex_file, ConstHandle<mirror::DexCache> dex_cache)
+  void AppendToBootClassPath(const DexFile& dex_file, Handle<mirror::DexCache> dex_cache)
       SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
 
   // Precomputes size needed for Class, in the case of a non-temporary class this size must be
@@ -459,20 +459,20 @@
                                             const DexFile::ClassDef& dex_class_def);
 
   void LoadClass(Thread* self, const DexFile& dex_file, const DexFile::ClassDef& dex_class_def,
-                 ConstHandle<mirror::Class> klass, mirror::ClassLoader* class_loader)
+                 Handle<mirror::Class> klass, mirror::ClassLoader* class_loader)
       SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
   void LoadClassMembers(Thread* self, const DexFile& dex_file, const byte* class_data,
-                        ConstHandle<mirror::Class> klass, mirror::ClassLoader* class_loader,
+                        Handle<mirror::Class> klass, mirror::ClassLoader* class_loader,
                         const OatFile::OatClass* oat_class)
       SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
 
   void LoadField(const DexFile& dex_file, const ClassDataItemIterator& it,
-                 ConstHandle<mirror::Class> klass, ConstHandle<mirror::ArtField> dst)
+                 Handle<mirror::Class> klass, Handle<mirror::ArtField> dst)
       SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
 
   mirror::ArtMethod* LoadMethod(Thread* self, const DexFile& dex_file,
                                 const ClassDataItemIterator& dex_method,
-                                ConstHandle<mirror::Class> klass)
+                                Handle<mirror::Class> klass)
       SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
 
   void FixupStaticTrampolines(mirror::Class* klass) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
@@ -482,23 +482,23 @@
   OatFile::OatClass FindOatClass(const DexFile& dex_file, uint16_t class_def_idx, bool* found)
       SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
 
-  void RegisterDexFileLocked(const DexFile& dex_file, ConstHandle<mirror::DexCache> dex_cache)
+  void RegisterDexFileLocked(const DexFile& dex_file, Handle<mirror::DexCache> dex_cache)
       EXCLUSIVE_LOCKS_REQUIRED(dex_lock_)
       SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
   bool IsDexFileRegisteredLocked(const DexFile& dex_file)
       SHARED_LOCKS_REQUIRED(dex_lock_, Locks::mutator_lock_);
 
-  bool InitializeClass(Thread* self, ConstHandle<mirror::Class> klass, bool can_run_clinit,
+  bool InitializeClass(Thread* self, Handle<mirror::Class> klass, bool can_run_clinit,
                        bool can_init_parents)
       SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
-  bool WaitForInitializeClass(ConstHandle<mirror::Class> klass, Thread* self,
+  bool WaitForInitializeClass(Handle<mirror::Class> klass, Thread* self,
                               ObjectLock<mirror::Class>& lock);
-  bool ValidateSuperClassDescriptors(ConstHandle<mirror::Class> klass)
+  bool ValidateSuperClassDescriptors(Handle<mirror::Class> klass)
       SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
 
   bool IsSameDescriptorInDifferentClassContexts(Thread* self, const char* descriptor,
-                                                ConstHandle<mirror::ClassLoader> class_loader1,
-                                                ConstHandle<mirror::ClassLoader> class_loader2)
+                                                Handle<mirror::ClassLoader> class_loader1,
+                                                Handle<mirror::ClassLoader> class_loader2)
       SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
 
   bool IsSameMethodSignatureInDifferentClassContexts(Thread* self, mirror::ArtMethod* method,
@@ -506,41 +506,40 @@
                                                      mirror::Class* klass2)
       SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
 
-  bool LinkClass(Thread* self, const char* descriptor, ConstHandle<mirror::Class> klass,
-                 ConstHandle<mirror::ObjectArray<mirror::Class>> interfaces,
+  bool LinkClass(Thread* self, const char* descriptor, Handle<mirror::Class> klass,
+                 Handle<mirror::ObjectArray<mirror::Class>> interfaces,
                  mirror::Class** new_class)
       SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
 
-  bool LinkSuperClass(ConstHandle<mirror::Class> klass)
+  bool LinkSuperClass(Handle<mirror::Class> klass)
       SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
 
-  bool LoadSuperAndInterfaces(ConstHandle<mirror::Class> klass, const DexFile& dex_file)
+  bool LoadSuperAndInterfaces(Handle<mirror::Class> klass, const DexFile& dex_file)
       SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
 
-  bool LinkMethods(Thread* self, ConstHandle<mirror::Class> klass,
-                   ConstHandle<mirror::ObjectArray<mirror::Class>> interfaces)
+  bool LinkMethods(Thread* self, Handle<mirror::Class> klass,
+                   Handle<mirror::ObjectArray<mirror::Class>> interfaces)
       SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
 
-  bool LinkVirtualMethods(Thread* self, ConstHandle<mirror::Class> klass)
+  bool LinkVirtualMethods(Thread* self, Handle<mirror::Class> klass)
       SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
 
-  bool LinkInterfaceMethods(ConstHandle<mirror::Class> klass,
-                            ConstHandle<mirror::ObjectArray<mirror::Class>> interfaces)
+  bool LinkInterfaceMethods(Handle<mirror::Class> klass,
+                            Handle<mirror::ObjectArray<mirror::Class>> interfaces)
       SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
 
-  bool LinkStaticFields(Thread* self, ConstHandle<mirror::Class> klass, size_t* class_size)
+  bool LinkStaticFields(Thread* self, Handle<mirror::Class> klass, size_t* class_size)
       SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
-  bool LinkInstanceFields(Thread* self, ConstHandle<mirror::Class> klass)
+  bool LinkInstanceFields(Thread* self, Handle<mirror::Class> klass)
       SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
-  bool LinkFields(Thread* self, ConstHandle<mirror::Class> klass, bool is_static,
-                  size_t* class_size)
+  bool LinkFields(Thread* self, Handle<mirror::Class> klass, bool is_static, size_t* class_size)
       SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
-  void LinkCode(ConstHandle<mirror::ArtMethod> method, const OatFile::OatClass* oat_class,
+  void LinkCode(Handle<mirror::ArtMethod> method, const OatFile::OatClass* oat_class,
                 const DexFile& dex_file, uint32_t dex_method_index, uint32_t method_index)
       SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
-  void CreateReferenceInstanceOffsets(ConstHandle<mirror::Class> klass)
+  void CreateReferenceInstanceOffsets(Handle<mirror::Class> klass)
       SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
-  void CreateReferenceOffsets(ConstHandle<mirror::Class> klass, uint32_t reference_offsets)
+  void CreateReferenceOffsets(Handle<mirror::Class> klass, uint32_t reference_offsets)
       SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
 
   // For use by ImageWriter to find DexCaches for its roots
@@ -632,16 +631,16 @@
                             const uint32_t* dex_location_checksum,
                             std::string* error_msg);
 
-  mirror::ArtMethod* CreateProxyConstructor(Thread* self, ConstHandle<mirror::Class> klass,
+  mirror::ArtMethod* CreateProxyConstructor(Thread* self, Handle<mirror::Class> klass,
                                             mirror::Class* proxy_class)
       SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
-  mirror::ArtMethod* CreateProxyMethod(Thread* self, ConstHandle<mirror::Class> klass,
-                                       ConstHandle<mirror::ArtMethod> prototype)
+  mirror::ArtMethod* CreateProxyMethod(Thread* self, Handle<mirror::Class> klass,
+                                       Handle<mirror::ArtMethod> prototype)
       SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
 
   // Ensures that methods have the kAccPreverified bit set. We use the kAccPreverfied bit on the
   // class access flags to determine whether this has been done before.
-  void EnsurePreverifiedMethods(ConstHandle<mirror::Class> c)
+  void EnsurePreverifiedMethods(Handle<mirror::Class> c)
       SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
 
   mirror::Class* LookupClassFromTableLocked(const char* descriptor,
diff --git a/runtime/class_linker_test.cc b/runtime/class_linker_test.cc
index 273d4c0..613ac66 100644
--- a/runtime/class_linker_test.cc
+++ b/runtime/class_linker_test.cc
@@ -278,10 +278,11 @@
     // Confirm that all instances fields are packed together at the start
     EXPECT_GE(klass->NumInstanceFields(), klass->NumReferenceInstanceFields());
     StackHandleScope<1> hs(Thread::Current());
-    FieldHelper fh(hs.NewHandle<mirror::ArtField>(nullptr));
+    MutableHandle<mirror::ArtField> fhandle = hs.NewHandle<mirror::ArtField>(nullptr);
     for (size_t i = 0; i < klass->NumReferenceInstanceFields(); i++) {
       mirror::ArtField* field = klass->GetInstanceField(i);
-      fh.ChangeField(field);
+      fhandle.Assign(field);
+      FieldHelper fh(fhandle);
       ASSERT_TRUE(!field->IsPrimitiveType());
       mirror::Class* field_type = fh.GetType();
       ASSERT_TRUE(field_type != NULL);
@@ -289,7 +290,8 @@
     }
     for (size_t i = klass->NumReferenceInstanceFields(); i < klass->NumInstanceFields(); i++) {
       mirror::ArtField* field = klass->GetInstanceField(i);
-      fh.ChangeField(field);
+      fhandle.Assign(field);
+      FieldHelper fh(fhandle);
       mirror::Class* field_type = fh.GetType();
       ASSERT_TRUE(field_type != NULL);
       if (!fh.GetField()->IsPrimitiveType() || !field_type->IsPrimitive()) {
diff --git a/runtime/debugger.cc b/runtime/debugger.cc
index efd7cc2..001032c 100644
--- a/runtime/debugger.cc
+++ b/runtime/debugger.cc
@@ -3662,7 +3662,7 @@
   }
 
   // Translate the method through the vtable, unless the debugger wants to suppress it.
-  Handle<mirror::ArtMethod> m(hs.NewHandle(pReq->method));
+  MutableHandle<mirror::ArtMethod> m(hs.NewHandle(pReq->method));
   if ((pReq->options & JDWP::INVOKE_NONVIRTUAL) == 0 && pReq->receiver != nullptr) {
     mirror::ArtMethod* actual_method = pReq->klass->FindVirtualMethodForVirtualOrInterface(m.Get());
     if (actual_method != m.Get()) {
diff --git a/runtime/dex_file.h b/runtime/dex_file.h
index 1cec264..c160253 100644
--- a/runtime/dex_file.h
+++ b/runtime/dex_file.h
@@ -201,6 +201,24 @@
     uint32_t class_data_off_;  // file offset to class_data_item
     uint32_t static_values_off_;  // file offset to EncodedArray
 
+    // Returns the valid access flags, that is, Java modifier bits relevant to the ClassDef type
+    // (class or interface). These are all in the lower 16b and do not contain runtime flags.
+    uint32_t GetJavaAccessFlags() const {
+      // Make sure that none of our runtime-only flags are set.
+      COMPILE_ASSERT((kAccValidClassFlags & kAccJavaFlagsMask) == kAccValidClassFlags,
+                     valid_class_flags_not_subset_of_java_flags);
+      COMPILE_ASSERT((kAccValidInterfaceFlags & kAccJavaFlagsMask) == kAccValidInterfaceFlags,
+                     valid_interface_flags_not_subset_of_java_flags);
+
+      if ((access_flags_ & kAccInterface) != 0) {
+        // Interface.
+        return access_flags_ & kAccValidInterfaceFlags;
+      } else {
+        // Class.
+        return access_flags_ & kAccValidClassFlags;
+      }
+    }
+
    private:
     DISALLOW_COPY_AND_ASSIGN(ClassDef);
   };
@@ -1112,7 +1130,7 @@
       return last_idx_ + method_.method_idx_delta_;
     }
   }
-  uint32_t GetMemberAccessFlags() const {
+  uint32_t GetRawMemberAccessFlags() const {
     if (pos_ < EndOfInstanceFieldsPos()) {
       return field_.access_flags_;
     } else {
@@ -1120,18 +1138,30 @@
       return method_.access_flags_;
     }
   }
+  uint32_t GetFieldAccessFlags() const {
+    return GetRawMemberAccessFlags() & kAccValidFieldFlags;
+  }
+  uint32_t GetMethodAccessFlags() const {
+    return GetRawMemberAccessFlags() & kAccValidMethodFlags;
+  }
+  bool MemberIsNative() const {
+    return GetRawMemberAccessFlags() & kAccNative;
+  }
+  bool MemberIsFinal() const {
+    return GetRawMemberAccessFlags() & kAccFinal;
+  }
   InvokeType GetMethodInvokeType(const DexFile::ClassDef& class_def) const {
     if (HasNextDirectMethod()) {
-      if ((GetMemberAccessFlags() & kAccStatic) != 0) {
+      if ((GetRawMemberAccessFlags() & kAccStatic) != 0) {
         return kStatic;
       } else {
         return kDirect;
       }
     } else {
-      DCHECK_EQ(GetMemberAccessFlags() & kAccStatic, 0U);
+      DCHECK_EQ(GetRawMemberAccessFlags() & kAccStatic, 0U);
       if ((class_def.access_flags_ & kAccInterface) != 0) {
         return kInterface;
-      } else if ((GetMemberAccessFlags() & kAccConstructor) != 0) {
+      } else if ((GetRawMemberAccessFlags() & kAccConstructor) != 0) {
         return kSuper;
       } else {
         return kVirtual;
diff --git a/runtime/dex_file_verifier.cc b/runtime/dex_file_verifier.cc
index 976cac9..9eba92f 100644
--- a/runtime/dex_file_verifier.cc
+++ b/runtime/dex_file_verifier.cc
@@ -456,9 +456,7 @@
     return false;
   }
 
-  uint32_t access_field_mask = kAccPublic | kAccPrivate | kAccProtected | kAccStatic |
-      kAccFinal | kAccVolatile | kAccTransient | kAccSynthetic | kAccEnum;
-  if (UNLIKELY((access_flags & ~access_field_mask) != 0)) {
+  if (UNLIKELY((access_flags & ~kAccJavaFlagsMask) != 0)) {
     ErrorStringPrintf("Bad class_data_item field access_flags %x", access_flags);
     return false;
   }
@@ -482,9 +480,8 @@
     return false;
   }
 
-  uint32_t access_method_mask = kAccPublic | kAccPrivate | kAccProtected | kAccStatic |
-      kAccFinal | kAccSynchronized | kAccBridge | kAccVarargs | kAccNative | kAccAbstract |
-      kAccStrict | kAccSynthetic | kAccConstructor | kAccDeclaredSynchronized;
+  constexpr uint32_t access_method_mask = kAccJavaFlagsMask | kAccConstructor |
+      kAccDeclaredSynchronized;
   if (UNLIKELY(((access_flags & ~access_method_mask) != 0) ||
                (is_synchronized && !allow_synchronized))) {
     ErrorStringPrintf("Bad class_data_item method access_flags %x", access_flags);
@@ -686,24 +683,26 @@
 bool DexFileVerifier::CheckIntraClassDataItem() {
   ClassDataItemIterator it(*dex_file_, ptr_);
 
+  // These calls use the raw access flags to check whether the whole dex field is valid.
+
   for (; it.HasNextStaticField(); it.Next()) {
-    if (!CheckClassDataItemField(it.GetMemberIndex(), it.GetMemberAccessFlags(), true)) {
+    if (!CheckClassDataItemField(it.GetMemberIndex(), it.GetRawMemberAccessFlags(), true)) {
       return false;
     }
   }
   for (; it.HasNextInstanceField(); it.Next()) {
-    if (!CheckClassDataItemField(it.GetMemberIndex(), it.GetMemberAccessFlags(), false)) {
+    if (!CheckClassDataItemField(it.GetMemberIndex(), it.GetRawMemberAccessFlags(), false)) {
       return false;
     }
   }
   for (; it.HasNextDirectMethod(); it.Next()) {
-    if (!CheckClassDataItemMethod(it.GetMemberIndex(), it.GetMemberAccessFlags(),
+    if (!CheckClassDataItemMethod(it.GetMemberIndex(), it.GetRawMemberAccessFlags(),
         it.GetMethodCodeItemOffset(), true)) {
       return false;
     }
   }
   for (; it.HasNextVirtualMethod(); it.Next()) {
-    if (!CheckClassDataItemMethod(it.GetMemberIndex(), it.GetMemberAccessFlags(),
+    if (!CheckClassDataItemMethod(it.GetMemberIndex(), it.GetRawMemberAccessFlags(),
         it.GetMethodCodeItemOffset(), false)) {
       return false;
     }
diff --git a/runtime/dex_instruction_list.h b/runtime/dex_instruction_list.h
index 64c9185..6a9976a 100644
--- a/runtime/dex_instruction_list.h
+++ b/runtime/dex_instruction_list.h
@@ -253,10 +253,10 @@
   V(0xE8, IPUT_OBJECT_QUICK, "iput-object-quick", k22c, false, kFieldRef, kContinue | kThrow | kStore | kRegCFieldOrConstant, kVerifyRegA | kVerifyRegB | kVerifyRuntimeOnly) \
   V(0xE9, INVOKE_VIRTUAL_QUICK, "invoke-virtual-quick", k35c, false, kMethodRef, kContinue | kThrow | kInvoke, kVerifyVarArgNonZero | kVerifyRuntimeOnly) \
   V(0xEA, INVOKE_VIRTUAL_RANGE_QUICK, "invoke-virtual/range-quick", k3rc, false, kMethodRef, kContinue | kThrow | kInvoke, kVerifyVarArgRangeNonZero | kVerifyRuntimeOnly) \
-  V(0xEB, IPUT_BOOLEAN_QUICK, "iput-boolean-quick", k22c, false, kUnknown, 0, kVerifyError) \
-  V(0xEC, IPUT_BYTE_QUICK, "iput-byte-quick", k22c, false, kFieldRef, kContinue | kThrow | kStore | kRegCFieldOrConstant, kVerifyRegAWide | kVerifyRegB | kVerifyRuntimeOnly) \
-  V(0xED, IPUT_CHAR_QUICK, "iput-char-quick", k22c, false, kFieldRef, kContinue | kThrow | kStore | kRegCFieldOrConstant, kVerifyRegAWide | kVerifyRegB | kVerifyRuntimeOnly) \
-  V(0xEE, IPUT_SHORT_QUICK, "iput-short-quick", k22c, false, kFieldRef, kContinue | kThrow | kStore | kRegCFieldOrConstant, kVerifyRegAWide | kVerifyRegB | kVerifyRuntimeOnly) \
+  V(0xEB, IPUT_BOOLEAN_QUICK, "iput-boolean-quick", k22c, false, kFieldRef, kContinue | kThrow | kStore | kRegCFieldOrConstant, kVerifyRegA | kVerifyRegB | kVerifyRuntimeOnly) \
+  V(0xEC, IPUT_BYTE_QUICK, "iput-byte-quick", k22c, false, kFieldRef, kContinue | kThrow | kStore | kRegCFieldOrConstant, kVerifyRegA | kVerifyRegB | kVerifyRuntimeOnly) \
+  V(0xED, IPUT_CHAR_QUICK, "iput-char-quick", k22c, false, kFieldRef, kContinue | kThrow | kStore | kRegCFieldOrConstant, kVerifyRegA | kVerifyRegB | kVerifyRuntimeOnly) \
+  V(0xEE, IPUT_SHORT_QUICK, "iput-short-quick", k22c, false, kFieldRef, kContinue | kThrow | kStore | kRegCFieldOrConstant, kVerifyRegA | kVerifyRegB | kVerifyRuntimeOnly) \
   V(0xEF, UNUSED_EF, "unused-ef", k10x, false, kUnknown, 0, kVerifyError) \
   V(0xF0, UNUSED_F0, "unused-f0", k10x, false, kUnknown, 0, kVerifyError) \
   V(0xF1, UNUSED_F1, "unused-f1", k10x, false, kUnknown, 0, kVerifyError) \
diff --git a/runtime/elf_file.cc b/runtime/elf_file.cc
index 529cd53..65a557b 100644
--- a/runtime/elf_file.cc
+++ b/runtime/elf_file.cc
@@ -202,12 +202,25 @@
     }
   }
 
-  // Either way, the program header is relative to the elf header
-  program_headers_start_ = Begin() + GetHeader().e_phoff;
+  if (program_header_only_) {
+    program_headers_start_ = Begin() + GetHeader().e_phoff;
+  } else {
+    if (!CheckAndSet(GetHeader().e_phoff, "program headers", &program_headers_start_, error_msg)) {
+      return false;
+    }
 
-  if (!program_header_only_) {
     // Setup section headers.
-    section_headers_start_ = Begin() + GetHeader().e_shoff;
+    if (!CheckAndSet(GetHeader().e_shoff, "section headers", &section_headers_start_, error_msg)) {
+      return false;
+    }
+
+    // Find shstrtab.
+    Elf32_Shdr* shstrtab_section_header = GetSectionNameStringSection();
+    if (shstrtab_section_header == nullptr) {
+      *error_msg = StringPrintf("Failed to find shstrtab section header in ELF file: '%s'",
+                                file_->GetPath().c_str());
+      return false;
+    }
 
     // Find .dynamic section info from program header
     dynamic_program_header_ = FindProgamHeaderByType(PT_DYNAMIC);
@@ -217,48 +230,84 @@
       return false;
     }
 
-    dynamic_section_start_
-        = reinterpret_cast<Elf32_Dyn*>(Begin() + GetDynamicProgramHeader().p_offset);
+    if (!CheckAndSet(GetDynamicProgramHeader().p_offset, "dynamic section",
+                     reinterpret_cast<byte**>(&dynamic_section_start_), error_msg)) {
+      return false;
+    }
 
     // Find other sections from section headers
     for (Elf32_Word i = 0; i < GetSectionHeaderNum(); i++) {
-      Elf32_Shdr& section_header = GetSectionHeader(i);
-      byte* section_addr = Begin() + section_header.sh_offset;
-      switch (section_header.sh_type) {
+      Elf32_Shdr* section_header = GetSectionHeader(i);
+      if (section_header == nullptr) {
+        *error_msg = StringPrintf("Failed to find section header for section %d in ELF file: '%s'",
+                                  i, file_->GetPath().c_str());
+        return false;
+      }
+      switch (section_header->sh_type) {
         case SHT_SYMTAB: {
-          symtab_section_start_ = reinterpret_cast<Elf32_Sym*>(section_addr);
+          if (!CheckAndSet(section_header->sh_offset, "symtab",
+                           reinterpret_cast<byte**>(&symtab_section_start_), error_msg)) {
+            return false;
+          }
           break;
         }
         case SHT_DYNSYM: {
-          dynsym_section_start_ = reinterpret_cast<Elf32_Sym*>(section_addr);
+          if (!CheckAndSet(section_header->sh_offset, "dynsym",
+                           reinterpret_cast<byte**>(&dynsym_section_start_), error_msg)) {
+            return false;
+          }
           break;
         }
         case SHT_STRTAB: {
           // TODO: base these off of sh_link from .symtab and .dynsym above
-          if ((section_header.sh_flags & SHF_ALLOC) != 0) {
-            dynstr_section_start_ = reinterpret_cast<char*>(section_addr);
+          if ((section_header->sh_flags & SHF_ALLOC) != 0) {
+            // Check that this is named ".dynstr" and ignore otherwise.
+            const char* header_name = GetString(*shstrtab_section_header, section_header->sh_name);
+            if (strncmp(".dynstr", header_name, 8) == 0) {
+              if (!CheckAndSet(section_header->sh_offset, "dynstr",
+                               reinterpret_cast<byte**>(&dynstr_section_start_), error_msg)) {
+                return false;
+              }
+            }
           } else {
-            strtab_section_start_ = reinterpret_cast<char*>(section_addr);
+            // Check that this is named ".strtab" and ignore otherwise.
+            const char* header_name = GetString(*shstrtab_section_header, section_header->sh_name);
+            if (strncmp(".strtab", header_name, 8) == 0) {
+              if (!CheckAndSet(section_header->sh_offset, "strtab",
+                               reinterpret_cast<byte**>(&strtab_section_start_), error_msg)) {
+                return false;
+              }
+            }
           }
           break;
         }
         case SHT_DYNAMIC: {
-          if (reinterpret_cast<byte*>(dynamic_section_start_) != section_addr) {
+          if (reinterpret_cast<byte*>(dynamic_section_start_) !=
+              Begin() + section_header->sh_offset) {
             LOG(WARNING) << "Failed to find matching SHT_DYNAMIC for PT_DYNAMIC in "
                          << file_->GetPath() << ": " << std::hex
                          << reinterpret_cast<void*>(dynamic_section_start_)
-                         << " != " << reinterpret_cast<void*>(section_addr);
+                         << " != " << reinterpret_cast<void*>(Begin() + section_header->sh_offset);
             return false;
           }
           break;
         }
         case SHT_HASH: {
-          hash_section_start_ = reinterpret_cast<Elf32_Word*>(section_addr);
+          if (!CheckAndSet(section_header->sh_offset, "hash section",
+                           reinterpret_cast<byte**>(&hash_section_start_), error_msg)) {
+            return false;
+          }
           break;
         }
       }
     }
+
+    // Check for the existence of some sections.
+    if (!CheckSectionsExist(error_msg)) {
+      return false;
+    }
   }
+
   return true;
 }
 
@@ -272,6 +321,117 @@
   }
 }
 
+bool ElfFile::CheckAndSet(Elf32_Off offset, const char* label,
+                          byte** target, std::string* error_msg) {
+  if (Begin() + offset >= End()) {
+    *error_msg = StringPrintf("Offset %d is out of range for %s in ELF file: '%s'", offset, label,
+                              file_->GetPath().c_str());
+    return false;
+  }
+  *target = Begin() + offset;
+  return true;
+}
+
+bool ElfFile::CheckSectionsLinked(const byte* source, const byte* target) const {
+  // Only works in whole-program mode, as we need to iterate over the sections.
+  // Note that we normally can't search by type, as duplicates are allowed for most section types.
+  if (program_header_only_) {
+    return true;
+  }
+
+  Elf32_Shdr* source_section = nullptr;
+  Elf32_Word target_index = 0;
+  bool target_found = false;
+  for (Elf32_Word i = 0; i < GetSectionHeaderNum(); i++) {
+    Elf32_Shdr* section_header = GetSectionHeader(i);
+
+    if (Begin() + section_header->sh_offset == source) {
+      // Found the source.
+      source_section = section_header;
+      if (target_index) {
+        break;
+      }
+    } else if (Begin() + section_header->sh_offset == target) {
+      target_index = i;
+      target_found = true;
+      if (source_section != nullptr) {
+        break;
+      }
+    }
+  }
+
+  return target_found && source_section != nullptr && source_section->sh_link == target_index;
+}
+
+bool ElfFile::CheckSectionsExist(std::string* error_msg) const {
+  if (!program_header_only_) {
+    // If in full mode, need section headers.
+    if (section_headers_start_ == nullptr) {
+      *error_msg = StringPrintf("No section headers in ELF file: '%s'", file_->GetPath().c_str());
+      return false;
+    }
+  }
+
+  // This is redundant, but defensive.
+  if (dynamic_program_header_ == nullptr) {
+    *error_msg = StringPrintf("Failed to find PT_DYNAMIC program header in ELF file: '%s'",
+                              file_->GetPath().c_str());
+    return false;
+  }
+
+  // Need a dynamic section. This is redundant, but defensive.
+  if (dynamic_section_start_ == nullptr) {
+    *error_msg = StringPrintf("Failed to find dynamic section in ELF file: '%s'",
+                              file_->GetPath().c_str());
+    return false;
+  }
+
+  // Symtab validation. These is not really a hard failure, as we are currently not using the
+  // symtab internally, but it's nice to be defensive.
+  if (symtab_section_start_ != nullptr) {
+    // When there's a symtab, there should be a strtab.
+    if (strtab_section_start_ == nullptr) {
+      *error_msg = StringPrintf("No strtab for symtab in ELF file: '%s'", file_->GetPath().c_str());
+      return false;
+    }
+
+    // The symtab should link to the strtab.
+    if (!CheckSectionsLinked(reinterpret_cast<const byte*>(symtab_section_start_),
+                             reinterpret_cast<const byte*>(strtab_section_start_))) {
+      *error_msg = StringPrintf("Symtab is not linked to the strtab in ELF file: '%s'",
+                                file_->GetPath().c_str());
+      return false;
+    }
+  }
+
+  // We always need a dynstr & dynsym.
+  if (dynstr_section_start_ == nullptr) {
+    *error_msg = StringPrintf("No dynstr in ELF file: '%s'", file_->GetPath().c_str());
+    return false;
+  }
+  if (dynsym_section_start_ == nullptr) {
+    *error_msg = StringPrintf("No dynsym in ELF file: '%s'", file_->GetPath().c_str());
+    return false;
+  }
+
+  // Need a hash section for dynamic symbol lookup.
+  if (hash_section_start_ == nullptr) {
+    *error_msg = StringPrintf("Failed to find hash section in ELF file: '%s'",
+                              file_->GetPath().c_str());
+    return false;
+  }
+
+  // And the hash section should be linking to the dynsym.
+  if (!CheckSectionsLinked(reinterpret_cast<const byte*>(hash_section_start_),
+                           reinterpret_cast<const byte*>(dynsym_section_start_))) {
+    *error_msg = StringPrintf("Hash section is not linked to the dynstr in ELF file: '%s'",
+                              file_->GetPath().c_str());
+    return false;
+  }
+
+  return true;
+}
+
 bool ElfFile::SetMap(MemMap* map, std::string* error_msg) {
   if (map == nullptr) {
     // MemMap::Open should have already set an error.
@@ -407,70 +567,68 @@
 
 
 Elf32_Ehdr& ElfFile::GetHeader() const {
-  CHECK(header_ != nullptr);
+  CHECK(header_ != nullptr);  // Header has been checked in SetMap. This is a sanity check.
   return *header_;
 }
 
 byte* ElfFile::GetProgramHeadersStart() const {
-  CHECK(program_headers_start_ != nullptr);
+  CHECK(program_headers_start_ != nullptr);  // Header has been set in Setup. This is a sanity
+                                             // check.
   return program_headers_start_;
 }
 
 byte* ElfFile::GetSectionHeadersStart() const {
-  CHECK(section_headers_start_ != nullptr);
+  CHECK(!program_header_only_);              // Only used in "full" mode.
+  CHECK(section_headers_start_ != nullptr);  // Is checked in CheckSectionsExist. Sanity check.
   return section_headers_start_;
 }
 
 Elf32_Phdr& ElfFile::GetDynamicProgramHeader() const {
-  CHECK(dynamic_program_header_ != nullptr);
+  CHECK(dynamic_program_header_ != nullptr);  // Is checked in CheckSectionsExist. Sanity check.
   return *dynamic_program_header_;
 }
 
 Elf32_Dyn* ElfFile::GetDynamicSectionStart() const {
-  CHECK(dynamic_section_start_ != nullptr);
+  CHECK(dynamic_section_start_ != nullptr);  // Is checked in CheckSectionsExist. Sanity check.
   return dynamic_section_start_;
 }
 
+static bool IsSymbolSectionType(Elf32_Word section_type) {
+  return ((section_type == SHT_SYMTAB) || (section_type == SHT_DYNSYM));
+}
+
 Elf32_Sym* ElfFile::GetSymbolSectionStart(Elf32_Word section_type) const {
   CHECK(IsSymbolSectionType(section_type)) << file_->GetPath() << " " << section_type;
-  Elf32_Sym* symbol_section_start;
   switch (section_type) {
     case SHT_SYMTAB: {
-      symbol_section_start = symtab_section_start_;
+      return symtab_section_start_;
       break;
     }
     case SHT_DYNSYM: {
-      symbol_section_start = dynsym_section_start_;
+      return dynsym_section_start_;
       break;
     }
     default: {
       LOG(FATAL) << section_type;
-      symbol_section_start = nullptr;
+      return nullptr;
     }
   }
-  CHECK(symbol_section_start != nullptr);
-  return symbol_section_start;
 }
 
 const char* ElfFile::GetStringSectionStart(Elf32_Word section_type) const {
   CHECK(IsSymbolSectionType(section_type)) << file_->GetPath() << " " << section_type;
-  const char* string_section_start;
   switch (section_type) {
     case SHT_SYMTAB: {
-      string_section_start = strtab_section_start_;
-      break;
+      return strtab_section_start_;
     }
     case SHT_DYNSYM: {
-      string_section_start = dynstr_section_start_;
-      break;
+      return dynstr_section_start_;
     }
     default: {
       LOG(FATAL) << section_type;
-      string_section_start = nullptr;
+      return nullptr;
     }
   }
-  CHECK(string_section_start != nullptr);
-  return string_section_start;
 }
 
 const char* ElfFile::GetString(Elf32_Word section_type, Elf32_Word i) const {
@@ -479,12 +637,16 @@
     return nullptr;
   }
   const char* string_section_start = GetStringSectionStart(section_type);
-  const char* string = string_section_start + i;
-  return string;
+  if (string_section_start == nullptr) {
+    return nullptr;
+  }
+  return string_section_start + i;
 }
 
+// WARNING: The following methods do not check for an error condition (non-existent hash section).
+//          It is the caller's job to do this.
+
 Elf32_Word* ElfFile::GetHashSectionStart() const {
-  CHECK(hash_section_start_ != nullptr);
   return hash_section_start_;
 }
 
@@ -496,14 +658,22 @@
   return GetHashSectionStart()[1];
 }
 
-Elf32_Word ElfFile::GetHashBucket(size_t i) const {
-  CHECK_LT(i, GetHashBucketNum());
+Elf32_Word ElfFile::GetHashBucket(size_t i, bool* ok) const {
+  if (i >= GetHashBucketNum()) {
+    *ok = false;
+    return 0;
+  }
+  *ok = true;
   // 0 is nbucket, 1 is nchain
   return GetHashSectionStart()[2 + i];
 }
 
-Elf32_Word ElfFile::GetHashChain(size_t i) const {
-  CHECK_LT(i, GetHashChainNum());
+Elf32_Word ElfFile::GetHashChain(size_t i, bool* ok) const {
+  if (i >= GetHashBucketNum()) {
+    *ok = false;
+    return 0;
+  }
+  *ok = true;
   // 0 is nbucket, 1 is nchain, & chains are after buckets
   return GetHashSectionStart()[2 + GetHashBucketNum() + i];
 }
@@ -512,18 +682,20 @@
   return GetHeader().e_phnum;
 }
 
-Elf32_Phdr& ElfFile::GetProgramHeader(Elf32_Word i) const {
-  CHECK_LT(i, GetProgramHeaderNum()) << file_->GetPath();
+Elf32_Phdr* ElfFile::GetProgramHeader(Elf32_Word i) const {
+  CHECK_LT(i, GetProgramHeaderNum()) << file_->GetPath();  // Sanity check for caller.
   byte* program_header = GetProgramHeadersStart() + (i * GetHeader().e_phentsize);
-  CHECK_LT(program_header, End()) << file_->GetPath();
-  return *reinterpret_cast<Elf32_Phdr*>(program_header);
+  if (program_header >= End()) {
+    return nullptr;  // Failure condition.
+  }
+  return reinterpret_cast<Elf32_Phdr*>(program_header);
 }
 
 Elf32_Phdr* ElfFile::FindProgamHeaderByType(Elf32_Word type) const {
   for (Elf32_Word i = 0; i < GetProgramHeaderNum(); i++) {
-    Elf32_Phdr& program_header = GetProgramHeader(i);
-    if (program_header.p_type == type) {
-      return &program_header;
+    Elf32_Phdr* program_header = GetProgramHeader(i);
+    if (program_header->p_type == type) {
+      return program_header;
     }
   }
   return nullptr;
@@ -533,14 +705,18 @@
   return GetHeader().e_shnum;
 }
 
-Elf32_Shdr& ElfFile::GetSectionHeader(Elf32_Word i) const {
+Elf32_Shdr* ElfFile::GetSectionHeader(Elf32_Word i) const {
   // Can only access arbitrary sections when we have the whole file, not just program header.
   // Even if we Load(), it doesn't bring in all the sections.
   CHECK(!program_header_only_) << file_->GetPath();
-  CHECK_LT(i, GetSectionHeaderNum()) << file_->GetPath();
+  if (i >= GetSectionHeaderNum()) {
+    return nullptr;  // Failure condition.
+  }
   byte* section_header = GetSectionHeadersStart() + (i * GetHeader().e_shentsize);
-  CHECK_LT(section_header, End()) << file_->GetPath();
-  return *reinterpret_cast<Elf32_Shdr*>(section_header);
+  if (section_header >= End()) {
+    return nullptr;  // Failure condition.
+  }
+  return reinterpret_cast<Elf32_Shdr*>(section_header);
 }
 
 Elf32_Shdr* ElfFile::FindSectionByType(Elf32_Word type) const {
@@ -548,9 +724,9 @@
   // We could change this to switch on known types if they were detected during loading.
   CHECK(!program_header_only_) << file_->GetPath();
   for (Elf32_Word i = 0; i < GetSectionHeaderNum(); i++) {
-    Elf32_Shdr& section_header = GetSectionHeader(i);
-    if (section_header.sh_type == type) {
-      return &section_header;
+    Elf32_Shdr* section_header = GetSectionHeader(i);
+    if (section_header->sh_type == type) {
+      return section_header;
     }
   }
   return nullptr;
@@ -570,11 +746,15 @@
   return h;
 }
 
-Elf32_Shdr& ElfFile::GetSectionNameStringSection() const {
+Elf32_Shdr* ElfFile::GetSectionNameStringSection() const {
   return GetSectionHeader(GetHeader().e_shstrndx);
 }
 
 const byte* ElfFile::FindDynamicSymbolAddress(const std::string& symbol_name) const {
+  // Check that we have a hash section.
+  if (GetHashSectionStart() == nullptr) {
+    return nullptr;  // Failure condition.
+  }
   const Elf32_Sym* sym = FindDynamicSymbol(symbol_name);
   if (sym != nullptr) {
     return base_address_ + sym->st_value;
@@ -583,6 +763,7 @@
   }
 }
 
+// WARNING: Only called from FindDynamicSymbolAddress. Elides check for hash section.
 const Elf32_Sym* ElfFile::FindDynamicSymbol(const std::string& symbol_name) const {
   if (GetHashBucketNum() == 0) {
     // No dynamic symbols at all.
@@ -590,22 +771,28 @@
   }
   Elf32_Word hash = elfhash(symbol_name.c_str());
   Elf32_Word bucket_index = hash % GetHashBucketNum();
-  Elf32_Word symbol_and_chain_index = GetHashBucket(bucket_index);
+  bool ok;
+  Elf32_Word symbol_and_chain_index = GetHashBucket(bucket_index, &ok);
+  if (!ok) {
+    return nullptr;
+  }
   while (symbol_and_chain_index != 0 /* STN_UNDEF */) {
-    Elf32_Sym& symbol = GetSymbol(SHT_DYNSYM, symbol_and_chain_index);
-    const char* name = GetString(SHT_DYNSYM, symbol.st_name);
-    if (symbol_name == name) {
-      return &symbol;
+    Elf32_Sym* symbol = GetSymbol(SHT_DYNSYM, symbol_and_chain_index);
+    if (symbol == nullptr) {
+      return nullptr;  // Failure condition.
     }
-    symbol_and_chain_index = GetHashChain(symbol_and_chain_index);
+    const char* name = GetString(SHT_DYNSYM, symbol->st_name);
+    if (symbol_name == name) {
+      return symbol;
+    }
+    symbol_and_chain_index = GetHashChain(symbol_and_chain_index, &ok);
+    if (!ok) {
+      return nullptr;
+    }
   }
   return nullptr;
 }
 
-bool ElfFile::IsSymbolSectionType(Elf32_Word section_type) {
-  return ((section_type == SHT_SYMTAB) || (section_type == SHT_DYNSYM));
-}
-
 Elf32_Word ElfFile::GetSymbolNum(Elf32_Shdr& section_header) const {
   CHECK(IsSymbolSectionType(section_header.sh_type))
       << file_->GetPath() << " " << section_header.sh_type;
@@ -613,9 +800,13 @@
   return section_header.sh_size / section_header.sh_entsize;
 }
 
-Elf32_Sym& ElfFile::GetSymbol(Elf32_Word section_type,
+Elf32_Sym* ElfFile::GetSymbol(Elf32_Word section_type,
                               Elf32_Word i) const {
-  return *(GetSymbolSectionStart(section_type) + i);
+  Elf32_Sym* sym_start = GetSymbolSectionStart(section_type);
+  if (sym_start == nullptr) {
+    return nullptr;
+  }
+  return sym_start + i;
 }
 
 ElfFile::SymbolTable** ElfFile::GetSymbolTable(Elf32_Word section_type) {
@@ -646,27 +837,37 @@
       DCHECK(build_map);
       *symbol_table = new SymbolTable;
       Elf32_Shdr* symbol_section = FindSectionByType(section_type);
-      CHECK(symbol_section != nullptr) << file_->GetPath();
-      Elf32_Shdr& string_section = GetSectionHeader(symbol_section->sh_link);
+      if (symbol_section == nullptr) {
+        return nullptr;  // Failure condition.
+      }
+      Elf32_Shdr* string_section = GetSectionHeader(symbol_section->sh_link);
+      if (string_section == nullptr) {
+        return nullptr;  // Failure condition.
+      }
       for (uint32_t i = 0; i < GetSymbolNum(*symbol_section); i++) {
-        Elf32_Sym& symbol = GetSymbol(section_type, i);
-        unsigned char type = ELF32_ST_TYPE(symbol.st_info);
+        Elf32_Sym* symbol = GetSymbol(section_type, i);
+        if (symbol == nullptr) {
+          return nullptr;  // Failure condition.
+        }
+        unsigned char type = ELF32_ST_TYPE(symbol->st_info);
         if (type == STT_NOTYPE) {
           continue;
         }
-        const char* name = GetString(string_section, symbol.st_name);
+        const char* name = GetString(*string_section, symbol->st_name);
         if (name == nullptr) {
           continue;
         }
         std::pair<SymbolTable::iterator, bool> result =
-            (*symbol_table)->insert(std::make_pair(name, &symbol));
+            (*symbol_table)->insert(std::make_pair(name, symbol));
         if (!result.second) {
           // If a duplicate, make sure it has the same logical value. Seen on x86.
-          CHECK_EQ(symbol.st_value, result.first->second->st_value);
-          CHECK_EQ(symbol.st_size, result.first->second->st_size);
-          CHECK_EQ(symbol.st_info, result.first->second->st_info);
-          CHECK_EQ(symbol.st_other, result.first->second->st_other);
-          CHECK_EQ(symbol.st_shndx, result.first->second->st_shndx);
+          if ((symbol->st_value != result.first->second->st_value) ||
+              (symbol->st_size != result.first->second->st_size) ||
+              (symbol->st_info != result.first->second->st_info) ||
+              (symbol->st_other != result.first->second->st_other) ||
+              (symbol->st_shndx != result.first->second->st_shndx)) {
+            return nullptr;  // Failure condition.
+          }
         }
       }
     }
@@ -680,16 +881,24 @@
 
   // Fall back to linear search
   Elf32_Shdr* symbol_section = FindSectionByType(section_type);
-  CHECK(symbol_section != nullptr) << file_->GetPath();
-  Elf32_Shdr& string_section = GetSectionHeader(symbol_section->sh_link);
+  if (symbol_section == nullptr) {
+    return nullptr;
+  }
+  Elf32_Shdr* string_section = GetSectionHeader(symbol_section->sh_link);
+  if (string_section == nullptr) {
+    return nullptr;
+  }
   for (uint32_t i = 0; i < GetSymbolNum(*symbol_section); i++) {
-    Elf32_Sym& symbol = GetSymbol(section_type, i);
-    const char* name = GetString(string_section, symbol.st_name);
+    Elf32_Sym* symbol = GetSymbol(section_type, i);
+    if (symbol == nullptr) {
+      return nullptr;  // Failure condition.
+    }
+    const char* name = GetString(*string_section, symbol->st_name);
     if (name == nullptr) {
       continue;
     }
     if (symbol_name == name) {
-      return &symbol;
+      return symbol;
     }
   }
   return nullptr;
@@ -708,14 +917,20 @@
 const char* ElfFile::GetString(Elf32_Shdr& string_section, Elf32_Word i) const {
   CHECK(!program_header_only_) << file_->GetPath();
   // TODO: remove this static_cast from enum when using -std=gnu++0x
-  CHECK_EQ(static_cast<Elf32_Word>(SHT_STRTAB), string_section.sh_type) << file_->GetPath();
-  CHECK_LT(i, string_section.sh_size) << file_->GetPath();
+  if (static_cast<Elf32_Word>(SHT_STRTAB) != string_section.sh_type) {
+    return nullptr;  // Failure condition.
+  }
+  if (i >= string_section.sh_size) {
+    return nullptr;
+  }
   if (i == 0) {
     return nullptr;
   }
   byte* strings = Begin() + string_section.sh_offset;
   byte* string = strings + i;
-  CHECK_LT(string, End()) << file_->GetPath();
+  if (string >= End()) {
+    return nullptr;
+  }
   return reinterpret_cast<const char*>(string);
 }
 
@@ -785,15 +1000,15 @@
   Elf32_Addr min_vaddr = 0xFFFFFFFFu;
   Elf32_Addr max_vaddr = 0x00000000u;
   for (Elf32_Word i = 0; i < GetProgramHeaderNum(); i++) {
-    Elf32_Phdr& program_header = GetProgramHeader(i);
-    if (program_header.p_type != PT_LOAD) {
+    Elf32_Phdr* program_header = GetProgramHeader(i);
+    if (program_header->p_type != PT_LOAD) {
       continue;
     }
-    Elf32_Addr begin_vaddr = program_header.p_vaddr;
+    Elf32_Addr begin_vaddr = program_header->p_vaddr;
     if (begin_vaddr < min_vaddr) {
        min_vaddr = begin_vaddr;
     }
-    Elf32_Addr end_vaddr = program_header.p_vaddr + program_header.p_memsz;
+    Elf32_Addr end_vaddr = program_header->p_vaddr + program_header->p_memsz;
     if (end_vaddr > max_vaddr) {
       max_vaddr = end_vaddr;
     }
@@ -843,16 +1058,21 @@
 
   bool reserved = false;
   for (Elf32_Word i = 0; i < GetProgramHeaderNum(); i++) {
-    Elf32_Phdr& program_header = GetProgramHeader(i);
+    Elf32_Phdr* program_header = GetProgramHeader(i);
+    if (program_header == nullptr) {
+      *error_msg = StringPrintf("No program header for entry %d in ELF file %s.",
+                                i, file_->GetPath().c_str());
+      return false;
+    }
 
     // Record .dynamic header information for later use
-    if (program_header.p_type == PT_DYNAMIC) {
-      dynamic_program_header_ = &program_header;
+    if (program_header->p_type == PT_DYNAMIC) {
+      dynamic_program_header_ = program_header;
       continue;
     }
 
     // Not something to load, move on.
-    if (program_header.p_type != PT_LOAD) {
+    if (program_header->p_type != PT_LOAD) {
       continue;
     }
 
@@ -874,8 +1094,8 @@
     }
     size_t file_length = static_cast<size_t>(temp_file_length);
     if (!reserved) {
-      byte* reserve_base = ((program_header.p_vaddr != 0) ?
-                            reinterpret_cast<byte*>(program_header.p_vaddr) : nullptr);
+      byte* reserve_base = ((program_header->p_vaddr != 0) ?
+                            reinterpret_cast<byte*>(program_header->p_vaddr) : nullptr);
       std::string reservation_name("ElfFile reservation for ");
       reservation_name += file_->GetPath();
       std::unique_ptr<MemMap> reserve(MemMap::MapAnonymous(reservation_name.c_str(),
@@ -894,18 +1114,18 @@
       segments_.push_back(reserve.release());
     }
     // empty segment, nothing to map
-    if (program_header.p_memsz == 0) {
+    if (program_header->p_memsz == 0) {
       continue;
     }
-    byte* p_vaddr = base_address_ + program_header.p_vaddr;
+    byte* p_vaddr = base_address_ + program_header->p_vaddr;
     int prot = 0;
-    if (executable && ((program_header.p_flags & PF_X) != 0)) {
+    if (executable && ((program_header->p_flags & PF_X) != 0)) {
       prot |= PROT_EXEC;
     }
-    if ((program_header.p_flags & PF_W) != 0) {
+    if ((program_header->p_flags & PF_W) != 0) {
       prot |= PROT_WRITE;
     }
-    if ((program_header.p_flags & PF_R) != 0) {
+    if ((program_header->p_flags & PF_R) != 0) {
       prot |= PROT_READ;
     }
     int flags = 0;
@@ -915,17 +1135,17 @@
     } else {
       flags |= MAP_PRIVATE;
     }
-    if (file_length < (program_header.p_offset + program_header.p_memsz)) {
+    if (file_length < (program_header->p_offset + program_header->p_memsz)) {
       *error_msg = StringPrintf("File size of %zd bytes not large enough to contain ELF segment "
                                 "%d of %d bytes: '%s'", file_length, i,
-                                program_header.p_offset + program_header.p_memsz,
+                                program_header->p_offset + program_header->p_memsz,
                                 file_->GetPath().c_str());
       return false;
     }
     std::unique_ptr<MemMap> segment(MemMap::MapFileAtAddress(p_vaddr,
-                                                       program_header.p_memsz,
+                                                       program_header->p_memsz,
                                                        prot, flags, file_->Fd(),
-                                                       program_header.p_offset,
+                                                       program_header->p_offset,
                                                        true,  // implies MAP_FIXED
                                                        file_->GetPath().c_str(),
                                                        error_msg));
@@ -944,8 +1164,14 @@
   }
 
   // Now that we are done loading, .dynamic should be in memory to find .dynstr, .dynsym, .hash
-  dynamic_section_start_
-      = reinterpret_cast<Elf32_Dyn*>(base_address_ + GetDynamicProgramHeader().p_vaddr);
+  byte* dsptr = base_address_ + GetDynamicProgramHeader().p_vaddr;
+  if ((dsptr < Begin() || dsptr >= End()) && !ValidPointer(dsptr)) {
+    *error_msg = StringPrintf("dynamic section address invalid in ELF file %s",
+                              file_->GetPath().c_str());
+    return false;
+  }
+  dynamic_section_start_ = reinterpret_cast<Elf32_Dyn*>(dsptr);
+
   for (Elf32_Word i = 0; i < GetDynamicNum(); i++) {
     Elf32_Dyn& elf_dyn = GetDynamic(i);
     byte* d_ptr = base_address_ + elf_dyn.d_un.d_ptr;
@@ -989,6 +1215,11 @@
     }
   }
 
+  // Check for the existence of some sections.
+  if (!CheckSectionsExist(error_msg)) {
+    return false;
+  }
+
   // Use GDB JIT support to do stack backtrace, etc.
   if (executable) {
     GdbJITSupport();
@@ -1010,15 +1241,21 @@
 
 Elf32_Shdr* ElfFile::FindSectionByName(const std::string& name) const {
   CHECK(!program_header_only_);
-  Elf32_Shdr& shstrtab_sec = GetSectionNameStringSection();
+  Elf32_Shdr* shstrtab_sec = GetSectionNameStringSection();
+  if (shstrtab_sec == nullptr) {
+    return nullptr;
+  }
   for (uint32_t i = 0; i < GetSectionHeaderNum(); i++) {
-    Elf32_Shdr& shdr = GetSectionHeader(i);
-    const char* sec_name = GetString(shstrtab_sec, shdr.sh_name);
+    Elf32_Shdr* shdr = GetSectionHeader(i);
+    if (shdr == nullptr) {
+      return nullptr;
+    }
+    const char* sec_name = GetString(*shstrtab_sec, shdr->sh_name);
     if (sec_name == nullptr) {
       continue;
     }
     if (name == sec_name) {
-      return &shdr;
+      return shdr;
     }
   }
   return nullptr;
@@ -1337,7 +1574,7 @@
   }
 
  private:
-  explicit DebugTag(uint32_t index) : index_(index) {}
+  explicit DebugTag(uint32_t index) : index_(index), size_(0), tag_(0), has_child_(false) {}
   void AddAttribute(uint32_t type, uint32_t attr_size) {
     off_map_.insert(std::pair<uint32_t, uint32_t>(type, size_));
     size_map_.insert(std::pair<uint32_t, uint32_t>(type, attr_size));
diff --git a/runtime/elf_file.h b/runtime/elf_file.h
index 1922911..916d693 100644
--- a/runtime/elf_file.h
+++ b/runtime/elf_file.h
@@ -67,35 +67,20 @@
   Elf32_Ehdr& GetHeader() const;
 
   Elf32_Word GetProgramHeaderNum() const;
-  Elf32_Phdr& GetProgramHeader(Elf32_Word) const;
-  Elf32_Phdr* FindProgamHeaderByType(Elf32_Word type) const;
+  Elf32_Phdr* GetProgramHeader(Elf32_Word) const;
 
   Elf32_Word GetSectionHeaderNum() const;
-  Elf32_Shdr& GetSectionHeader(Elf32_Word) const;
+  Elf32_Shdr* GetSectionHeader(Elf32_Word) const;
   Elf32_Shdr* FindSectionByType(Elf32_Word type) const;
   Elf32_Shdr* FindSectionByName(const std::string& name) const;
 
-  Elf32_Shdr& GetSectionNameStringSection() const;
+  Elf32_Shdr* GetSectionNameStringSection() const;
 
   // Find .dynsym using .hash for more efficient lookup than FindSymbolAddress.
   const byte* FindDynamicSymbolAddress(const std::string& symbol_name) const;
-  const Elf32_Sym* FindDynamicSymbol(const std::string& symbol_name) const;
 
-  static bool IsSymbolSectionType(Elf32_Word section_type);
   Elf32_Word GetSymbolNum(Elf32_Shdr&) const;
-  Elf32_Sym& GetSymbol(Elf32_Word section_type, Elf32_Word i) const;
-
-  // Find symbol in specified table, returning nullptr if it is not found.
-  //
-  // If build_map is true, builds a map to speed repeated access. The
-  // map does not included untyped symbol values (aka STT_NOTYPE)
-  // since they can contain duplicates. If build_map is false, the map
-  // will be used if it was already created. Typically build_map
-  // should be set unless only a small number of symbols will be
-  // looked up.
-  Elf32_Sym* FindSymbolByName(Elf32_Word section_type,
-                              const std::string& symbol_name,
-                              bool build_map);
+  Elf32_Sym* GetSymbol(Elf32_Word section_type, Elf32_Word i) const;
 
   // Find address of symbol in specified table, returning 0 if it is
   // not found. See FindSymbolByName for an explanation of build_map.
@@ -107,13 +92,8 @@
   // special 0 offset.
   const char* GetString(Elf32_Shdr&, Elf32_Word) const;
 
-  // Lookup a string by section type. Returns nullptr for special 0 offset.
-  const char* GetString(Elf32_Word section_type, Elf32_Word) const;
-
   Elf32_Word GetDynamicNum() const;
   Elf32_Dyn& GetDynamic(Elf32_Word) const;
-  Elf32_Dyn* FindDynamicByType(Elf32_Sword type) const;
-  Elf32_Word FindDynamicValueByType(Elf32_Sword type) const;
 
   Elf32_Word GetRelNum(Elf32_Shdr&) const;
   Elf32_Rel& GetRel(Elf32_Shdr&, Elf32_Word) const;
@@ -148,14 +128,45 @@
   Elf32_Word* GetHashSectionStart() const;
   Elf32_Word GetHashBucketNum() const;
   Elf32_Word GetHashChainNum() const;
-  Elf32_Word GetHashBucket(size_t i) const;
-  Elf32_Word GetHashChain(size_t i) const;
+  Elf32_Word GetHashBucket(size_t i, bool* ok) const;
+  Elf32_Word GetHashChain(size_t i, bool* ok) const;
 
   typedef std::map<std::string, Elf32_Sym*> SymbolTable;
   SymbolTable** GetSymbolTable(Elf32_Word section_type);
 
   bool ValidPointer(const byte* start) const;
 
+  const Elf32_Sym* FindDynamicSymbol(const std::string& symbol_name) const;
+
+  // Check that certain sections and their dependencies exist.
+  bool CheckSectionsExist(std::string* error_msg) const;
+
+  // Check that the link of the first section links to the second section.
+  bool CheckSectionsLinked(const byte* source, const byte* target) const;
+
+  // Check whether the offset is in range, and set to target to Begin() + offset if OK.
+  bool CheckAndSet(Elf32_Off offset, const char* label, byte** target, std::string* error_msg);
+
+  // Find symbol in specified table, returning nullptr if it is not found.
+  //
+  // If build_map is true, builds a map to speed repeated access. The
+  // map does not included untyped symbol values (aka STT_NOTYPE)
+  // since they can contain duplicates. If build_map is false, the map
+  // will be used if it was already created. Typically build_map
+  // should be set unless only a small number of symbols will be
+  // looked up.
+  Elf32_Sym* FindSymbolByName(Elf32_Word section_type,
+                              const std::string& symbol_name,
+                              bool build_map);
+
+  Elf32_Phdr* FindProgamHeaderByType(Elf32_Word type) const;
+
+  Elf32_Dyn* FindDynamicByType(Elf32_Sword type) const;
+  Elf32_Word FindDynamicValueByType(Elf32_Sword type) const;
+
+  // Lookup a string by section type. Returns nullptr for special 0 offset.
+  const char* GetString(Elf32_Word section_type, Elf32_Word) const;
+
   const File* const file_;
   const bool writable_;
   const bool program_header_only_;
diff --git a/runtime/entrypoints/quick/quick_trampoline_entrypoints.cc b/runtime/entrypoints/quick/quick_trampoline_entrypoints.cc
index 95dd8be..1dbbb70 100644
--- a/runtime/entrypoints/quick/quick_trampoline_entrypoints.cc
+++ b/runtime/entrypoints/quick/quick_trampoline_entrypoints.cc
@@ -1488,7 +1488,7 @@
       // Initialize padding entries.
       size_t expected_slots = handle_scope_->NumberOfReferences();
       while (cur_entry_ < expected_slots) {
-        handle_scope_->GetHandle(cur_entry_++).Assign(nullptr);
+        handle_scope_->GetMutableHandle(cur_entry_++).Assign(nullptr);
       }
       DCHECK_NE(cur_entry_, 0U);
     }
@@ -1509,7 +1509,7 @@
 
 uintptr_t BuildGenericJniFrameVisitor::FillJniCall::PushHandle(mirror::Object* ref) {
   uintptr_t tmp;
-  Handle<mirror::Object> h = handle_scope_->GetHandle(cur_entry_);
+  MutableHandle<mirror::Object> h = handle_scope_->GetMutableHandle(cur_entry_);
   h.Assign(ref);
   tmp = reinterpret_cast<uintptr_t>(h.ToJObject());
   cur_entry_++;
diff --git a/runtime/field_helper.h b/runtime/field_helper.h
index 5eae55e..8097025 100644
--- a/runtime/field_helper.h
+++ b/runtime/field_helper.h
@@ -27,11 +27,6 @@
  public:
   explicit FieldHelper(Handle<mirror::ArtField> f) : field_(f) {}
 
-  void ChangeField(mirror::ArtField* new_f) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
-    DCHECK(new_f != nullptr);
-    field_.Assign(new_f);
-  }
-
   mirror::ArtField* GetField() SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
     return field_.Get();
   }
diff --git a/runtime/gc/collector/mark_compact.cc b/runtime/gc/collector/mark_compact.cc
index 4044852..b3bed64 100644
--- a/runtime/gc/collector/mark_compact.cc
+++ b/runtime/gc/collector/mark_compact.cc
@@ -547,8 +547,11 @@
 }
 
 void MarkCompact::SweepLargeObjects(bool swap_bitmaps) {
-  TimingLogger::ScopedTiming t(__FUNCTION__, GetTimings());
-  RecordFreeLOS(heap_->GetLargeObjectsSpace()->Sweep(swap_bitmaps));
+  space::LargeObjectSpace* los = heap_->GetLargeObjectsSpace();
+  if (los != nullptr) {
+    TimingLogger::ScopedTiming t(__FUNCTION__, GetTimings());\
+    RecordFreeLOS(los->Sweep(swap_bitmaps));
+  }
 }
 
 // Process the "referent" field in a java.lang.ref.Reference.  If the referent has not yet been
diff --git a/runtime/gc/collector/mark_sweep.cc b/runtime/gc/collector/mark_sweep.cc
index 95530be..930499a 100644
--- a/runtime/gc/collector/mark_sweep.cc
+++ b/runtime/gc/collector/mark_sweep.cc
@@ -374,7 +374,8 @@
     }
     space::LargeObjectSpace* large_object_space = mark_sweep_->GetHeap()->GetLargeObjectsSpace();
     if (UNLIKELY(obj == nullptr || !IsAligned<kPageSize>(obj) ||
-                 (kIsDebugBuild && !large_object_space->Contains(obj)))) {
+                 (kIsDebugBuild && large_object_space != nullptr &&
+                     !large_object_space->Contains(obj)))) {
       LOG(ERROR) << "Tried to mark " << obj << " not contained by any spaces";
       LOG(ERROR) << "Attempting see if it's a bad root";
       mark_sweep_->VerifyRoots();
@@ -481,7 +482,7 @@
   // See if the root is on any space bitmap.
   if (heap_->GetLiveBitmap()->GetContinuousSpaceBitmap(root) == nullptr) {
     space::LargeObjectSpace* large_object_space = GetHeap()->GetLargeObjectsSpace();
-    if (!large_object_space->Contains(root)) {
+    if (large_object_space != nullptr && !large_object_space->Contains(root)) {
       LOG(ERROR) << "Found invalid root: " << root << " with type " << root_type;
       if (visitor != NULL) {
         LOG(ERROR) << visitor->DescribeLocation() << " in VReg: " << vreg;
@@ -1074,20 +1075,22 @@
   }
   // Handle the large object space.
   space::LargeObjectSpace* large_object_space = GetHeap()->GetLargeObjectsSpace();
-  accounting::LargeObjectBitmap* large_live_objects = large_object_space->GetLiveBitmap();
-  accounting::LargeObjectBitmap* large_mark_objects = large_object_space->GetMarkBitmap();
-  if (swap_bitmaps) {
-    std::swap(large_live_objects, large_mark_objects);
-  }
-  for (size_t i = 0; i < count; ++i) {
-    Object* obj = objects[i];
-    // Handle large objects.
-    if (kUseThreadLocalAllocationStack && obj == nullptr) {
-      continue;
+  if (large_object_space != nullptr) {
+    accounting::LargeObjectBitmap* large_live_objects = large_object_space->GetLiveBitmap();
+    accounting::LargeObjectBitmap* large_mark_objects = large_object_space->GetMarkBitmap();
+    if (swap_bitmaps) {
+      std::swap(large_live_objects, large_mark_objects);
     }
-    if (!large_mark_objects->Test(obj)) {
-      ++freed_los.objects;
-      freed_los.bytes += large_object_space->Free(self, obj);
+    for (size_t i = 0; i < count; ++i) {
+      Object* obj = objects[i];
+      // Handle large objects.
+      if (kUseThreadLocalAllocationStack && obj == nullptr) {
+        continue;
+      }
+      if (!large_mark_objects->Test(obj)) {
+        ++freed_los.objects;
+        freed_los.bytes += large_object_space->Free(self, obj);
+      }
     }
   }
   {
@@ -1125,8 +1128,11 @@
 }
 
 void MarkSweep::SweepLargeObjects(bool swap_bitmaps) {
-  TimingLogger::ScopedTiming split(__FUNCTION__, GetTimings());
-  RecordFreeLOS(heap_->GetLargeObjectsSpace()->Sweep(swap_bitmaps));
+  space::LargeObjectSpace* los = heap_->GetLargeObjectsSpace();
+  if (los != nullptr) {
+    TimingLogger::ScopedTiming split(__FUNCTION__, GetTimings());
+    RecordFreeLOS(los->Sweep(swap_bitmaps));
+  }
 }
 
 // Process the "referent" field in a java.lang.ref.Reference.  If the referent has not yet been
diff --git a/runtime/gc/collector/semi_space.cc b/runtime/gc/collector/semi_space.cc
index 8fb33ce..c8fa869 100644
--- a/runtime/gc/collector/semi_space.cc
+++ b/runtime/gc/collector/semi_space.cc
@@ -365,23 +365,23 @@
   }
 
   CHECK_EQ(is_large_object_space_immune_, collect_from_space_only_);
-  if (is_large_object_space_immune_) {
+  space::LargeObjectSpace* los = GetHeap()->GetLargeObjectsSpace();
+  if (is_large_object_space_immune_ && los != nullptr) {
     TimingLogger::ScopedTiming t("VisitLargeObjects", GetTimings());
     DCHECK(collect_from_space_only_);
     // Delay copying the live set to the marked set until here from
     // BindBitmaps() as the large objects on the allocation stack may
     // be newly added to the live set above in MarkAllocStackAsLive().
-    GetHeap()->GetLargeObjectsSpace()->CopyLiveToMarked();
+    los->CopyLiveToMarked();
 
     // When the large object space is immune, we need to scan the
     // large object space as roots as they contain references to their
     // classes (primitive array classes) that could move though they
     // don't contain any other references.
-    space::LargeObjectSpace* large_object_space = GetHeap()->GetLargeObjectsSpace();
-    accounting::LargeObjectBitmap* large_live_bitmap = large_object_space->GetLiveBitmap();
+    accounting::LargeObjectBitmap* large_live_bitmap = los->GetLiveBitmap();
     SemiSpaceScanObjectVisitor visitor(this);
-    large_live_bitmap->VisitMarkedRange(reinterpret_cast<uintptr_t>(large_object_space->Begin()),
-                                        reinterpret_cast<uintptr_t>(large_object_space->End()),
+    large_live_bitmap->VisitMarkedRange(reinterpret_cast<uintptr_t>(los->Begin()),
+                                        reinterpret_cast<uintptr_t>(los->End()),
                                         visitor);
   }
   // Recursively process the mark stack.
@@ -655,8 +655,11 @@
 
 void SemiSpace::SweepLargeObjects(bool swap_bitmaps) {
   DCHECK(!is_large_object_space_immune_);
-  TimingLogger::ScopedTiming split("SweepLargeObjects", GetTimings());
-  RecordFreeLOS(heap_->GetLargeObjectsSpace()->Sweep(swap_bitmaps));
+  space::LargeObjectSpace* los = heap_->GetLargeObjectsSpace();
+  if (los != nullptr) {
+    TimingLogger::ScopedTiming split("SweepLargeObjects", GetTimings());
+    RecordFreeLOS(los->Sweep(swap_bitmaps));
+  }
 }
 
 // Process the "referent" field in a java.lang.ref.Reference.  If the referent has not yet been
@@ -751,6 +754,7 @@
   from_space_ = nullptr;
   CHECK(mark_stack_->IsEmpty());
   mark_stack_->Reset();
+  space::LargeObjectSpace* los = GetHeap()->GetLargeObjectsSpace();
   if (generational_) {
     // Decide whether to do a whole heap collection or a bump pointer
     // only space collection at the next collection by updating
@@ -762,7 +766,7 @@
       bytes_promoted_since_last_whole_heap_collection_ += bytes_promoted_;
       bool bytes_promoted_threshold_exceeded =
           bytes_promoted_since_last_whole_heap_collection_ >= kBytesPromotedThreshold;
-      uint64_t current_los_bytes_allocated = GetHeap()->GetLargeObjectsSpace()->GetBytesAllocated();
+      uint64_t current_los_bytes_allocated = los != nullptr ? los->GetBytesAllocated() : 0U;
       uint64_t last_los_bytes_allocated =
           large_object_bytes_allocated_at_last_whole_heap_collection_;
       bool large_object_bytes_threshold_exceeded =
@@ -775,7 +779,7 @@
       // Reset the counters.
       bytes_promoted_since_last_whole_heap_collection_ = bytes_promoted_;
       large_object_bytes_allocated_at_last_whole_heap_collection_ =
-          GetHeap()->GetLargeObjectsSpace()->GetBytesAllocated();
+          los != nullptr ? los->GetBytesAllocated() : 0U;
       collect_from_space_only_ = true;
     }
   }
diff --git a/runtime/gc/collector/sticky_mark_sweep.cc b/runtime/gc/collector/sticky_mark_sweep.cc
index 5a58446..4ed6abc 100644
--- a/runtime/gc/collector/sticky_mark_sweep.cc
+++ b/runtime/gc/collector/sticky_mark_sweep.cc
@@ -16,7 +16,7 @@
 
 #include "gc/heap.h"
 #include "gc/space/large_object_space.h"
-#include "gc/space/space.h"
+#include "gc/space/space-inl.h"
 #include "sticky_mark_sweep.h"
 #include "thread-inl.h"
 
@@ -32,7 +32,6 @@
 
 void StickyMarkSweep::BindBitmaps() {
   PartialMarkSweep::BindBitmaps();
-
   WriterMutexLock mu(Thread::Current(), *Locks::heap_bitmap_lock_);
   // For sticky GC, we want to bind the bitmaps of all spaces as the allocation stack lets us
   // know what was allocated since the last GC. A side-effect of binding the allocation space mark
@@ -44,7 +43,10 @@
       space->AsContinuousMemMapAllocSpace()->BindLiveToMarkBitmap();
     }
   }
-  GetHeap()->GetLargeObjectsSpace()->CopyLiveToMarked();
+  for (const auto& space : GetHeap()->GetDiscontinuousSpaces()) {
+    CHECK(space->IsLargeObjectSpace());
+    space->AsLargeObjectSpace()->CopyLiveToMarked();
+  }
 }
 
 void StickyMarkSweep::MarkReachableObjects() {
diff --git a/runtime/gc/heap.cc b/runtime/gc/heap.cc
index bb7da0d..3e3b964 100644
--- a/runtime/gc/heap.cc
+++ b/runtime/gc/heap.cc
@@ -83,13 +83,6 @@
 // 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.0;
-// Whether or not we use the free list large object space. Only use it if USE_ART_LOW_4G_ALLOCATOR
-// since this means that we have to use the slow msync loop in MemMap::MapAnonymous.
-#if USE_ART_LOW_4G_ALLOCATOR
-static constexpr bool kUseFreeListSpaceForLOS = true;
-#else
-static constexpr bool kUseFreeListSpaceForLOS = false;
-#endif
 // Whether or not we compact the zygote in PreZygoteFork.
 static constexpr bool kCompactZygote = kMovingCollector;
 // How many reserve entries are at the end of the allocation stack, these are only needed if the
@@ -107,8 +100,9 @@
            double target_utilization, double foreground_heap_growth_multiplier,
            size_t capacity, size_t non_moving_space_capacity, const std::string& image_file_name,
            const InstructionSet image_instruction_set, CollectorType foreground_collector_type,
-           CollectorType background_collector_type, size_t parallel_gc_threads,
-           size_t conc_gc_threads, bool low_memory_mode,
+           CollectorType background_collector_type,
+           space::LargeObjectSpaceType large_object_space_type, size_t large_object_threshold,
+           size_t parallel_gc_threads, size_t conc_gc_threads, bool low_memory_mode,
            size_t long_pause_log_threshold, size_t long_gc_log_threshold,
            bool ignore_max_footprint, bool use_tlab,
            bool verify_pre_gc_heap, bool verify_pre_sweeping_heap, bool verify_post_gc_heap,
@@ -135,7 +129,7 @@
       ignore_max_footprint_(ignore_max_footprint),
       zygote_creation_lock_("zygote creation lock", kZygoteCreationLock),
       zygote_space_(nullptr),
-      large_object_threshold_(kDefaultLargeObjectThreshold),  // Starts out disabled.
+      large_object_threshold_(large_object_threshold),
       collector_type_running_(kCollectorTypeNone),
       last_gc_type_(collector::kGcTypeNone),
       next_gc_type_(collector::kGcTypePartial),
@@ -338,13 +332,21 @@
   CHECK(non_moving_space_ != nullptr);
   CHECK(!non_moving_space_->CanMoveObjects());
   // Allocate the large object space.
-  if (kUseFreeListSpaceForLOS) {
-    large_object_space_ = space::FreeListSpace::Create("large object space", nullptr, capacity_);
+  if (large_object_space_type == space::kLargeObjectSpaceTypeFreeList) {
+    large_object_space_ = space::FreeListSpace::Create("free list large object space", nullptr,
+                                                       capacity_);
+    CHECK(large_object_space_ != nullptr) << "Failed to create large object space";
+  } else if (large_object_space_type == space::kLargeObjectSpaceTypeMap) {
+    large_object_space_ = space::LargeObjectMapSpace::Create("mem map large object space");
+    CHECK(large_object_space_ != nullptr) << "Failed to create large object space";
   } else {
-    large_object_space_ = space::LargeObjectMapSpace::Create("large object space");
+    // Disable the large object space by making the cutoff excessively large.
+    large_object_threshold_ = std::numeric_limits<size_t>::max();
+    large_object_space_ = nullptr;
   }
-  CHECK(large_object_space_ != nullptr) << "Failed to create large object space";
-  AddSpace(large_object_space_);
+  if (large_object_space_ != nullptr) {
+    AddSpace(large_object_space_);
+  }
   // Compute heap capacity. Continuous spaces are sorted in order of Begin().
   CHECK(!continuous_spaces_.empty());
   // Relies on the spaces being sorted.
@@ -712,7 +714,8 @@
   CHECK(space1 != nullptr);
   CHECK(space2 != nullptr);
   MarkAllocStack(space1->GetLiveBitmap(), space2->GetLiveBitmap(),
-                 large_object_space_->GetLiveBitmap(), stack);
+                 (large_object_space_ != nullptr ? large_object_space_->GetLiveBitmap() : nullptr),
+                 stack);
 }
 
 void Heap::DeleteThreadPool() {
@@ -1002,7 +1005,10 @@
       total_alloc_space_size += malloc_space->Size();
     }
   }
-  total_alloc_space_allocated = GetBytesAllocated() - large_object_space_->GetBytesAllocated();
+  total_alloc_space_allocated = GetBytesAllocated();
+  if (large_object_space_ != nullptr) {
+    total_alloc_space_allocated -= large_object_space_->GetBytesAllocated();
+  }
   if (bump_pointer_space_ != nullptr) {
     total_alloc_space_allocated -= bump_pointer_space_->Size();
   }
@@ -2018,6 +2024,7 @@
       } else if (bitmap2->HasAddress(obj)) {
         bitmap2->Set(obj);
       } else {
+        DCHECK(large_objects != nullptr);
         large_objects->Set(obj);
       }
     }
diff --git a/runtime/gc/heap.h b/runtime/gc/heap.h
index 351e1c6..faaea40 100644
--- a/runtime/gc/heap.h
+++ b/runtime/gc/heap.h
@@ -30,6 +30,7 @@
 #include "gc/collector/garbage_collector.h"
 #include "gc/collector/gc_type.h"
 #include "gc/collector_type.h"
+#include "gc/space/large_object_space.h"
 #include "globals.h"
 #include "gtest/gtest.h"
 #include "instruction_set.h"
@@ -129,8 +130,6 @@
  public:
   // If true, measure the total allocation time.
   static constexpr bool kMeasureAllocationTime = false;
-  // Primitive arrays larger than this size are put in the large object space.
-  static constexpr size_t kDefaultLargeObjectThreshold = 3 * kPageSize;
   static constexpr size_t kDefaultStartingSize = kPageSize;
   static constexpr size_t kDefaultInitialSize = 2 * MB;
   static constexpr size_t kDefaultMaximumSize = 256 * MB;
@@ -142,7 +141,17 @@
   static constexpr size_t kDefaultTLABSize = 256 * KB;
   static constexpr double kDefaultTargetUtilization = 0.5;
   static constexpr double kDefaultHeapGrowthMultiplier = 2.0;
-
+  // Primitive arrays larger than this size are put in the large object space.
+  static constexpr size_t kDefaultLargeObjectThreshold = 3 * kPageSize;
+  // Whether or not we use the free list large object space. Only use it if USE_ART_LOW_4G_ALLOCATOR
+  // since this means that we have to use the slow msync loop in MemMap::MapAnonymous.
+#if USE_ART_LOW_4G_ALLOCATOR
+  static constexpr space::LargeObjectSpaceType kDefaultLargeObjectSpaceType =
+      space::kLargeObjectSpaceTypeFreeList;
+#else
+  static constexpr space::LargeObjectSpaceType kDefaultLargeObjectSpaceType =
+      space::kLargeObjectSpaceTypeMap;
+#endif
   // Used so that we don't overflow the allocation time atomic integer.
   static constexpr size_t kTimeAdjust = 1024;
 
@@ -161,6 +170,7 @@
                 const std::string& original_image_file_name,
                 InstructionSet image_instruction_set,
                 CollectorType foreground_collector_type, CollectorType background_collector_type,
+                space::LargeObjectSpaceType large_object_space_type, size_t large_object_threshold,
                 size_t parallel_gc_threads, size_t conc_gc_threads, bool low_memory_mode,
                 size_t long_pause_threshold, size_t long_gc_threshold,
                 bool ignore_max_footprint, bool use_tlab,
diff --git a/runtime/gc/reference_processor.cc b/runtime/gc/reference_processor.cc
index d3641d1..75de623 100644
--- a/runtime/gc/reference_processor.cc
+++ b/runtime/gc/reference_processor.cc
@@ -30,8 +30,13 @@
 
 ReferenceProcessor::ReferenceProcessor()
     : process_references_args_(nullptr, nullptr, nullptr),
-      preserving_references_(false), lock_("reference processor lock", kReferenceProcessorLock),
-      condition_("reference processor condition", lock_) {
+      preserving_references_(false),
+      condition_("reference processor condition", *Locks::reference_processor_lock_) ,
+      soft_reference_queue_(Locks::reference_queue_soft_references_lock_),
+      weak_reference_queue_(Locks::reference_queue_weak_references_lock_),
+      finalizer_reference_queue_(Locks::reference_queue_finalizer_references_lock_),
+      phantom_reference_queue_(Locks::reference_queue_phantom_references_lock_),
+      cleared_references_(Locks::reference_queue_cleared_references_lock_) {
 }
 
 void ReferenceProcessor::EnableSlowPath() {
@@ -50,7 +55,7 @@
   if (UNLIKELY(!SlowPathEnabled()) || referent == nullptr) {
     return referent;
   }
-  MutexLock mu(self, lock_);
+  MutexLock mu(self, *Locks::reference_processor_lock_);
   while (SlowPathEnabled()) {
     mirror::HeapReference<mirror::Object>* const referent_addr =
         reference->GetReferentReferenceAddr();
@@ -93,12 +98,12 @@
 }
 
 void ReferenceProcessor::StartPreservingReferences(Thread* self) {
-  MutexLock mu(self, lock_);
+  MutexLock mu(self, *Locks::reference_processor_lock_);
   preserving_references_ = true;
 }
 
 void ReferenceProcessor::StopPreservingReferences(Thread* self) {
-  MutexLock mu(self, lock_);
+  MutexLock mu(self, *Locks::reference_processor_lock_);
   preserving_references_ = false;
   // We are done preserving references, some people who are blocked may see a marked referent.
   condition_.Broadcast(self);
@@ -114,7 +119,7 @@
   TimingLogger::ScopedTiming t(concurrent ? __FUNCTION__ : "(Paused)ProcessReferences", timings);
   Thread* self = Thread::Current();
   {
-    MutexLock mu(self, lock_);
+    MutexLock mu(self, *Locks::reference_processor_lock_);
     process_references_args_.is_marked_callback_ = is_marked_callback;
     process_references_args_.mark_callback_ = mark_object_callback;
     process_references_args_.arg_ = arg;
@@ -163,7 +168,7 @@
   DCHECK(finalizer_reference_queue_.IsEmpty());
   DCHECK(phantom_reference_queue_.IsEmpty());
   {
-    MutexLock mu(self, lock_);
+    MutexLock mu(self, *Locks::reference_processor_lock_);
     // Need to always do this since the next GC may be concurrent. Doing this for only concurrent
     // could result in a stale is_marked_callback_ being called before the reference processing
     // starts since there is a small window of time where slow_path_enabled_ is enabled but the
@@ -225,5 +230,31 @@
   }
 }
 
+bool ReferenceProcessor::MakeCircularListIfUnenqueued(mirror::FinalizerReference* reference) {
+  Thread* self = Thread::Current();
+  MutexLock mu(self, *Locks::reference_processor_lock_);
+  // Wait untul we are done processing reference.
+  while (SlowPathEnabled()) {
+    condition_.Wait(self);
+  }
+  // At this point, since the sentinel of the reference is live, it is guaranteed to not be
+  // enqueued if we just finished processing references. Otherwise, we may be doing the main GC
+  // phase. Since we are holding the reference processor lock, it guarantees that reference
+  // processing can't begin. The GC could have just enqueued the reference one one of the internal
+  // GC queues, but since we hold the lock finalizer_reference_queue_ lock it also prevents this
+  // race.
+  MutexLock mu2(self, *Locks::reference_queue_finalizer_references_lock_);
+  if (!reference->IsEnqueued()) {
+    CHECK(reference->IsFinalizerReferenceInstance());
+    if (Runtime::Current()->IsActiveTransaction()) {
+      reference->SetPendingNext<true>(reference);
+    } else {
+      reference->SetPendingNext<false>(reference);
+    }
+    return true;
+  }
+  return false;
+}
+
 }  // namespace gc
 }  // namespace art
diff --git a/runtime/gc/reference_processor.h b/runtime/gc/reference_processor.h
index 7274457..5eb095b 100644
--- a/runtime/gc/reference_processor.h
+++ b/runtime/gc/reference_processor.h
@@ -28,6 +28,7 @@
 class TimingLogger;
 
 namespace mirror {
+class FinalizerReference;
 class Object;
 class Reference;
 }  // namespace mirror
@@ -48,20 +49,25 @@
                          ProcessMarkStackCallback* process_mark_stack_callback, void* arg)
       SHARED_LOCKS_REQUIRED(Locks::mutator_lock_)
       EXCLUSIVE_LOCKS_REQUIRED(Locks::heap_bitmap_lock_)
-      LOCKS_EXCLUDED(lock_);
+      LOCKS_EXCLUDED(Locks::reference_processor_lock_);
   // The slow path bool is contained in the reference class object, can only be set once
   // Only allow setting this with mutators suspended so that we can avoid using a lock in the
   // GetReferent fast path as an optimization.
   void EnableSlowPath() EXCLUSIVE_LOCKS_REQUIRED(Locks::mutator_lock_);
   // Decode the referent, may block if references are being processed.
   mirror::Object* GetReferent(Thread* self, mirror::Reference* reference)
-      SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) LOCKS_EXCLUDED(lock_);
+      SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) LOCKS_EXCLUDED(Locks::reference_processor_lock_);
   void EnqueueClearedReferences(Thread* self) LOCKS_EXCLUDED(Locks::mutator_lock_);
   void DelayReferenceReferent(mirror::Class* klass, mirror::Reference* ref,
                               IsHeapReferenceMarkedCallback* is_marked_callback, void* arg)
       SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
   void UpdateRoots(IsMarkedCallback* callback, void* arg)
       SHARED_LOCKS_REQUIRED(Locks::mutator_lock_, Locks::heap_bitmap_lock_);
+  // Make a circular list with reference if it is not enqueued. Uses the finalizer queue lock.
+  bool MakeCircularListIfUnenqueued(mirror::FinalizerReference* reference)
+      SHARED_LOCKS_REQUIRED(Locks::mutator_lock_)
+      LOCKS_EXCLUDED(Locks::reference_processor_lock_,
+                     Locks::reference_queue_finalizer_references_lock_);
 
  private:
   class ProcessReferencesArgs {
@@ -78,23 +84,21 @@
   };
   bool SlowPathEnabled() SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
   // Called by ProcessReferences.
-  void DisableSlowPath(Thread* self) EXCLUSIVE_LOCKS_REQUIRED(lock_)
+  void DisableSlowPath(Thread* self) EXCLUSIVE_LOCKS_REQUIRED(Locks::reference_processor_lock_)
       SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
   // If we are preserving references it means that some dead objects may become live, we use start
   // and stop preserving to block mutators using GetReferrent from getting access to these
   // referents.
-  void StartPreservingReferences(Thread* self) LOCKS_EXCLUDED(lock_);
-  void StopPreservingReferences(Thread* self) LOCKS_EXCLUDED(lock_);
+  void StartPreservingReferences(Thread* self) LOCKS_EXCLUDED(Locks::reference_processor_lock_);
+  void StopPreservingReferences(Thread* self) LOCKS_EXCLUDED(Locks::reference_processor_lock_);
   // Process args, used by the GetReferent to return referents which are already marked.
-  ProcessReferencesArgs process_references_args_ GUARDED_BY(lock_);
+  ProcessReferencesArgs process_references_args_ GUARDED_BY(Locks::reference_processor_lock_);
   // Boolean for whether or not we are preserving references (either soft references or finalizers).
   // If this is true, then we cannot return a referent (see comment in GetReferent).
-  bool preserving_references_ GUARDED_BY(lock_);
-  // Lock that guards the reference processing.
-  Mutex lock_ DEFAULT_MUTEX_ACQUIRED_AFTER;
+  bool preserving_references_ GUARDED_BY(Locks::reference_processor_lock_);
   // Condition that people wait on if they attempt to get the referent of a reference while
   // processing is in progress.
-  ConditionVariable condition_ GUARDED_BY(lock_);
+  ConditionVariable condition_ GUARDED_BY(Locks::reference_processor_lock_);
   // Reference queues used by the GC.
   ReferenceQueue soft_reference_queue_;
   ReferenceQueue weak_reference_queue_;
diff --git a/runtime/gc/reference_queue.cc b/runtime/gc/reference_queue.cc
index c3931e8..4003524 100644
--- a/runtime/gc/reference_queue.cc
+++ b/runtime/gc/reference_queue.cc
@@ -25,13 +25,12 @@
 namespace art {
 namespace gc {
 
-ReferenceQueue::ReferenceQueue()
-    : lock_("reference queue lock"), list_(nullptr) {
+ReferenceQueue::ReferenceQueue(Mutex* lock) : lock_(lock), list_(nullptr) {
 }
 
 void ReferenceQueue::AtomicEnqueueIfNotEnqueued(Thread* self, mirror::Reference* ref) {
   DCHECK(ref != NULL);
-  MutexLock mu(self, lock_);
+  MutexLock mu(self, *lock_);
   if (!ref->IsEnqueued()) {
     EnqueuePendingReference(ref);
   }
diff --git a/runtime/gc/reference_queue.h b/runtime/gc/reference_queue.h
index cd814bb..dbf4abc 100644
--- a/runtime/gc/reference_queue.h
+++ b/runtime/gc/reference_queue.h
@@ -44,7 +44,7 @@
 // java.lang.ref.Reference objects.
 class ReferenceQueue {
  public:
-  explicit ReferenceQueue();
+  explicit ReferenceQueue(Mutex* lock);
   // Enqueue a reference if is not already enqueued. Thread safe to call from multiple threads
   // since it uses a lock to avoid a race between checking for the references presence and adding
   // it.
@@ -90,7 +90,7 @@
  private:
   // Lock, used for parallel GC reference enqueuing. It allows for multiple threads simultaneously
   // calling AtomicEnqueueIfNotEnqueued.
-  Mutex lock_ DEFAULT_MUTEX_ACQUIRED_AFTER;
+  Mutex* lock_;
   // The actual reference list. Only a root for the mark compact GC since it will be null for other
   // GC types.
   mirror::Reference* list_;
diff --git a/runtime/gc/space/large_object_space.cc b/runtime/gc/space/large_object_space.cc
index 2a43712..dad5855 100644
--- a/runtime/gc/space/large_object_space.cc
+++ b/runtime/gc/space/large_object_space.cc
@@ -120,7 +120,7 @@
   mirror::Object* obj = reinterpret_cast<mirror::Object*>(mem_map->Begin());
   large_objects_.push_back(obj);
   mem_maps_.Put(obj, mem_map);
-  size_t allocation_size = mem_map->Size();
+  const size_t allocation_size = mem_map->BaseSize();
   DCHECK(bytes_allocated != nullptr);
   begin_ = std::min(begin_, reinterpret_cast<byte*>(obj));
   byte* obj_end = reinterpret_cast<byte*>(obj) + allocation_size;
@@ -145,8 +145,9 @@
     Runtime::Current()->GetHeap()->DumpSpaces(LOG(ERROR));
     LOG(FATAL) << "Attempted to free large object " << ptr << " which was not live";
   }
-  DCHECK_GE(num_bytes_allocated_, found->second->Size());
-  size_t allocation_size = found->second->Size();
+  const size_t map_size = found->second->BaseSize();
+  DCHECK_GE(num_bytes_allocated_, map_size);
+  size_t allocation_size = map_size;
   num_bytes_allocated_ -= allocation_size;
   --num_objects_allocated_;
   delete found->second;
@@ -158,7 +159,7 @@
   MutexLock mu(Thread::Current(), lock_);
   auto found = mem_maps_.find(obj);
   CHECK(found != mem_maps_.end()) << "Attempted to get size of a large object which is not live";
-  return found->second->Size();
+  return found->second->BaseSize();
 }
 
 size_t LargeObjectSpace::FreeList(Thread* self, size_t num_ptrs, mirror::Object** ptrs) {
diff --git a/runtime/gc/space/large_object_space.h b/runtime/gc/space/large_object_space.h
index 9d5e090..a63c5c0 100644
--- a/runtime/gc/space/large_object_space.h
+++ b/runtime/gc/space/large_object_space.h
@@ -31,6 +31,12 @@
 
 class AllocationInfo;
 
+enum LargeObjectSpaceType {
+  kLargeObjectSpaceTypeDisabled,
+  kLargeObjectSpaceTypeMap,
+  kLargeObjectSpaceTypeFreeList,
+};
+
 // Abstraction implemented by all large object spaces.
 class LargeObjectSpace : public DiscontinuousSpace, public AllocSpace {
  public:
diff --git a/runtime/gc/space/space_test.h b/runtime/gc/space/space_test.h
index 0291155..7211bb4 100644
--- a/runtime/gc/space/space_test.h
+++ b/runtime/gc/space/space_test.h
@@ -181,7 +181,7 @@
   // Succeeds, fits without adjusting the footprint limit.
   size_t ptr1_bytes_allocated, ptr1_usable_size;
   StackHandleScope<3> hs(soa.Self());
-  Handle<mirror::Object> ptr1(
+  MutableHandle<mirror::Object> ptr1(
       hs.NewHandle(Alloc(space, self, 1 * MB, &ptr1_bytes_allocated, &ptr1_usable_size)));
   EXPECT_TRUE(ptr1.Get() != nullptr);
   EXPECT_LE(1U * MB, ptr1_bytes_allocated);
@@ -194,7 +194,7 @@
 
   // Succeeds, adjusts the footprint.
   size_t ptr3_bytes_allocated, ptr3_usable_size;
-  Handle<mirror::Object> ptr3(
+  MutableHandle<mirror::Object> ptr3(
       hs.NewHandle(AllocWithGrowth(space, self, 8 * MB, &ptr3_bytes_allocated, &ptr3_usable_size)));
   EXPECT_TRUE(ptr3.Get() != nullptr);
   EXPECT_LE(8U * MB, ptr3_bytes_allocated);
@@ -284,7 +284,7 @@
   // Succeeds, fits without adjusting the footprint limit.
   size_t ptr1_bytes_allocated, ptr1_usable_size;
   StackHandleScope<3> hs(soa.Self());
-  Handle<mirror::Object> ptr1(
+  MutableHandle<mirror::Object> ptr1(
       hs.NewHandle(Alloc(space, self, 1 * MB, &ptr1_bytes_allocated, &ptr1_usable_size)));
   EXPECT_TRUE(ptr1.Get() != nullptr);
   EXPECT_LE(1U * MB, ptr1_bytes_allocated);
@@ -297,7 +297,7 @@
 
   // Succeeds, adjusts the footprint.
   size_t ptr3_bytes_allocated, ptr3_usable_size;
-  Handle<mirror::Object> ptr3(
+  MutableHandle<mirror::Object> ptr3(
       hs.NewHandle(AllocWithGrowth(space, self, 8 * MB, &ptr3_bytes_allocated, &ptr3_usable_size)));
   EXPECT_TRUE(ptr3.Get() != nullptr);
   EXPECT_LE(8U * MB, ptr3_bytes_allocated);
diff --git a/runtime/handle.h b/runtime/handle.h
index 06938e5..addb663 100644
--- a/runtime/handle.h
+++ b/runtime/handle.h
@@ -30,23 +30,23 @@
 
 // Handles are memory locations that contain GC roots. As the mirror::Object*s within a handle are
 // GC visible then the GC may move the references within them, something that couldn't be done with
-// a wrap pointer. Handles are generally allocated within HandleScopes. ConstHandle is a super-class
-// of Handle and doesn't support assignment operations.
+// a wrap pointer. Handles are generally allocated within HandleScopes. Handle is a super-class
+// of MutableHandle and doesn't support assignment operations.
 template<class T>
-class ConstHandle {
+class Handle {
  public:
-  ConstHandle() : reference_(nullptr) {
+  Handle() : reference_(nullptr) {
   }
 
-  ALWAYS_INLINE ConstHandle(const ConstHandle<T>& handle) : reference_(handle.reference_) {
+  ALWAYS_INLINE Handle(const Handle<T>& handle) : reference_(handle.reference_) {
   }
 
-  ALWAYS_INLINE ConstHandle<T>& operator=(const ConstHandle<T>& handle) {
+  ALWAYS_INLINE Handle<T>& operator=(const Handle<T>& handle) {
     reference_ = handle.reference_;
     return *this;
   }
 
-  ALWAYS_INLINE explicit ConstHandle(StackReference<T>* reference) : reference_(reference) {
+  ALWAYS_INLINE explicit Handle(StackReference<T>* reference) : reference_(reference) {
   }
 
   ALWAYS_INLINE T& operator*() const SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
@@ -73,11 +73,11 @@
   StackReference<T>* reference_;
 
   template<typename S>
-  explicit ConstHandle(StackReference<S>* reference)
+  explicit Handle(StackReference<S>* reference)
       : reference_(reinterpret_cast<StackReference<T>*>(reference)) {
   }
   template<typename S>
-  explicit ConstHandle(const ConstHandle<S>& handle)
+  explicit Handle(const Handle<S>& handle)
       : reference_(reinterpret_cast<StackReference<T>*>(handle.reference_)) {
   }
 
@@ -91,7 +91,7 @@
 
  private:
   friend class BuildGenericJniFrameVisitor;
-  template<class S> friend class ConstHandle;
+  template<class S> friend class Handle;
   friend class HandleScope;
   template<class S> friend class HandleWrapper;
   template<size_t kNumReferences> friend class StackHandleScope;
@@ -99,42 +99,43 @@
 
 // Handles that support assignment.
 template<class T>
-class Handle : public ConstHandle<T> {
+class MutableHandle : public Handle<T> {
  public:
-  Handle() {
+  MutableHandle() {
   }
 
-  ALWAYS_INLINE Handle(const Handle<T>& handle) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_)
-      : ConstHandle<T>(handle.reference_) {
+  ALWAYS_INLINE MutableHandle(const MutableHandle<T>& handle)
+      SHARED_LOCKS_REQUIRED(Locks::mutator_lock_)
+      : Handle<T>(handle.reference_) {
   }
 
-  ALWAYS_INLINE Handle<T>& operator=(const Handle<T>& handle)
+  ALWAYS_INLINE MutableHandle<T>& operator=(const MutableHandle<T>& handle)
       SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
-    ConstHandle<T>::operator=(handle);
+    Handle<T>::operator=(handle);
     return *this;
   }
 
-  ALWAYS_INLINE explicit Handle(StackReference<T>* reference)
+  ALWAYS_INLINE explicit MutableHandle(StackReference<T>* reference)
       SHARED_LOCKS_REQUIRED(Locks::mutator_lock_)
-      : ConstHandle<T>(reference) {
+      : Handle<T>(reference) {
   }
 
   ALWAYS_INLINE T* Assign(T* reference) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
-    StackReference<T>* ref = ConstHandle<T>::GetReference();
+    StackReference<T>* ref = Handle<T>::GetReference();
     T* const old = ref->AsMirrorPtr();
     ref->Assign(reference);
     return old;
   }
 
   template<typename S>
-  explicit Handle(const Handle<S>& handle) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_)
-      : ConstHandle<T>(handle) {
+  explicit MutableHandle(const MutableHandle<S>& handle) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_)
+      : Handle<T>(handle) {
   }
 
  protected:
   template<typename S>
-  explicit Handle(StackReference<S>* reference) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_)
-      : ConstHandle<T>(reference) {
+  explicit MutableHandle(StackReference<S>* reference) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_)
+      : Handle<T>(reference) {
   }
 
  private:
@@ -146,9 +147,9 @@
 
 // A special case of Handle that only holds references to null.
 template<class T>
-class NullHandle : public ConstHandle<T> {
+class NullHandle : public Handle<T> {
  public:
-  NullHandle() : ConstHandle<T>(&null_ref_) {
+  NullHandle() : Handle<T>(&null_ref_) {
   }
 
  private:
diff --git a/runtime/handle_scope.h b/runtime/handle_scope.h
index 42ef779..99059f9 100644
--- a/runtime/handle_scope.h
+++ b/runtime/handle_scope.h
@@ -89,6 +89,12 @@
     return Handle<mirror::Object>(&references_[i]);
   }
 
+  MutableHandle<mirror::Object> GetMutableHandle(size_t i)
+      SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) ALWAYS_INLINE {
+    DCHECK_LT(i, number_of_references_);
+    return MutableHandle<mirror::Object>(&references_[i]);
+  }
+
   void SetReference(size_t i, mirror::Object* object) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_)
       ALWAYS_INLINE {
     DCHECK_LT(i, number_of_references_);
@@ -139,14 +145,14 @@
 // A wrapper which wraps around Object** and restores the pointer in the destructor.
 // TODO: Add more functionality.
 template<class T>
-class HandleWrapper : public Handle<T> {
+class HandleWrapper : public MutableHandle<T> {
  public:
-  HandleWrapper(T** obj, const Handle<T>& handle)
-     : Handle<T>(handle), obj_(obj) {
+  HandleWrapper(T** obj, const MutableHandle<T>& handle)
+     : MutableHandle<T>(handle), obj_(obj) {
   }
 
   ~HandleWrapper() {
-    *obj_ = Handle<T>::Get();
+    *obj_ = MutableHandle<T>::Get();
   }
 
  private:
@@ -169,10 +175,10 @@
     return references_storage_[i].AsMirrorPtr();
   }
 
-  Handle<mirror::Object> GetHandle(size_t i) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_)
+  MutableHandle<mirror::Object> GetHandle(size_t i) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_)
       ALWAYS_INLINE {
     DCHECK_LT(i, number_of_references_);
-    return Handle<mirror::Object>(&references_storage_[i]);
+    return MutableHandle<mirror::Object>(&references_storage_[i]);
   }
 
   void SetReference(size_t i, mirror::Object* object) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_)
@@ -182,9 +188,9 @@
   }
 
   template<class T>
-  Handle<T> NewHandle(T* object) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
+  MutableHandle<T> NewHandle(T* object) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
     SetReference(pos_, object);
-    Handle<T> h(GetHandle(pos_));
+    MutableHandle<T> h(GetHandle(pos_));
     pos_++;
     return h;
   }
@@ -192,7 +198,7 @@
   template<class T>
   HandleWrapper<T> NewHandleWrapper(T** object) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
     SetReference(pos_, *object);
-    Handle<T> h(GetHandle(pos_));
+    MutableHandle<T> h(GetHandle(pos_));
     pos_++;
     return HandleWrapper<T>(object, h);
   }
diff --git a/runtime/image.cc b/runtime/image.cc
index 93ec27d..478b486 100644
--- a/runtime/image.cc
+++ b/runtime/image.cc
@@ -24,7 +24,7 @@
 namespace art {
 
 const byte ImageHeader::kImageMagic[] = { 'a', 'r', 't', '\n' };
-const byte ImageHeader::kImageVersion[] = { '0', '0', '8', '\0' };
+const byte ImageHeader::kImageVersion[] = { '0', '0', '9', '\0' };
 
 ImageHeader::ImageHeader(uint32_t image_begin,
                          uint32_t image_size,
diff --git a/runtime/interpreter/interpreter_common.cc b/runtime/interpreter/interpreter_common.cc
index 2129c1b..9f08013 100644
--- a/runtime/interpreter/interpreter_common.cc
+++ b/runtime/interpreter/interpreter_common.cc
@@ -455,7 +455,7 @@
   Thread* const self_;
   StackHandleScope<1> handle_scope_;
   Handle<mirror::Throwable>* exception_;
-  Handle<mirror::ArtMethod> catch_method_;
+  MutableHandle<mirror::ArtMethod> catch_method_;
   uint32_t catch_dex_pc_;
   bool clear_exception_;
 
@@ -780,8 +780,8 @@
 }
 
 // Helper function to deal with class loading in an unstarted runtime.
-static void UnstartedRuntimeFindClass(Thread* self, ConstHandle<mirror::String> className,
-                                      ConstHandle<mirror::ClassLoader> class_loader, JValue* result,
+static void UnstartedRuntimeFindClass(Thread* self, Handle<mirror::String> className,
+                                      Handle<mirror::ClassLoader> class_loader, JValue* result,
                                       const std::string& method_name, bool initialize_class,
                                       bool abort_if_not_found)
     SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
diff --git a/runtime/method_helper-inl.h b/runtime/method_helper-inl.h
index 9af835f..143f4bc 100644
--- a/runtime/method_helper-inl.h
+++ b/runtime/method_helper-inl.h
@@ -26,7 +26,9 @@
 
 namespace art {
 
-inline bool MethodHelper::HasSameNameAndSignature(MethodHelper* other) {
+template <template <class T> class HandleKind>
+template <template <class T2> class HandleKind2>
+inline bool MethodHelperT<HandleKind>::HasSameNameAndSignature(MethodHelperT<HandleKind2>* other) {
   const DexFile* dex_file = method_->GetDexFile();
   const DexFile::MethodId& mid = dex_file->GetMethodId(GetMethod()->GetDexMethodIndex());
   if (method_->GetDexCache() == other->method_->GetDexCache()) {
@@ -43,7 +45,9 @@
   return dex_file->GetMethodSignature(mid) == other_dex_file->GetMethodSignature(other_mid);
 }
 
-inline mirror::Class* MethodHelper::GetClassFromTypeIdx(uint16_t type_idx, bool resolve) {
+template <template <class T> class HandleKind>
+inline mirror::Class* MethodHelperT<HandleKind>::GetClassFromTypeIdx(uint16_t type_idx,
+                                                                     bool resolve) {
   mirror::ArtMethod* method = GetMethod();
   mirror::Class* type = method->GetDexCacheResolvedType(type_idx);
   if (type == nullptr && resolve) {
@@ -53,7 +57,8 @@
   return type;
 }
 
-inline mirror::Class* MethodHelper::GetReturnType(bool resolve) {
+template <template <class T> class HandleKind>
+inline mirror::Class* MethodHelperT<HandleKind>::GetReturnType(bool resolve) {
   mirror::ArtMethod* method = GetMethod();
   const DexFile* dex_file = method->GetDexFile();
   const DexFile::MethodId& method_id = dex_file->GetMethodId(method->GetDexMethodIndex());
@@ -62,7 +67,8 @@
   return GetClassFromTypeIdx(return_type_idx, resolve);
 }
 
-inline mirror::String* MethodHelper::ResolveString(uint32_t string_idx) {
+template <template <class T> class HandleKind>
+inline mirror::String* MethodHelperT<HandleKind>::ResolveString(uint32_t string_idx) {
   mirror::ArtMethod* method = GetMethod();
   mirror::String* s = method->GetDexCacheStrings()->Get(string_idx);
   if (UNLIKELY(s == nullptr)) {
diff --git a/runtime/method_helper.cc b/runtime/method_helper.cc
index d6f83a8..79c2b91 100644
--- a/runtime/method_helper.cc
+++ b/runtime/method_helper.cc
@@ -25,7 +25,8 @@
 
 namespace art {
 
-mirror::String* MethodHelper::GetNameAsString(Thread* self) {
+template <template <class T> class HandleKind>
+mirror::String* MethodHelperT<HandleKind>::GetNameAsString(Thread* self) {
   const DexFile* dex_file = method_->GetDexFile();
   mirror::ArtMethod* method = method_->GetInterfaceMethodIfProxy();
   uint32_t dex_method_idx = method->GetDexMethodIndex();
@@ -36,7 +37,10 @@
                                                              dex_cache);
 }
 
-bool MethodHelper::HasSameSignatureWithDifferentClassLoaders(MethodHelper* other) {
+template <template <class T> class HandleKind>
+template <template <class T2> class HandleKind2>
+bool MethodHelperT<HandleKind>::HasSameSignatureWithDifferentClassLoaders(
+    MethodHelperT<HandleKind2>* other) {
   if (UNLIKELY(GetReturnType() != other->GetReturnType())) {
     return false;
   }
@@ -62,7 +66,8 @@
   return true;
 }
 
-uint32_t MethodHelper::FindDexMethodIndexInOtherDexFile(const DexFile& other_dexfile)
+template <template <class T> class HandleKind>
+uint32_t MethodHelperT<HandleKind>::FindDexMethodIndexInOtherDexFile(const DexFile& other_dexfile)
     SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
   mirror::ArtMethod* method = GetMethod();
   const DexFile* dexfile = method->GetDexFile();
@@ -102,8 +107,9 @@
   return DexFile::kDexNoIndex;
 }
 
-uint32_t MethodHelper::FindDexMethodIndexInOtherDexFile(const DexFile& other_dexfile,
-                                                        uint32_t name_and_signature_idx)
+template <template <typename> class HandleKind>
+uint32_t MethodHelperT<HandleKind>::FindDexMethodIndexInOtherDexFile(
+    const DexFile& other_dexfile, uint32_t name_and_signature_idx)
     SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
   mirror::ArtMethod* method = GetMethod();
   const DexFile* dexfile = method->GetDexFile();
@@ -133,4 +139,38 @@
   return DexFile::kDexNoIndex;
 }
 
+// Instantiate methods.
+template mirror::String* MethodHelperT<Handle>::GetNameAsString(Thread* self);
+
+template mirror::String* MethodHelperT<MutableHandle>::GetNameAsString(Thread* self);
+
+template
+uint32_t MethodHelperT<Handle>::FindDexMethodIndexInOtherDexFile(const DexFile& other_dexfile);
+template
+uint32_t MethodHelperT<MutableHandle>::FindDexMethodIndexInOtherDexFile(
+    const DexFile& other_dexfile);
+
+template
+uint32_t MethodHelperT<Handle>::FindDexMethodIndexInOtherDexFile(const DexFile& other_dexfile,
+                                                                 uint32_t name_and_signature_idx);
+template
+uint32_t MethodHelperT<MutableHandle>::FindDexMethodIndexInOtherDexFile(
+    const DexFile& other_dexfile, uint32_t name_and_signature_idx);
+
+template
+bool MethodHelperT<Handle>::HasSameSignatureWithDifferentClassLoaders<Handle>(
+    MethodHelperT<Handle>* other);
+
+template
+bool MethodHelperT<Handle>::HasSameSignatureWithDifferentClassLoaders<MutableHandle>(
+    MethodHelperT<MutableHandle>* other);
+
+template
+bool MethodHelperT<MutableHandle>::HasSameSignatureWithDifferentClassLoaders<Handle>(
+    MethodHelperT<Handle>* other);
+
+template
+bool MethodHelperT<MutableHandle>::HasSameSignatureWithDifferentClassLoaders<MutableHandle>(
+    MethodHelperT<MutableHandle>* other);
+
 }  // namespace art
diff --git a/runtime/method_helper.h b/runtime/method_helper.h
index 8150456..fe364d3 100644
--- a/runtime/method_helper.h
+++ b/runtime/method_helper.h
@@ -24,17 +24,11 @@
 
 namespace art {
 
-class MethodHelper {
+template <template <class T> class HandleKind>
+class MethodHelperT {
  public:
-  explicit MethodHelper(Handle<mirror::ArtMethod> m) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_)
-      : method_(m), shorty_(nullptr), shorty_len_(0) {
-    SetMethod(m.Get());
-  }
-
-  void ChangeMethod(mirror::ArtMethod* new_m) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
-    DCHECK(new_m != nullptr);
-    SetMethod(new_m);
-    shorty_ = nullptr;
+  explicit MethodHelperT(HandleKind<mirror::ArtMethod> m)
+      SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) : method_(m), shorty_(nullptr), shorty_len_(0) {
   }
 
   mirror::ArtMethod* GetMethod() const SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
@@ -110,10 +104,12 @@
     return GetParamPrimitiveType(param) == Primitive::kPrimNot;
   }
 
-  ALWAYS_INLINE bool HasSameNameAndSignature(MethodHelper* other)
+  template <template <class T> class HandleKind2>
+  ALWAYS_INLINE bool HasSameNameAndSignature(MethodHelperT<HandleKind2>* other)
       SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
 
-  bool HasSameSignatureWithDifferentClassLoaders(MethodHelper* other)
+  template <template <class T> class HandleKind2>
+  bool HasSameSignatureWithDifferentClassLoaders(MethodHelperT<HandleKind2>* other)
       SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
 
   mirror::Class* GetClassFromTypeIdx(uint16_t type_idx, bool resolve = true)
@@ -130,6 +126,33 @@
                                             uint32_t name_and_signature_idx)
       SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
 
+ protected:
+  HandleKind<mirror::ArtMethod> method_;
+
+  const char* shorty_;
+  uint32_t shorty_len_;
+
+ private:
+  template <template <class T2> class HandleKind2> friend class MethodHelperT;
+
+  DISALLOW_COPY_AND_ASSIGN(MethodHelperT);
+};
+
+class MethodHelper : public MethodHelperT<Handle> {
+  using MethodHelperT<Handle>::MethodHelperT;
+ private:
+  DISALLOW_COPY_AND_ASSIGN(MethodHelper);
+};
+
+class MutableMethodHelper : public MethodHelperT<MutableHandle> {
+  using MethodHelperT<MutableHandle>::MethodHelperT;
+ public:
+  void ChangeMethod(mirror::ArtMethod* new_m) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
+    DCHECK(new_m != nullptr);
+    SetMethod(new_m);
+    shorty_ = nullptr;
+  }
+
  private:
   // Set the method_ field, for proxy methods looking up the interface method via the resolved
   // methods table.
@@ -137,11 +160,7 @@
     method_.Assign(method);
   }
 
-  Handle<mirror::ArtMethod> method_;
-  const char* shorty_;
-  uint32_t shorty_len_;
-
-  DISALLOW_COPY_AND_ASSIGN(MethodHelper);
+  DISALLOW_COPY_AND_ASSIGN(MutableMethodHelper);
 };
 
 }  // namespace art
diff --git a/runtime/mirror/array.cc b/runtime/mirror/array.cc
index f54af85..4535f6c 100644
--- a/runtime/mirror/array.cc
+++ b/runtime/mirror/array.cc
@@ -94,7 +94,7 @@
   ClassLinker* class_linker = Runtime::Current()->GetClassLinker();
   mirror::Class* element_class_ptr = element_class.Get();
   StackHandleScope<1> hs(self);
-  Handle<mirror::Class> array_class(
+  MutableHandle<mirror::Class> array_class(
       hs.NewHandle(class_linker->FindArrayClass(self, &element_class_ptr)));
   if (UNLIKELY(array_class.Get() == nullptr)) {
     CHECK(self->IsExceptionPending());
diff --git a/runtime/mirror/art_method-inl.h b/runtime/mirror/art_method-inl.h
index ae17070..8447616 100644
--- a/runtime/mirror/art_method-inl.h
+++ b/runtime/mirror/art_method-inl.h
@@ -285,14 +285,17 @@
 }
 
 inline StackMap ArtMethod::GetStackMap(uint32_t native_pc_offset) {
+  return GetOptimizedCodeInfo().GetStackMapForNativePcOffset(native_pc_offset);
+}
+
+inline CodeInfo ArtMethod::GetOptimizedCodeInfo() {
   DCHECK(IsOptimized());
   const void* code_pointer = GetQuickOatCodePointer();
   DCHECK(code_pointer != nullptr);
   uint32_t offset =
       reinterpret_cast<const OatQuickMethodHeader*>(code_pointer)[-1].vmap_table_offset_;
   const void* data = reinterpret_cast<const void*>(reinterpret_cast<const uint8_t*>(code_pointer) - offset);
-  CodeInfo code_info(data);
-  return code_info.GetStackMapForNativePcOffset(native_pc_offset);
+  return CodeInfo(data);
 }
 
 inline void ArtMethod::SetOatNativeGcMapOffset(uint32_t gc_map_offset) {
diff --git a/runtime/mirror/art_method.cc b/runtime/mirror/art_method.cc
index 131f5d6..159d04d 100644
--- a/runtime/mirror/art_method.cc
+++ b/runtime/mirror/art_method.cc
@@ -143,7 +143,7 @@
     } else {
       StackHandleScope<2> hs(Thread::Current());
       MethodHelper mh(hs.NewHandle(this));
-      MethodHelper interface_mh(hs.NewHandle<mirror::ArtMethod>(nullptr));
+      MutableMethodHelper interface_mh(hs.NewHandle<mirror::ArtMethod>(nullptr));
       IfTable* iftable = GetDeclaringClass()->GetIfTable();
       for (size_t i = 0; i < iftable->Count() && result == NULL; i++) {
         Class* interface = iftable->GetInterface(i);
diff --git a/runtime/mirror/art_method.h b/runtime/mirror/art_method.h
index d37aa57..de6ec05 100644
--- a/runtime/mirror/art_method.h
+++ b/runtime/mirror/art_method.h
@@ -155,7 +155,9 @@
     // Temporary solution for detecting if a method has been optimized: the compiler
     // does not create a GC map. Instead, the vmap table contains the stack map
     // (as in stack_map.h).
-    return (GetEntryPointFromQuickCompiledCode() != nullptr) && (GetNativeGcMap() == nullptr);
+    return (GetEntryPointFromQuickCompiledCode() != nullptr)
+        && (GetQuickOatCodePointer() != nullptr)
+        && (GetNativeGcMap() == nullptr);
   }
 
   bool IsPortableCompiled() SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
@@ -349,6 +351,7 @@
       SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
 
   StackMap GetStackMap(uint32_t native_pc_offset) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
+  CodeInfo GetOptimizedCodeInfo() SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
 
   const uint8_t* GetNativeGcMap() SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
     return GetFieldPtr<uint8_t*>(OFFSET_OF_OBJECT_MEMBER(ArtMethod, gc_map_));
diff --git a/runtime/mirror/class.cc b/runtime/mirror/class.cc
index e7d8163..0ee8fa8 100644
--- a/runtime/mirror/class.cc
+++ b/runtime/mirror/class.cc
@@ -760,7 +760,7 @@
   return GetInterfaceTypeList()->GetTypeItem(idx).type_idx_;
 }
 
-mirror::Class* Class::GetDirectInterface(Thread* self, ConstHandle<mirror::Class> klass,
+mirror::Class* Class::GetDirectInterface(Thread* self, Handle<mirror::Class> klass,
                                          uint32_t idx) {
   DCHECK(klass.Get() != nullptr);
   DCHECK(!klass->IsPrimitive());
diff --git a/runtime/mirror/class.h b/runtime/mirror/class.h
index aad678f..4a8d6dc 100644
--- a/runtime/mirror/class.h
+++ b/runtime/mirror/class.h
@@ -65,7 +65,7 @@
 namespace art {
 
 struct ClassOffsets;
-template<class T> class ConstHandle;
+template<class T> class Handle;
 template<class T> class Handle;
 class Signature;
 class StringPiece;
@@ -990,7 +990,7 @@
 
   uint16_t GetDirectInterfaceTypeIdx(uint32_t idx) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
 
-  static mirror::Class* GetDirectInterface(Thread* self, ConstHandle<mirror::Class> klass,
+  static mirror::Class* GetDirectInterface(Thread* self, Handle<mirror::Class> klass,
                                            uint32_t idx)
       SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
 
diff --git a/runtime/mirror/object_test.cc b/runtime/mirror/object_test.cc
index aa181ee..1290a3d 100644
--- a/runtime/mirror/object_test.cc
+++ b/runtime/mirror/object_test.cc
@@ -161,7 +161,7 @@
   ScopedObjectAccess soa(Thread::Current());
   Class* c = class_linker_->FindSystemClass(soa.Self(), "[I");
   StackHandleScope<1> hs(soa.Self());
-  Handle<Array> a(
+  MutableHandle<Array> a(
       hs.NewHandle(Array::Alloc<true>(soa.Self(), c, 1, c->GetComponentSize(),
                                       Runtime::Current()->GetHeap()->GetCurrentAllocator())));
   EXPECT_TRUE(c == a->GetClass());
@@ -184,7 +184,7 @@
   ScopedObjectAccess soa(Thread::Current());
   Class* c = class_linker_->FindSystemClass(soa.Self(), "[B");
   StackHandleScope<1> hs(soa.Self());
-  Handle<Array> a(
+  MutableHandle<Array> a(
       hs.NewHandle(Array::Alloc<true>(soa.Self(), c, 1, c->GetComponentSize(),
                                       Runtime::Current()->GetHeap()->GetCurrentAllocator(), true)));
   EXPECT_TRUE(c == a->GetClass());
@@ -287,7 +287,7 @@
 
   StackHandleScope<2> hs(soa.Self());
   Handle<Class> c(hs.NewHandle(class_linker_->FindSystemClass(soa.Self(), "I")));
-  Handle<IntArray> dims(hs.NewHandle(IntArray::Alloc(soa.Self(), 1)));
+  MutableHandle<IntArray> dims(hs.NewHandle(IntArray::Alloc(soa.Self(), 1)));
   dims->Set<false>(0, 1);
   Array* multi = Array::CreateMultiArray(soa.Self(), c, dims);
   EXPECT_TRUE(multi->GetClass() == class_linker_->FindSystemClass(soa.Self(), "[I"));
@@ -485,8 +485,8 @@
   ArtMethod* m4_2 = klass2->GetVirtualMethod(3);
   EXPECT_STREQ(m4_2->GetName(), "m4");
 
-  MethodHelper mh(hs.NewHandle(m1_1));
-  MethodHelper mh2(hs.NewHandle(m1_2));
+  MutableMethodHelper mh(hs.NewHandle(m1_1));
+  MutableMethodHelper mh2(hs.NewHandle(m1_2));
   EXPECT_TRUE(mh.HasSameNameAndSignature(&mh2));
   EXPECT_TRUE(mh2.HasSameNameAndSignature(&mh));
 
diff --git a/runtime/modifiers.h b/runtime/modifiers.h
index 2814ed8..23c18f8 100644
--- a/runtime/modifiers.h
+++ b/runtime/modifiers.h
@@ -19,48 +19,77 @@
 
 #include <stdint.h>
 
-static const uint32_t kAccPublic = 0x0001;  // class, field, method, ic
-static const uint32_t kAccPrivate = 0x0002;  // field, method, ic
-static const uint32_t kAccProtected = 0x0004;  // field, method, ic
-static const uint32_t kAccStatic = 0x0008;  // field, method, ic
-static const uint32_t kAccFinal = 0x0010;  // class, field, method, ic
-static const uint32_t kAccSynchronized = 0x0020;  // method (only allowed on natives)
-static const uint32_t kAccSuper = 0x0020;  // class (not used in dex)
-static const uint32_t kAccVolatile = 0x0040;  // field
-static const uint32_t kAccBridge = 0x0040;  // method (1.5)
-static const uint32_t kAccTransient = 0x0080;  // field
-static const uint32_t kAccVarargs = 0x0080;  // method (1.5)
-static const uint32_t kAccNative = 0x0100;  // method
-static const uint32_t kAccInterface = 0x0200;  // class, ic
-static const uint32_t kAccAbstract = 0x0400;  // class, method, ic
-static const uint32_t kAccStrict = 0x0800;  // method
-static const uint32_t kAccSynthetic = 0x1000;  // class, field, method, ic
-static const uint32_t kAccAnnotation = 0x2000;  // class, ic (1.5)
-static const uint32_t kAccEnum = 0x4000;  // class, field, ic (1.5)
+static constexpr uint32_t kAccPublic =       0x0001;  // class, field, method, ic
+static constexpr uint32_t kAccPrivate =      0x0002;  // field, method, ic
+static constexpr uint32_t kAccProtected =    0x0004;  // field, method, ic
+static constexpr uint32_t kAccStatic =       0x0008;  // field, method, ic
+static constexpr uint32_t kAccFinal =        0x0010;  // class, field, method, ic
+static constexpr uint32_t kAccSynchronized = 0x0020;  // method (only allowed on natives)
+static constexpr uint32_t kAccSuper =        0x0020;  // class (not used in dex)
+static constexpr uint32_t kAccVolatile =     0x0040;  // field
+static constexpr uint32_t kAccBridge =       0x0040;  // method (1.5)
+static constexpr uint32_t kAccTransient =    0x0080;  // field
+static constexpr uint32_t kAccVarargs =      0x0080;  // method (1.5)
+static constexpr uint32_t kAccNative =       0x0100;  // method
+static constexpr uint32_t kAccInterface =    0x0200;  // class, ic
+static constexpr uint32_t kAccAbstract =     0x0400;  // class, method, ic
+static constexpr uint32_t kAccStrict =       0x0800;  // method
+static constexpr uint32_t kAccSynthetic =    0x1000;  // class, field, method, ic
+static constexpr uint32_t kAccAnnotation =   0x2000;  // class, ic (1.5)
+static constexpr uint32_t kAccEnum =         0x4000;  // class, field, ic (1.5)
 
-static const uint32_t kAccMiranda = 0x8000;  // method
+static constexpr uint32_t kAccJavaFlagsMask = 0xffff;  // bits set from Java sources (low 16)
 
-static const uint32_t kAccJavaFlagsMask = 0xffff;  // bits set from Java sources (low 16)
-
-static const uint32_t kAccConstructor = 0x00010000;  // method (dex only) <init> and <clinit>
-static const uint32_t kAccDeclaredSynchronized = 0x00020000;  // method (dex only)
-static const uint32_t kAccClassIsProxy = 0x00040000;  // class (dex only)
-static const uint32_t kAccPreverified = 0x00080000;  // class (runtime), method (dex only)
-static const uint32_t kAccFastNative = 0x0080000;  // method (dex only)
-static const uint32_t kAccPortableCompiled = 0x0100000;  // method (dex only)
+static constexpr uint32_t kAccConstructor =          0x00010000;  // method (dex only) <(cl)init>
+static constexpr uint32_t kAccDeclaredSynchronized = 0x00020000;  // method (dex only)
+static constexpr uint32_t kAccClassIsProxy =         0x00040000;  // class  (dex only)
+static constexpr uint32_t kAccPreverified =          0x00080000;  // class (runtime),
+                                                                  // method (dex only)
+static constexpr uint32_t kAccFastNative =           0x00080000;  // method (dex only)
+static constexpr uint32_t kAccPortableCompiled =     0x00100000;  // method (dex only)
+static constexpr uint32_t kAccMiranda =              0x00200000;  // method (dex only)
 
 // Special runtime-only flags.
 // Note: if only kAccClassIsReference is set, we have a soft reference.
-static const uint32_t kAccClassIsFinalizable        = 0x80000000;  // class/ancestor overrides finalize()
-static const uint32_t kAccClassIsReference          = 0x08000000;  // class is a soft/weak/phantom ref
-static const uint32_t kAccClassIsWeakReference      = 0x04000000;  // class is a weak reference
-static const uint32_t kAccClassIsFinalizerReference = 0x02000000;  // class is a finalizer reference
-static const uint32_t kAccClassIsPhantomReference   = 0x01000000;  // class is a phantom reference
 
-static const uint32_t kAccReferenceFlagsMask = (kAccClassIsReference
-                                                | kAccClassIsWeakReference
-                                                | kAccClassIsFinalizerReference
-                                                | kAccClassIsPhantomReference);
+// class/ancestor overrides finalize()
+static constexpr uint32_t kAccClassIsFinalizable        = 0x80000000;
+// class is a soft/weak/phantom ref
+static constexpr uint32_t kAccClassIsReference          = 0x08000000;
+// class is a weak reference
+static constexpr uint32_t kAccClassIsWeakReference      = 0x04000000;
+// class is a finalizer reference
+static constexpr uint32_t kAccClassIsFinalizerReference = 0x02000000;
+// class is a phantom reference
+static constexpr uint32_t kAccClassIsPhantomReference   = 0x01000000;
+
+static constexpr uint32_t kAccReferenceFlagsMask = (kAccClassIsReference
+                                                  | kAccClassIsWeakReference
+                                                  | kAccClassIsFinalizerReference
+                                                  | kAccClassIsPhantomReference);
+
+// Valid (meaningful) bits for a field.
+static constexpr uint32_t kAccValidFieldFlags = kAccPublic | kAccPrivate | kAccProtected |
+    kAccStatic | kAccFinal | kAccVolatile | kAccTransient | kAccSynthetic | kAccEnum;
+
+// Valid (meaningful) bits for a method.
+static constexpr uint32_t kAccValidMethodFlags = kAccPublic | kAccPrivate | kAccProtected |
+    kAccStatic | kAccFinal | kAccSynchronized | kAccBridge | kAccVarargs | kAccNative |
+    kAccAbstract | kAccStrict | kAccSynthetic | kAccMiranda | kAccConstructor |
+    kAccDeclaredSynchronized;
+
+// Valid (meaningful) bits for a class (not interface).
+// Note 1. These are positive bits. Other bits may have to be zero.
+// Note 2. Inner classes can expose more access flags to Java programs. That is handled by libcore.
+static constexpr uint32_t kAccValidClassFlags = kAccPublic | kAccFinal | kAccSuper |
+    kAccAbstract | kAccSynthetic | kAccEnum;
+
+// Valid (meaningful) bits for an interface.
+// Note 1. Annotations are interfaces.
+// Note 2. These are positive bits. Other bits may have to be zero.
+// Note 3. Inner classes can expose more access flags to Java programs. That is handled by libcore.
+static constexpr uint32_t kAccValidInterfaceFlags = kAccPublic | kAccInterface |
+    kAccAbstract | kAccSynthetic | kAccAnnotation;
 
 #endif  // ART_RUNTIME_MODIFIERS_H_
 
diff --git a/runtime/monitor_test.cc b/runtime/monitor_test.cc
index af24368..704e041 100644
--- a/runtime/monitor_test.cc
+++ b/runtime/monitor_test.cc
@@ -58,7 +58,7 @@
 static const size_t kMaxHandles = 1000000;  // Use arbitrary large amount for now.
 static void FillHeap(Thread* self, ClassLinker* class_linker,
                      std::unique_ptr<StackHandleScope<kMaxHandles>>* hsp,
-                     std::vector<Handle<mirror::Object>>* handles)
+                     std::vector<MutableHandle<mirror::Object>>* handles)
     SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
   Runtime::Current()->GetHeap()->SetIdealFootprint(1 * GB);
 
@@ -73,7 +73,7 @@
   // Start allocating with 128K
   size_t length = 128 * KB / 4;
   while (length > 10) {
-    Handle<mirror::Object> h((*hsp)->NewHandle<mirror::Object>(
+    MutableHandle<mirror::Object> h((*hsp)->NewHandle<mirror::Object>(
         mirror::ObjectArray<mirror::Object>::Alloc(self, ca.Get(), length / 4)));
     if (self->IsExceptionPending() || h.Get() == nullptr) {
       self->ClearException();
@@ -92,7 +92,7 @@
 
   // Allocate simple objects till it fails.
   while (!self->IsExceptionPending()) {
-    Handle<mirror::Object> h = (*hsp)->NewHandle<mirror::Object>(c->AllocObject(self));
+    MutableHandle<mirror::Object> h = (*hsp)->NewHandle<mirror::Object>(c->AllocObject(self));
     if (!self->IsExceptionPending() && h.Get() != nullptr) {
       handles->push_back(h);
     }
@@ -307,7 +307,7 @@
 
   // Fill the heap.
   std::unique_ptr<StackHandleScope<kMaxHandles>> hsp;
-  std::vector<Handle<mirror::Object>> handles;
+  std::vector<MutableHandle<mirror::Object>> handles;
   {
     Thread* self = Thread::Current();
     ScopedObjectAccess soa(self);
diff --git a/runtime/native/java_lang_ref_FinalizerReference.cc b/runtime/native/java_lang_ref_FinalizerReference.cc
new file mode 100644
index 0000000..ad48ec0
--- /dev/null
+++ b/runtime/native/java_lang_ref_FinalizerReference.cc
@@ -0,0 +1,40 @@
+/*
+ * 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 "gc/heap.h"
+#include "gc/reference_processor.h"
+#include "jni_internal.h"
+#include "mirror/object-inl.h"
+#include "mirror/reference-inl.h"
+#include "scoped_fast_native_object_access.h"
+
+namespace art {
+
+static jboolean FinalizerReference_makeCircularListIfUnenqueued(JNIEnv* env, jobject javaThis) {
+  ScopedFastNativeObjectAccess soa(env);
+  mirror::FinalizerReference* const ref = soa.Decode<mirror::FinalizerReference*>(javaThis);
+  return Runtime::Current()->GetHeap()->GetReferenceProcessor()->MakeCircularListIfUnenqueued(ref);
+}
+
+static JNINativeMethod gMethods[] = {
+  NATIVE_METHOD(FinalizerReference, makeCircularListIfUnenqueued, "!()Z"),
+};
+
+void register_java_lang_ref_FinalizerReference(JNIEnv* env) {
+  REGISTER_NATIVE_METHODS("java/lang/ref/FinalizerReference");
+}
+
+}  // namespace art
diff --git a/runtime/oat_file-inl.h b/runtime/oat_file-inl.h
index 97ca6b2..9570bb5 100644
--- a/runtime/oat_file-inl.h
+++ b/runtime/oat_file-inl.h
@@ -21,6 +21,39 @@
 
 namespace art {
 
+inline const OatQuickMethodHeader* OatFile::OatMethod::GetOatQuickMethodHeader() const {
+  const void* code = mirror::ArtMethod::EntryPointToCodePointer(GetQuickCode());
+  if (code == nullptr) {
+    return nullptr;
+  }
+  // Return a pointer to the packed struct before the code.
+  return reinterpret_cast<const OatQuickMethodHeader*>(code) - 1;
+}
+
+inline uint32_t OatFile::OatMethod::GetOatQuickMethodHeaderOffset() const {
+  const OatQuickMethodHeader* method_header = GetOatQuickMethodHeader();
+  if (method_header == nullptr) {
+    return 0u;
+  }
+  return reinterpret_cast<const byte*>(method_header) - begin_;
+}
+
+inline uint32_t OatFile::OatMethod::GetQuickCodeSize() const {
+  const void* code = mirror::ArtMethod::EntryPointToCodePointer(GetQuickCode());
+  if (code == nullptr) {
+    return 0u;
+  }
+  return reinterpret_cast<const OatQuickMethodHeader*>(code)[-1].code_size_;
+}
+
+inline uint32_t OatFile::OatMethod::GetQuickCodeSizeOffset() const {
+  const OatQuickMethodHeader* method_header = GetOatQuickMethodHeader();
+  if (method_header == nullptr) {
+    return 0u;
+  }
+  return reinterpret_cast<const byte*>(&method_header->code_size_) - begin_;
+}
+
 inline size_t OatFile::OatMethod::GetFrameSizeInBytes() const {
   const void* code = mirror::ArtMethod::EntryPointToCodePointer(GetQuickCode());
   if (code == nullptr) {
@@ -50,11 +83,27 @@
   return static_cast<uint32_t>(mapping_table != nullptr ? mapping_table - begin_ : 0u);
 }
 
+inline uint32_t OatFile::OatMethod::GetMappingTableOffsetOffset() const {
+  const OatQuickMethodHeader* method_header = GetOatQuickMethodHeader();
+  if (method_header == nullptr) {
+    return 0u;
+  }
+  return reinterpret_cast<const byte*>(&method_header->mapping_table_offset_) - begin_;
+}
+
 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 uint32_t OatFile::OatMethod::GetVmapTableOffsetOffset() const {
+  const OatQuickMethodHeader* method_header = GetOatQuickMethodHeader();
+  if (method_header == nullptr) {
+    return 0u;
+  }
+  return reinterpret_cast<const byte*>(&method_header->vmap_table_offset_) - begin_;
+}
+
 inline const uint8_t* OatFile::OatMethod::GetMappingTable() const {
   const void* code = mirror::ArtMethod::EntryPointToCodePointer(GetQuickCode());
   if (code == nullptr) {
diff --git a/runtime/oat_file.cc b/runtime/oat_file.cc
index cf1c6e1..a896f3e 100644
--- a/runtime/oat_file.cc
+++ b/runtime/oat_file.cc
@@ -19,6 +19,7 @@
 #include <dlfcn.h>
 #include <sstream>
 #include <string.h>
+#include <unistd.h>
 
 #include "base/bit_vector.h"
 #include "base/stl_util.h"
@@ -91,6 +92,10 @@
       return nullptr;
     }
     ret.reset(OpenElfFile(file.get(), location, requested_base, false, executable, error_msg));
+
+    // It would be nice to unlink here. But we might have opened the file created by the
+    // ScopedLock, which we better not delete to avoid races. TODO: Investigate how to fix the API
+    // to allow removal when we know the ELF must be borked.
   }
   return ret.release();
 }
@@ -449,8 +454,12 @@
                        dex_file_location_checksum_, error_msg);
 }
 
+uint32_t OatFile::OatDexFile::GetOatClassOffset(uint16_t class_def_index) const {
+  return oat_class_offsets_pointer_[class_def_index];
+}
+
 OatFile::OatClass OatFile::OatDexFile::GetOatClass(uint16_t class_def_index) const {
-  uint32_t oat_class_offset = oat_class_offsets_pointer_[class_def_index];
+  uint32_t oat_class_offset = GetOatClassOffset(class_def_index);
 
   const byte* oat_class_pointer = oat_file_->Begin() + oat_class_offset;
   CHECK_LT(oat_class_pointer, oat_file_->End()) << oat_file_->GetLocation();
@@ -526,49 +535,54 @@
     }
 }
 
-const OatFile::OatMethod OatFile::OatClass::GetOatMethod(uint32_t method_index) const {
+uint32_t OatFile::OatClass::GetOatMethodOffsetsOffset(uint32_t method_index) const {
+  const OatMethodOffsets* oat_method_offsets = GetOatMethodOffsets(method_index);
+  if (oat_method_offsets == nullptr) {
+    return 0u;
+  }
+  return reinterpret_cast<const uint8_t*>(oat_method_offsets) - oat_file_->Begin();
+}
+
+const OatMethodOffsets* OatFile::OatClass::GetOatMethodOffsets(uint32_t method_index) const {
   // NOTE: We don't keep the number of methods and cannot do a bounds check for method_index.
-  if (methods_pointer_ == NULL) {
+  if (methods_pointer_ == nullptr) {
     CHECK_EQ(kOatClassNoneCompiled, type_);
-    return OatMethod(NULL, 0, 0);
+    return nullptr;
   }
   size_t methods_pointer_index;
-  if (bitmap_ == NULL) {
+  if (bitmap_ == nullptr) {
     CHECK_EQ(kOatClassAllCompiled, type_);
     methods_pointer_index = method_index;
   } else {
     CHECK_EQ(kOatClassSomeCompiled, type_);
     if (!BitVector::IsBitSet(bitmap_, method_index)) {
-      return OatMethod(NULL, 0, 0);
+      return nullptr;
     }
     size_t num_set_bits = BitVector::NumSetBits(bitmap_, method_index);
     methods_pointer_index = num_set_bits;
   }
   const OatMethodOffsets& oat_method_offsets = methods_pointer_[methods_pointer_index];
-  if (oat_file_->IsExecutable()
-      || (Runtime::Current() == nullptr)
-      || Runtime::Current()->IsCompiler()) {
+  return &oat_method_offsets;
+}
+
+const OatFile::OatMethod OatFile::OatClass::GetOatMethod(uint32_t method_index) const {
+  const OatMethodOffsets* oat_method_offsets = GetOatMethodOffsets(method_index);
+  if (oat_method_offsets == nullptr) {
+    return OatMethod(nullptr, 0, 0);
+  }
+  if (oat_file_->IsExecutable() ||
+      Runtime::Current() == nullptr ||        // This case applies for oatdump.
+      Runtime::Current()->IsCompiler()) {
     return OatMethod(
         oat_file_->Begin(),
-        oat_method_offsets.code_offset_,
-        oat_method_offsets.gc_map_offset_);
+        oat_method_offsets->code_offset_,
+        oat_method_offsets->gc_map_offset_);
   } else {
     // We aren't allowed to use the compiled code. We just force it down the interpreted version.
     return OatMethod(oat_file_->Begin(), 0, 0);
   }
 }
 
-
-uint32_t OatFile::OatMethod::GetQuickCodeSize() const {
-  uintptr_t code = reinterpret_cast<uintptr_t>(GetQuickCode());
-  if (code == 0) {
-    return 0;
-  }
-  // TODO: make this Thumb2 specific
-  code &= ~0x1;
-  return reinterpret_cast<uint32_t*>(code)[-1];
-}
-
 void OatFile::OatMethod::LinkMethod(mirror::ArtMethod* method) const {
   CHECK(method != NULL);
   method->SetEntryPointFromPortableCompiledCode(GetPortableCode());
diff --git a/runtime/oat_file.h b/runtime/oat_file.h
index 2fd4f4c..b9d5702 100644
--- a/runtime/oat_file.h
+++ b/runtime/oat_file.h
@@ -114,13 +114,22 @@
       }
     }
 
+    // Returns 0.
     uint32_t GetPortableCodeSize() const {
       // TODO: With Quick, we store the size before the code. With Portable, the code is in a .o
       // file we don't manage ourselves. ELF symbols do have a concept of size, so we could capture
       // that and store it somewhere, such as the OatMethod.
       return 0;
     }
+
+    // Returns size of quick code.
     uint32_t GetQuickCodeSize() const;
+    uint32_t GetQuickCodeSizeOffset() const;
+
+    // Returns OatQuickMethodHeader for debugging. Most callers should
+    // use more specific methods such as GetQuickCodeSize.
+    const OatQuickMethodHeader* GetOatQuickMethodHeader() const;
+    uint32_t GetOatQuickMethodHeaderOffset() const;
 
     const uint8_t* GetNativeGcMap() const {
       return GetOatPointer<const uint8_t*>(native_gc_map_offset_);
@@ -129,10 +138,14 @@
     size_t GetFrameSizeInBytes() const;
     uint32_t GetCoreSpillMask() const;
     uint32_t GetFpSpillMask() const;
-    uint32_t GetMappingTableOffset() const;
-    uint32_t GetVmapTableOffset() const;
+
     const uint8_t* GetMappingTable() const;
+    uint32_t GetMappingTableOffset() const;
+    uint32_t GetMappingTableOffsetOffset() const;
+
     const uint8_t* GetVmapTable() const;
+    uint32_t GetVmapTableOffset() const;
+    uint32_t GetVmapTableOffsetOffset() const;
 
     // Create an OatMethod with offsets relative to the given base address
     OatMethod(const byte* base, const uint32_t code_offset, const uint32_t gc_map_offset)
@@ -176,11 +189,21 @@
     }
 
     // Get the OatMethod entry based on its index into the class
-    // defintion. direct methods come first, followed by virtual
-    // methods. note that runtime created methods such as miranda
+    // defintion. Direct methods come first, followed by virtual
+    // methods. Note that runtime created methods such as miranda
     // methods are not included.
     const OatMethod GetOatMethod(uint32_t method_index) const;
 
+    // Return a pointer to the OatMethodOffsets for the requested
+    // method_index, or nullptr if none is present. Note that most
+    // callers should use GetOatMethod.
+    const OatMethodOffsets* GetOatMethodOffsets(uint32_t method_index) const;
+
+    // Return the offset from the start of the OatFile to the
+    // OatMethodOffsets for the requested method_index, or 0 if none
+    // is present. Note that most callers should use GetOatMethod.
+    uint32_t GetOatMethodOffsetsOffset(uint32_t method_index) const;
+
     // A representation of an invalid OatClass, used when an OatClass can't be found.
     // See ClassLinker::FindOatClass.
     static OatClass Invalid() {
@@ -239,6 +262,9 @@
     // Returns the OatClass for the class specified by the given DexFile class_def_index.
     OatClass GetOatClass(uint16_t class_def_index) const;
 
+    // Returns the offset to the OatClass information. Most callers should use GetOatClass.
+    uint32_t GetOatClassOffset(uint16_t class_def_index) const;
+
     ~OatDexFile();
 
    private:
diff --git a/runtime/object_lock.cc b/runtime/object_lock.cc
index a2668ec..f7accc0 100644
--- a/runtime/object_lock.cc
+++ b/runtime/object_lock.cc
@@ -22,7 +22,7 @@
 namespace art {
 
 template <typename T>
-ObjectLock<T>::ObjectLock(Thread* self, ConstHandle<T> object) : self_(self), obj_(object) {
+ObjectLock<T>::ObjectLock(Thread* self, Handle<T> object) : self_(self), obj_(object) {
   CHECK(object.Get() != nullptr);
   obj_->MonitorEnter(self_);
 }
diff --git a/runtime/object_lock.h b/runtime/object_lock.h
index 38690bc..acddc03 100644
--- a/runtime/object_lock.h
+++ b/runtime/object_lock.h
@@ -28,7 +28,7 @@
 template <typename T>
 class ObjectLock {
  public:
-  ObjectLock(Thread* self, ConstHandle<T> object) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
+  ObjectLock(Thread* self, Handle<T> object) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
 
   ~ObjectLock() SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
 
@@ -40,7 +40,7 @@
 
  private:
   Thread* const self_;
-  ConstHandle<T> const obj_;
+  Handle<T> const obj_;
 
   DISALLOW_COPY_AND_ASSIGN(ObjectLock);
 };
diff --git a/runtime/parsed_options.cc b/runtime/parsed_options.cc
index 37e08a5..6b4f764 100644
--- a/runtime/parsed_options.cc
+++ b/runtime/parsed_options.cc
@@ -63,6 +63,8 @@
     heap_min_free_(gc::Heap::kDefaultMinFree),
     heap_max_free_(gc::Heap::kDefaultMaxFree),
     heap_non_moving_space_capacity_(gc::Heap::kDefaultNonMovingSpaceCapacity),
+    large_object_space_type_(gc::Heap::kDefaultLargeObjectSpaceType),
+    large_object_threshold_(gc::Heap::kDefaultLargeObjectThreshold),
     heap_target_utilization_(gc::Heap::kDefaultTargetUtilization),
     foreground_heap_growth_multiplier_(gc::Heap::kDefaultHeapGrowthMultiplier),
     parallel_gc_threads_(1),
@@ -452,6 +454,32 @@
       if (!ParseXGcOption(option)) {
         return false;
       }
+    } else if (StartsWith(option, "-XX:LargeObjectSpace=")) {
+      std::string substring;
+      if (!ParseStringAfterChar(option, '=', &substring)) {
+        return false;
+      }
+      if (substring == "disabled") {
+        large_object_space_type_ = gc::space::kLargeObjectSpaceTypeDisabled;
+      } else if (substring == "freelist") {
+        large_object_space_type_ = gc::space::kLargeObjectSpaceTypeFreeList;
+      } else if (substring == "map") {
+        large_object_space_type_ = gc::space::kLargeObjectSpaceTypeMap;
+      } else {
+        Usage("Unknown -XX:LargeObjectSpace= option %s\n", substring.c_str());
+        return false;
+      }
+    } else if (StartsWith(option, "-XX:LargeObjectThreshold=")) {
+      std::string substring;
+      if (!ParseStringAfterChar(option, '=', &substring)) {
+        return false;
+      }
+      size_t size = ParseMemoryOption(substring.c_str(), 1);
+      if (size == 0) {
+        Usage("Failed to parse memory option %s\n", option.c_str());
+        return false;
+      }
+      large_object_threshold_ = size;
     } else if (StartsWith(option, "-XX:BackgroundGC=")) {
       std::string substring;
       if (!ParseStringAfterChar(option, '=', &substring)) {
@@ -757,7 +785,6 @@
   UsageMessage(stream, "  -Xstacktracefile:<filename>\n");
   UsageMessage(stream, "  -Xgc:[no]preverify\n");
   UsageMessage(stream, "  -Xgc:[no]postverify\n");
-  UsageMessage(stream, "  -XX:+DisableExplicitGC\n");
   UsageMessage(stream, "  -XX:HeapGrowthLimit=N\n");
   UsageMessage(stream, "  -XX:HeapMinFree=N\n");
   UsageMessage(stream, "  -XX:HeapMaxFree=N\n");
@@ -774,6 +801,7 @@
   UsageMessage(stream, "  -Xgc:[no]postverify_rosalloc\n");
   UsageMessage(stream, "  -Xgc:[no]presweepingverify\n");
   UsageMessage(stream, "  -Ximage:filename\n");
+  UsageMessage(stream, "  -XX:+DisableExplicitGC\n");
   UsageMessage(stream, "  -XX:ParallelGCThreads=integervalue\n");
   UsageMessage(stream, "  -XX:ConcGCThreads=integervalue\n");
   UsageMessage(stream, "  -XX:MaxSpinsBeforeThinLockInflation=integervalue\n");
@@ -783,6 +811,8 @@
   UsageMessage(stream, "  -XX:IgnoreMaxFootprint\n");
   UsageMessage(stream, "  -XX:UseTLAB\n");
   UsageMessage(stream, "  -XX:BackgroundGC=none\n");
+  UsageMessage(stream, "  -XX:LargeObjectSpace={disabled,map,freelist}\n");
+  UsageMessage(stream, "  -XX:LargeObjectThreshold=N\n");
   UsageMessage(stream, "  -Xmethod-trace\n");
   UsageMessage(stream, "  -Xmethod-trace-file:filename");
   UsageMessage(stream, "  -Xmethod-trace-file-size:integervalue\n");
diff --git a/runtime/parsed_options.h b/runtime/parsed_options.h
index 3839e19..26a2f31 100644
--- a/runtime/parsed_options.h
+++ b/runtime/parsed_options.h
@@ -24,6 +24,7 @@
 
 #include "globals.h"
 #include "gc/collector_type.h"
+#include "gc/space/large_object_space.h"
 #include "instruction_set.h"
 #include "profiler_options.h"
 
@@ -72,6 +73,8 @@
   size_t heap_min_free_;
   size_t heap_max_free_;
   size_t heap_non_moving_space_capacity_;
+  gc::space::LargeObjectSpaceType large_object_space_type_;
+  size_t large_object_threshold_;
   double heap_target_utilization_;
   double foreground_heap_growth_multiplier_;
   unsigned int parallel_gc_threads_;
diff --git a/runtime/proxy_test.cc b/runtime/proxy_test.cc
index d977ce9..1eded62 100644
--- a/runtime/proxy_test.cc
+++ b/runtime/proxy_test.cc
@@ -183,7 +183,8 @@
   ASSERT_TRUE(throwsFieldClass.Get() != nullptr);
 
   // Test "Class[] interfaces" field.
-  FieldHelper fh(hs.NewHandle(static_fields->Get(0)));
+  MutableHandle<mirror::ArtField> fhandle = hs.NewHandle(static_fields->Get(0));
+  FieldHelper fh(fhandle);
   EXPECT_EQ("interfaces", std::string(fh.GetField()->GetName()));
   EXPECT_EQ("[Ljava/lang/Class;", std::string(fh.GetField()->GetTypeDescriptor()));
   EXPECT_EQ(interfacesFieldClass.Get(), fh.GetType());
@@ -191,12 +192,13 @@
   EXPECT_FALSE(fh.GetField()->IsPrimitiveType());
 
   // Test "Class[][] throws" field.
-  fh.ChangeField(static_fields->Get(1));
-  EXPECT_EQ("throws", std::string(fh.GetField()->GetName()));
-  EXPECT_EQ("[[Ljava/lang/Class;", std::string(fh.GetField()->GetTypeDescriptor()));
-  EXPECT_EQ(throwsFieldClass.Get(), fh.GetType());
-  EXPECT_EQ("L$Proxy1234;", std::string(fh.GetDeclaringClassDescriptor()));
-  EXPECT_FALSE(fh.GetField()->IsPrimitiveType());
+  fhandle.Assign(static_fields->Get(1));
+  FieldHelper fh2(fhandle);
+  EXPECT_EQ("throws", std::string(fh2.GetField()->GetName()));
+  EXPECT_EQ("[[Ljava/lang/Class;", std::string(fh2.GetField()->GetTypeDescriptor()));
+  EXPECT_EQ(throwsFieldClass.Get(), fh2.GetType());
+  EXPECT_EQ("L$Proxy1234;", std::string(fh2.GetDeclaringClassDescriptor()));
+  EXPECT_FALSE(fh2.GetField()->IsPrimitiveType());
 }
 
 }  // namespace art
diff --git a/runtime/runtime.cc b/runtime/runtime.cc
index b4a09e5..9b24bec 100644
--- a/runtime/runtime.cc
+++ b/runtime/runtime.cc
@@ -697,6 +697,8 @@
                        options->image_isa_,
                        options->collector_type_,
                        options->background_collector_type_,
+                       options->large_object_space_type_,
+                       options->large_object_threshold_,
                        options->parallel_gc_threads_,
                        options->conc_gc_threads_,
                        options->low_memory_mode_,
@@ -957,6 +959,7 @@
   REGISTER(register_java_lang_System);
   REGISTER(register_java_lang_Thread);
   REGISTER(register_java_lang_VMClassLoader);
+  REGISTER(register_java_lang_ref_FinalizerReference);
   REGISTER(register_java_lang_ref_Reference);
   REGISTER(register_java_lang_reflect_Array);
   REGISTER(register_java_lang_reflect_Constructor);
diff --git a/runtime/stack.h b/runtime/stack.h
index 8e5da35..44e36c4 100644
--- a/runtime/stack.h
+++ b/runtime/stack.h
@@ -604,8 +604,8 @@
    *     | Compiler temp region          |  ... (reg >= max_num_special_temps)
    *     |      .                        |
    *     |      .                        |
-   *     | V[max_num_special_temps + 1] |
-   *     | V[max_num_special_temps + 0] |
+   *     | V[max_num_special_temps + 1]  |
+   *     | V[max_num_special_temps + 0]  |
    *     +-------------------------------+
    *     | OUT[outs-1]                   |
    *     | OUT[outs-2]                   |
diff --git a/runtime/thread.cc b/runtime/thread.cc
index d4ac02b..c54bebe 100644
--- a/runtime/thread.cc
+++ b/runtime/thread.cc
@@ -446,7 +446,7 @@
 
   ScopedObjectAccess soa(self);
   StackHandleScope<1> hs(self);
-  Handle<mirror::String> peer_thread_name(hs.NewHandle(GetThreadName(soa)));
+  MutableHandle<mirror::String> peer_thread_name(hs.NewHandle(GetThreadName(soa)));
   if (peer_thread_name.Get() == nullptr) {
     // The Thread constructor should have set the Thread.name to a
     // non-null value. However, because we can run without code
diff --git a/runtime/thread_list.cc b/runtime/thread_list.cc
index 3cc2a28..2dbfb3e 100644
--- a/runtime/thread_list.cc
+++ b/runtime/thread_list.cc
@@ -156,7 +156,11 @@
   void WaitForThreadsToRunThroughCheckpoint(size_t threads_running_checkpoint) {
     Thread* self = Thread::Current();
     ScopedThreadStateChange tsc(self, kWaitingForCheckPointsToRun);
-    barrier_.Increment(self, threads_running_checkpoint);
+    const uint32_t kWaitTimeoutMs = 10000;
+    bool timed_out = barrier_.Increment(self, threads_running_checkpoint, kWaitTimeoutMs);
+    if (timed_out) {
+      LOG(kIsDebugBuild ? FATAL : ERROR) << "Unexpected time out during dump checkpoint.";
+    }
   }
 
  private:
diff --git a/runtime/transaction_test.cc b/runtime/transaction_test.cc
index 8c37489..432a2fe 100644
--- a/runtime/transaction_test.cc
+++ b/runtime/transaction_test.cc
@@ -460,7 +460,7 @@
 
   // Load and verify java.lang.ExceptionInInitializerError and java.lang.InternalError which will
   // be thrown by class initialization due to native call.
-  Handle<mirror::Class> h_klass(
+  MutableHandle<mirror::Class> h_klass(
       hs.NewHandle(class_linker_->FindSystemClass(soa.Self(),
                                                   "Ljava/lang/ExceptionInInitializerError;")));
   ASSERT_TRUE(h_klass.Get() != nullptr);
diff --git a/runtime/verifier/method_verifier.cc b/runtime/verifier/method_verifier.cc
index b799588..f28d488 100644
--- a/runtime/verifier/method_verifier.cc
+++ b/runtime/verifier/method_verifier.cc
@@ -127,8 +127,8 @@
 
 MethodVerifier::FailureKind MethodVerifier::VerifyClass(Thread* self,
                                                         const DexFile* dex_file,
-                                                        ConstHandle<mirror::DexCache> dex_cache,
-                                                        ConstHandle<mirror::ClassLoader> class_loader,
+                                                        Handle<mirror::DexCache> dex_cache,
+                                                        Handle<mirror::ClassLoader> class_loader,
                                                         const DexFile::ClassDef* class_def,
                                                         bool allow_soft_failures,
                                                         std::string* error) {
@@ -175,7 +175,7 @@
                                                       class_def,
                                                       it.GetMethodCodeItem(),
                                                       h_method,
-                                                      it.GetMemberAccessFlags(),
+                                                      it.GetMethodAccessFlags(),
                                                       allow_soft_failures,
                                                       false);
     if (result != kNoFailure) {
@@ -223,7 +223,7 @@
                                                       class_def,
                                                       it.GetMethodCodeItem(),
                                                       h_method,
-                                                      it.GetMemberAccessFlags(),
+                                                      it.GetMethodAccessFlags(),
                                                       allow_soft_failures,
                                                       false);
     if (result != kNoFailure) {
@@ -250,11 +250,11 @@
 
 MethodVerifier::FailureKind MethodVerifier::VerifyMethod(Thread* self, uint32_t method_idx,
                                                          const DexFile* dex_file,
-                                                         ConstHandle<mirror::DexCache> dex_cache,
-                                                         ConstHandle<mirror::ClassLoader> class_loader,
+                                                         Handle<mirror::DexCache> dex_cache,
+                                                         Handle<mirror::ClassLoader> class_loader,
                                                          const DexFile::ClassDef* class_def,
                                                          const DexFile::CodeItem* code_item,
-                                                         ConstHandle<mirror::ArtMethod> method,
+                                                         Handle<mirror::ArtMethod> method,
                                                          uint32_t method_access_flags,
                                                          bool allow_soft_failures,
                                                          bool need_precise_constants) {
@@ -297,30 +297,39 @@
   return result;
 }
 
-void MethodVerifier::VerifyMethodAndDump(Thread* self, std::ostream& os, uint32_t dex_method_idx,
+MethodVerifier* MethodVerifier::VerifyMethodAndDump(Thread* self, std::ostream& os, uint32_t dex_method_idx,
                                          const DexFile* dex_file,
-                                         ConstHandle<mirror::DexCache> dex_cache,
-                                         ConstHandle<mirror::ClassLoader> class_loader,
+                                         Handle<mirror::DexCache> dex_cache,
+                                         Handle<mirror::ClassLoader> class_loader,
                                          const DexFile::ClassDef* class_def,
                                          const DexFile::CodeItem* code_item,
-                                         ConstHandle<mirror::ArtMethod> method,
+                                         Handle<mirror::ArtMethod> method,
                                          uint32_t method_access_flags) {
-  MethodVerifier verifier(self, dex_file, dex_cache, class_loader, class_def, code_item,
-                          dex_method_idx, method, method_access_flags, true, true, true);
-  verifier.Verify();
-  verifier.DumpFailures(os);
-  os << verifier.info_messages_.str();
-  verifier.Dump(os);
+  MethodVerifier* verifier = new MethodVerifier(self, dex_file, dex_cache, class_loader,
+                                                class_def, code_item, dex_method_idx, method,
+                                                method_access_flags, true, true, true, true);
+  verifier->Verify();
+  verifier->DumpFailures(os);
+  os << verifier->info_messages_.str();
+  // Only dump and return if no hard failures. Otherwise the verifier may be not fully initialized
+  // and querying any info is dangerous/can abort.
+  if (verifier->have_pending_hard_failure_) {
+    delete verifier;
+    return nullptr;
+  } else {
+    verifier->Dump(os);
+    return verifier;
+  }
 }
 
 MethodVerifier::MethodVerifier(Thread* self,
-                               const DexFile* dex_file, ConstHandle<mirror::DexCache> dex_cache,
-                               ConstHandle<mirror::ClassLoader> class_loader,
+                               const DexFile* dex_file, Handle<mirror::DexCache> dex_cache,
+                               Handle<mirror::ClassLoader> class_loader,
                                const DexFile::ClassDef* class_def,
                                const DexFile::CodeItem* code_item, uint32_t dex_method_idx,
-                               ConstHandle<mirror::ArtMethod> method, uint32_t method_access_flags,
+                               Handle<mirror::ArtMethod> method, uint32_t method_access_flags,
                                bool can_load_classes, bool allow_soft_failures,
-                               bool need_precise_constants)
+                               bool need_precise_constants, bool verify_to_dump)
     : self_(self),
       reg_types_(can_load_classes),
       work_insn_idx_(-1),
@@ -344,7 +353,8 @@
       allow_soft_failures_(allow_soft_failures),
       need_precise_constants_(need_precise_constants),
       has_check_casts_(false),
-      has_virtual_or_interface_invokes_(false) {
+      has_virtual_or_interface_invokes_(false),
+      verify_to_dump_(verify_to_dump) {
   Runtime::Current()->AddMethodVerifier(this);
   DCHECK(class_def != nullptr);
 }
@@ -774,7 +784,7 @@
       result = false;
       break;
   }
-  if (inst->GetVerifyIsRuntimeOnly() && Runtime::Current()->IsCompiler()) {
+  if (inst->GetVerifyIsRuntimeOnly() && Runtime::Current()->IsCompiler() && !verify_to_dump_) {
     Fail(VERIFY_ERROR_BAD_CLASS_HARD) << "opcode only expected at runtime " << inst->Name();
     result = false;
   }
@@ -3341,8 +3351,8 @@
 }
 
 mirror::ArtMethod* MethodVerifier::VerifyInvokeVirtualQuickArgs(const Instruction* inst,
-                                                                     bool is_range) {
-  DCHECK(Runtime::Current()->IsStarted());
+                                                                bool is_range) {
+  DCHECK(Runtime::Current()->IsStarted() || verify_to_dump_);
   mirror::ArtMethod* res_method = GetQuickInvokedMethod(inst, work_line_.get(),
                                                              is_range);
   if (res_method == nullptr) {
@@ -3857,7 +3867,7 @@
 
 void MethodVerifier::VerifyIGetQuick(const Instruction* inst, const RegType& insn_type,
                                      bool is_primitive) {
-  DCHECK(Runtime::Current()->IsStarted());
+  DCHECK(Runtime::Current()->IsStarted() || verify_to_dump_);
   mirror::ArtField* field = GetQuickFieldAccess(inst, work_line_.get());
   if (field == nullptr) {
     Fail(VERIFY_ERROR_BAD_CLASS_HARD) << "Cannot infer field from " << inst->Name();
@@ -3916,7 +3926,7 @@
 
 void MethodVerifier::VerifyIPutQuick(const Instruction* inst, const RegType& insn_type,
                                      bool is_primitive) {
-  DCHECK(Runtime::Current()->IsStarted());
+  DCHECK(Runtime::Current()->IsStarted() || verify_to_dump_);
   mirror::ArtField* field = GetQuickFieldAccess(inst, work_line_.get());
   if (field == nullptr) {
     Fail(VERIFY_ERROR_BAD_CLASS_HARD) << "Cannot infer field from " << inst->Name();
diff --git a/runtime/verifier/method_verifier.h b/runtime/verifier/method_verifier.h
index eef2b9e..87acb20 100644
--- a/runtime/verifier/method_verifier.h
+++ b/runtime/verifier/method_verifier.h
@@ -144,18 +144,20 @@
                                  std::string* error)
       SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
   static FailureKind VerifyClass(Thread* self, const DexFile* dex_file,
-                                 ConstHandle<mirror::DexCache> dex_cache,
-                                 ConstHandle<mirror::ClassLoader> class_loader,
+                                 Handle<mirror::DexCache> dex_cache,
+                                 Handle<mirror::ClassLoader> class_loader,
                                  const DexFile::ClassDef* class_def,
                                  bool allow_soft_failures, std::string* error)
       SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
 
-  static void VerifyMethodAndDump(Thread* self, std::ostream& os, uint32_t method_idx,
-                                  const DexFile* dex_file, ConstHandle<mirror::DexCache> dex_cache,
-                                  ConstHandle<mirror::ClassLoader> class_loader,
-                                  const DexFile::ClassDef* class_def,
-                                  const DexFile::CodeItem* code_item,
-                                  ConstHandle<mirror::ArtMethod> method, uint32_t method_access_flags)
+  static MethodVerifier* VerifyMethodAndDump(Thread* self, std::ostream& os, uint32_t method_idx,
+                                             const DexFile* dex_file,
+                                             Handle<mirror::DexCache> dex_cache,
+                                             Handle<mirror::ClassLoader> class_loader,
+                                             const DexFile::ClassDef* class_def,
+                                             const DexFile::CodeItem* code_item,
+                                             Handle<mirror::ArtMethod> method,
+                                             uint32_t method_access_flags)
       SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
 
   uint8_t EncodePcToReferenceMapData() const;
@@ -204,13 +206,15 @@
     return can_load_classes_;
   }
 
-  MethodVerifier(Thread* self, const DexFile* dex_file, ConstHandle<mirror::DexCache> dex_cache,
-                 ConstHandle<mirror::ClassLoader> class_loader, const DexFile::ClassDef* class_def,
+  MethodVerifier(Thread* self, const DexFile* dex_file, Handle<mirror::DexCache> dex_cache,
+                 Handle<mirror::ClassLoader> class_loader, const DexFile::ClassDef* class_def,
                  const DexFile::CodeItem* code_item, uint32_t method_idx,
-                 ConstHandle<mirror::ArtMethod> method,
+                 Handle<mirror::ArtMethod> method,
                  uint32_t access_flags, bool can_load_classes, bool allow_soft_failures,
-                 bool need_precise_constants)
-          SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
+                 bool need_precise_constants) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_)
+      : MethodVerifier(self, dex_file, dex_cache, class_loader, class_def, code_item, method_idx,
+                       method, access_flags, can_load_classes, allow_soft_failures,
+                       need_precise_constants, false) {}
 
   ~MethodVerifier();
 
@@ -240,6 +244,15 @@
       SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
 
  private:
+  // Private constructor for dumping.
+  MethodVerifier(Thread* self, const DexFile* dex_file, Handle<mirror::DexCache> dex_cache,
+                 Handle<mirror::ClassLoader> class_loader, const DexFile::ClassDef* class_def,
+                 const DexFile::CodeItem* code_item, uint32_t method_idx,
+                 Handle<mirror::ArtMethod> method, uint32_t access_flags,
+                 bool can_load_classes, bool allow_soft_failures, bool need_precise_constants,
+                 bool verify_to_dump)
+      SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
+
   // Adds the given string to the beginning of the last failure message.
   void PrependToLastFailMessage(std::string);
 
@@ -258,13 +271,13 @@
    *      for code flow problems.
    */
   static FailureKind VerifyMethod(Thread* self, uint32_t method_idx, const DexFile* dex_file,
-                                  ConstHandle<mirror::DexCache> dex_cache,
-                                  ConstHandle<mirror::ClassLoader> class_loader,
+                                  Handle<mirror::DexCache> dex_cache,
+                                  Handle<mirror::ClassLoader> class_loader,
                                   const DexFile::ClassDef* class_def_idx,
                                   const DexFile::CodeItem* code_item,
-                                  ConstHandle<mirror::ArtMethod> method, uint32_t method_access_flags,
+                                  Handle<mirror::ArtMethod> method, uint32_t method_access_flags,
                                   bool allow_soft_failures, bool need_precise_constants)
-          SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
+      SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
 
   void FindLocksAtDexPc() SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
 
@@ -508,7 +521,7 @@
                    bool is_primitive, bool is_static)
       SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
 
-  // Returns the access field of a quick field access (iget/iput-quick) or NULL
+  // Returns the access field of a quick field access (iget/iput-quick) or nullptr
   // if it cannot be found.
   mirror::ArtField* GetQuickFieldAccess(const Instruction* inst, RegisterLine* reg_line)
       SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
@@ -563,7 +576,7 @@
    * Widening conversions on integers and references are allowed, but
    * narrowing conversions are not.
    *
-   * Returns the resolved method on success, NULL on failure (with *failure
+   * Returns the resolved method on success, nullptr on failure (with *failure
    * set appropriately).
    */
   mirror::ArtMethod* VerifyInvocationArgs(const Instruction* inst,
@@ -648,14 +661,14 @@
 
   const uint32_t dex_method_idx_;  // The method we're working on.
   // Its object representation if known.
-  ConstHandle<mirror::ArtMethod> mirror_method_ GUARDED_BY(Locks::mutator_lock_);
+  Handle<mirror::ArtMethod> mirror_method_ GUARDED_BY(Locks::mutator_lock_);
   const uint32_t method_access_flags_;  // Method's access flags.
   const RegType* return_type_;  // Lazily computed return type of the method.
   const DexFile* const dex_file_;  // The dex file containing the method.
   // The dex_cache for the declaring class of the method.
-  ConstHandle<mirror::DexCache> dex_cache_ GUARDED_BY(Locks::mutator_lock_);
+  Handle<mirror::DexCache> dex_cache_ GUARDED_BY(Locks::mutator_lock_);
   // The class loader for the declaring class of the method.
-  ConstHandle<mirror::ClassLoader> class_loader_ GUARDED_BY(Locks::mutator_lock_);
+  Handle<mirror::ClassLoader> class_loader_ GUARDED_BY(Locks::mutator_lock_);
   const DexFile::ClassDef* const class_def_;  // The class def of the declaring class of the method.
   const DexFile::CodeItem* const code_item_;  // The code item containing the code for the method.
   const RegType* declaring_class_;  // Lazily computed reg type of the method's declaring class.
@@ -664,7 +677,7 @@
   // The dex PC of a FindLocksAtDexPc request, -1 otherwise.
   uint32_t interesting_dex_pc_;
   // The container into which FindLocksAtDexPc should write the registers containing held locks,
-  // NULL if we're not doing FindLocksAtDexPc.
+  // nullptr if we're not doing FindLocksAtDexPc.
   std::vector<uint32_t>* monitor_enter_dex_pcs_;
 
   // The types of any error that occurs.
@@ -706,6 +719,11 @@
   // Indicates the method being verified contains at least one invoke-virtual/range
   // or invoke-interface/range.
   bool has_virtual_or_interface_invokes_;
+
+  // Indicates whether we verify to dump the info. In that case we accept quickened instructions
+  // even though we might detect to be a compiler. Should only be set when running
+  // VerifyMethodAndDump.
+  const bool verify_to_dump_;
 };
 std::ostream& operator<<(std::ostream& os, const MethodVerifier::FailureKind& rhs);
 
diff --git a/test/004-ReferenceMap/stack_walk_refmap_jni.cc b/test/004-ReferenceMap/stack_walk_refmap_jni.cc
index 7929554..e914bd9 100644
--- a/test/004-ReferenceMap/stack_walk_refmap_jni.cc
+++ b/test/004-ReferenceMap/stack_walk_refmap_jni.cc
@@ -14,138 +14,57 @@
  * limitations under the License.
  */
 
-#include <stdio.h>
-#include <memory>
-
-#include "class_linker.h"
-#include "dex_file-inl.h"
-#include "gc_map.h"
-#include "mirror/art_method-inl.h"
-#include "mirror/class-inl.h"
-#include "mirror/object_array-inl.h"
-#include "mirror/object-inl.h"
-#include "scoped_thread_state_change.h"
-#include "thread.h"
+#include "check_reference_map_visitor.h"
 #include "jni.h"
-#include "verifier/method_verifier.h"
 
 namespace art {
 
-#define IS_IN_REF_BITMAP(ref_bitmap, reg) \
-    (((reg) < m->GetCodeItem()->registers_size_) && \
-     ((*((ref_bitmap) + (reg)/8) >> ((reg) % 8) ) & 0x01))
+#define CHECK_REGS_CONTAIN_REFS(native_pc_offset, ...) do { \
+  int t[] = {__VA_ARGS__}; \
+  int t_size = sizeof(t) / sizeof(*t); \
+  CheckReferences(t, t_size, m->NativePcOffset(m->ToNativePc(native_pc_offset))); \
+} while (false);
 
-#define CHECK_REGS_CONTAIN_REFS(...)     \
-  do {                                   \
-    int t[] = {__VA_ARGS__};             \
-    int t_size = sizeof(t) / sizeof(*t);      \
-    for (int i = 0; i < t_size; ++i)          \
-      CHECK(IS_IN_REF_BITMAP(ref_bitmap, t[i])) \
-          << "Error: Reg @ " << i << "-th argument is not in GC map"; \
-  } while (false)
-
-struct ReferenceMap2Visitor : public StackVisitor {
-  explicit ReferenceMap2Visitor(Thread* thread)
-      SHARED_LOCKS_REQUIRED(Locks::mutator_lock_)
-      : StackVisitor(thread, NULL) {
-  }
+struct ReferenceMap2Visitor : public CheckReferenceMapVisitor {
+  explicit ReferenceMap2Visitor(Thread* thread) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_)
+      : CheckReferenceMapVisitor(thread) {}
 
   bool VisitFrame() SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
+    if (CheckReferenceMapVisitor::VisitFrame()) {
+      return true;
+    }
     mirror::ArtMethod* m = GetMethod();
-    if (!m || m->IsNative() || m->IsRuntimeMethod() || IsShadowFrame()) {
-      return true;
-    }
-    LOG(INFO) << "At " << PrettyMethod(m, false);
-
-    NativePcOffsetToReferenceMap map(m->GetNativeGcMap());
-
-    if (m->IsCalleeSaveMethod()) {
-      LOG(WARNING) << "no PC for " << PrettyMethod(m);
-      return true;
-    }
-
-    const uint8_t* ref_bitmap = NULL;
     std::string m_name(m->GetName());
 
     // Given the method name and the number of times the method has been called,
     // we know the Dex registers with live reference values. Assert that what we
     // find is what is expected.
     if (m_name.compare("f") == 0) {
-      ref_bitmap = map.FindBitMap(m->NativePcOffset(m->ToNativePc(0x03U)));
-      CHECK(ref_bitmap);
-      CHECK_REGS_CONTAIN_REFS(8);  // v8: this
-
-      ref_bitmap = map.FindBitMap(m->NativePcOffset(m->ToNativePc(0x06U)));
-      CHECK(ref_bitmap);
-      CHECK_REGS_CONTAIN_REFS(8, 1);  // v8: this, v1: x
-
-      ref_bitmap = map.FindBitMap(m->NativePcOffset(m->ToNativePc(0x08U)));
-      CHECK(ref_bitmap);
-      CHECK_REGS_CONTAIN_REFS(8, 3, 1);  // v8: this, v3: y, v1: x
-
-      ref_bitmap = map.FindBitMap(m->NativePcOffset(m->ToNativePc(0x0cU)));
-      CHECK(ref_bitmap);
-      CHECK_REGS_CONTAIN_REFS(8, 3, 1);  // v8: this, v3: y, v1: x
-
-      ref_bitmap = map.FindBitMap(m->NativePcOffset(m->ToNativePc(0x0eU)));
-      CHECK(ref_bitmap);
-      CHECK_REGS_CONTAIN_REFS(8, 3, 1);  // v8: this, v3: y, v1: x
-
-      ref_bitmap = map.FindBitMap(m->NativePcOffset(m->ToNativePc(0x10U)));
-      CHECK(ref_bitmap);
-      CHECK_REGS_CONTAIN_REFS(8, 3, 1);  // v8: this, v3: y, v1: x
-
-      ref_bitmap = map.FindBitMap(m->NativePcOffset(m->ToNativePc(0x13U)));
-      CHECK(ref_bitmap);
+      CHECK_REGS_CONTAIN_REFS(0x03U, 8);  // v8: this
+      CHECK_REGS_CONTAIN_REFS(0x06U, 8, 1);  // v8: this, v1: x
+      CHECK_REGS_CONTAIN_REFS(0x08U, 8, 3, 1);  // v8: this, v3: y, v1: x
+      CHECK_REGS_CONTAIN_REFS(0x0cU, 8, 3, 1);  // v8: this, v3: y, v1: x
+      CHECK_REGS_CONTAIN_REFS(0x0eU, 8, 3, 1);  // v8: this, v3: y, v1: x
+      CHECK_REGS_CONTAIN_REFS(0x10U, 8, 3, 1);  // v8: this, v3: y, v1: x
       // v2 is added because of the instruction at DexPC 0024. Object merges with 0 is Object. See:
       //   0024: move-object v3, v2
       //   0025: goto 0013
       // Detaled dex instructions for ReferenceMap.java are at the end of this function.
       // CHECK_REGS_CONTAIN_REFS(8, 3, 2, 1);  // v8: this, v3: y, v2: y, v1: x
       // We eliminate the non-live registers at a return, so only v3 is live:
-      CHECK_REGS_CONTAIN_REFS(3);  // v3: y
-
-      ref_bitmap = map.FindBitMap(m->NativePcOffset(m->ToNativePc(0x18U)));
-      CHECK(ref_bitmap);
-      CHECK_REGS_CONTAIN_REFS(8, 2, 1, 0);  // v8: this, v2: y, v1: x, v0: ex
-
-      ref_bitmap = map.FindBitMap(m->NativePcOffset(m->ToNativePc(0x1aU)));
-      CHECK(ref_bitmap);
-      CHECK_REGS_CONTAIN_REFS(8, 5, 2, 1, 0);  // v8: this, v5: x[1], v2: y, v1: x, v0: ex
-
-      ref_bitmap = map.FindBitMap(m->NativePcOffset(m->ToNativePc(0x1dU)));
-      CHECK(ref_bitmap);
-      CHECK_REGS_CONTAIN_REFS(8, 5, 2, 1, 0);  // v8: this, v5: x[1], v2: y, v1: x, v0: ex
-
-      ref_bitmap = map.FindBitMap(m->NativePcOffset(m->ToNativePc(0x1fU)));
-      CHECK(ref_bitmap);
+      CHECK_REGS_CONTAIN_REFS(0x13U);  // v3: y
+      CHECK_REGS_CONTAIN_REFS(0x18U, 8, 2, 1, 0);  // v8: this, v2: y, v1: x, v0: ex
+      CHECK_REGS_CONTAIN_REFS(0x1aU, 8, 5, 2, 1, 0);  // v8: this, v5: x[1], v2: y, v1: x, v0: ex
+      CHECK_REGS_CONTAIN_REFS(0x1dU, 8, 5, 2, 1, 0);  // v8: this, v5: x[1], v2: y, v1: x, v0: ex
       // v5 is removed from the root set because there is a "merge" operation.
       // See 0015: if-nez v2, 001f.
-      CHECK_REGS_CONTAIN_REFS(8, 2, 1, 0);  // v8: this, v2: y, v1: x, v0: ex
-
-      ref_bitmap = map.FindBitMap(m->NativePcOffset(m->ToNativePc(0x21U)));
-      CHECK(ref_bitmap);
-      CHECK_REGS_CONTAIN_REFS(8, 2, 1, 0);  // v8: this, v2: y, v1: x, v0: ex
-
-      ref_bitmap = map.FindBitMap(m->NativePcOffset(m->ToNativePc(0x27U)));
-      CHECK(ref_bitmap);
-      CHECK_REGS_CONTAIN_REFS(8, 4, 2, 1);  // v8: this, v4: ex, v2: y, v1: x
-
-      ref_bitmap = map.FindBitMap(m->NativePcOffset(m->ToNativePc(0x29U)));
-      CHECK(ref_bitmap);
-      CHECK_REGS_CONTAIN_REFS(8, 4, 2, 1);  // v8: this, v4: ex, v2: y, v1: x
-
-      ref_bitmap = map.FindBitMap(m->NativePcOffset(m->ToNativePc(0x2cU)));
-      CHECK(ref_bitmap);
-      CHECK_REGS_CONTAIN_REFS(8, 4, 2, 1);  // v8: this, v4: ex, v2: y, v1: x
-
-      ref_bitmap = map.FindBitMap(m->NativePcOffset(m->ToNativePc(0x2fU)));
-      CHECK(ref_bitmap);
-      CHECK_REGS_CONTAIN_REFS(8, 4, 3, 2, 1);  // v8: this, v4: ex, v3: y, v2: y, v1: x
-
-      ref_bitmap = map.FindBitMap(m->NativePcOffset(m->ToNativePc(0x32U)));
-      CHECK(ref_bitmap);
-      CHECK_REGS_CONTAIN_REFS(8, 3, 2, 1, 0);  // v8: this, v3: y, v2: y, v1: x, v0: ex
+      CHECK_REGS_CONTAIN_REFS(0x1fU, 8, 2, 1, 0);  // v8: this, v2: y, v1: x, v0: ex
+      CHECK_REGS_CONTAIN_REFS(0x21U, 8, 2, 1, 0);  // v8: this, v2: y, v1: x, v0: ex
+      CHECK_REGS_CONTAIN_REFS(0x27U, 8, 4, 2, 1);  // v8: this, v4: ex, v2: y, v1: x
+      CHECK_REGS_CONTAIN_REFS(0x29U, 8, 4, 2, 1);  // v8: this, v4: ex, v2: y, v1: x
+      CHECK_REGS_CONTAIN_REFS(0x2cU, 8, 4, 2, 1);  // v8: this, v4: ex, v2: y, v1: x
+      CHECK_REGS_CONTAIN_REFS(0x2fU, 8, 4, 3, 2, 1);  // v8: this, v4: ex, v3: y, v2: y, v1: x
+      CHECK_REGS_CONTAIN_REFS(0x32U, 8, 3, 2, 1, 0);  // v8: this, v3: y, v2: y, v1: x, v0: ex
     }
 
     return true;
diff --git a/test/004-StackWalk/stack_walk_jni.cc b/test/004-StackWalk/stack_walk_jni.cc
index 30a0d59..c40de7e 100644
--- a/test/004-StackWalk/stack_walk_jni.cc
+++ b/test/004-StackWalk/stack_walk_jni.cc
@@ -14,54 +14,29 @@
  * limitations under the License.
  */
 
-#include <stdio.h>
-#include <memory>
-
-#include "class_linker.h"
-#include "gc_map.h"
-#include "mirror/art_method-inl.h"
-#include "mirror/class-inl.h"
-#include "mirror/object_array-inl.h"
-#include "mirror/object-inl.h"
+#include "check_reference_map_visitor.h"
 #include "jni.h"
-#include "scoped_thread_state_change.h"
 
 namespace art {
 
-#define REG(reg_bitmap, reg) \
-    (((reg) < m->GetCodeItem()->registers_size_) && \
-     ((*((reg_bitmap) + (reg)/8) >> ((reg) % 8) ) & 0x01))
-
-#define CHECK_REGS(...) if (!IsShadowFrame()) { \
-    int t[] = {__VA_ARGS__}; \
-    int t_size = sizeof(t) / sizeof(*t); \
-    for (int i = 0; i < t_size; ++i) \
-      CHECK(REG(reg_bitmap, t[i])) << "Error: Reg " << i << " is not in RegisterMap"; \
-  }
+#define CHECK_REGS(...) do { \
+  int t[] = {__VA_ARGS__}; \
+  int t_size = sizeof(t) / sizeof(*t); \
+  CheckReferences(t, t_size, GetNativePcOffset()); \
+} while (false);
 
 static int gJava_StackWalk_refmap_calls = 0;
 
-struct TestReferenceMapVisitor : public StackVisitor {
-  explicit TestReferenceMapVisitor(Thread* thread)
-      SHARED_LOCKS_REQUIRED(Locks::mutator_lock_)
-      : StackVisitor(thread, NULL) {
-  }
+class TestReferenceMapVisitor : public CheckReferenceMapVisitor {
+ public:
+  explicit TestReferenceMapVisitor(Thread* thread) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_)
+      : CheckReferenceMapVisitor(thread) {}
 
   bool VisitFrame() SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
-    mirror::ArtMethod* m = GetMethod();
-    CHECK(m != NULL);
-    LOG(INFO) << "At " << PrettyMethod(m, false);
-
-    if (m->IsCalleeSaveMethod() || m->IsNative()) {
-      LOG(WARNING) << "no PC for " << PrettyMethod(m);
-      CHECK_EQ(GetDexPc(), DexFile::kDexNoIndex);
+    if (CheckReferenceMapVisitor::VisitFrame()) {
       return true;
     }
-    const uint8_t* reg_bitmap = NULL;
-    if (!IsShadowFrame()) {
-      NativePcOffsetToReferenceMap map(m->GetNativeGcMap());
-      reg_bitmap = map.FindBitMap(GetNativePcOffset());
-    }
+    mirror::ArtMethod* m = GetMethod();
     StringPiece m_name(m->GetName());
 
     // Given the method name and the number of times the method has been called,
diff --git a/test/121-modifiers/build b/test/121-modifiers/build
new file mode 100644
index 0000000..d73be86
--- /dev/null
+++ b/test/121-modifiers/build
@@ -0,0 +1,34 @@
+#!/bin/bash
+#
+# Copyright (C) 2014 The Android Open Source Project
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#     http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+# Stop if something fails.
+set -e
+
+# The classes are pre-compiled and modified with ASM.
+#
+# To reproduce, compile the source files. Asm.java needs the ASM libraries (core and tree). Then
+# run Asm.java, which produces Inf.out and NonInf.out. Rename these to class files and put them
+# into the classes directory (this assumes the ASM libraries are names asm.jar and asm-tree.jar):
+#
+# javac Inf.java NonInf.java Main.java
+# javac -cp asm.jar:asm-tree.jar:. Asm.java
+# java -cp asm.jar:asm-tree.jar:. Asm
+# mv Inf.out classes/Inf.class
+# mv NonInf.out classes/NonInf.class
+# mv Main.class A.class A\$B.class A\$C.class classes/
+
+${DX} --debug --dex --dump-to=classes.lst --output=classes.dex classes
+zip $TEST_NAME.jar classes.dex
diff --git a/test/121-modifiers/classes/A$B.class b/test/121-modifiers/classes/A$B.class
new file mode 100644
index 0000000..bd7ebfe
--- /dev/null
+++ b/test/121-modifiers/classes/A$B.class
Binary files differ
diff --git a/test/121-modifiers/classes/A$C.class b/test/121-modifiers/classes/A$C.class
new file mode 100644
index 0000000..3ae872e
--- /dev/null
+++ b/test/121-modifiers/classes/A$C.class
Binary files differ
diff --git a/test/121-modifiers/classes/A.class b/test/121-modifiers/classes/A.class
new file mode 100644
index 0000000..d89d029
--- /dev/null
+++ b/test/121-modifiers/classes/A.class
Binary files differ
diff --git a/test/121-modifiers/classes/Inf.class b/test/121-modifiers/classes/Inf.class
new file mode 100644
index 0000000..e8dd680
--- /dev/null
+++ b/test/121-modifiers/classes/Inf.class
Binary files differ
diff --git a/test/121-modifiers/classes/Main.class b/test/121-modifiers/classes/Main.class
new file mode 100644
index 0000000..e044074
--- /dev/null
+++ b/test/121-modifiers/classes/Main.class
Binary files differ
diff --git a/test/121-modifiers/classes/NonInf.class b/test/121-modifiers/classes/NonInf.class
new file mode 100644
index 0000000..0f1e826
--- /dev/null
+++ b/test/121-modifiers/classes/NonInf.class
Binary files differ
diff --git a/test/121-modifiers/expected.txt b/test/121-modifiers/expected.txt
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/test/121-modifiers/expected.txt
diff --git a/test/121-modifiers/info.txt b/test/121-modifiers/info.txt
new file mode 100644
index 0000000..943cbf8
--- /dev/null
+++ b/test/121-modifiers/info.txt
@@ -0,0 +1 @@
+This is a test checking the modifier (access flags) handling of ART.
diff --git a/test/121-modifiers/src/Asm.java b/test/121-modifiers/src/Asm.java
new file mode 100644
index 0000000..f120622
--- /dev/null
+++ b/test/121-modifiers/src/Asm.java
@@ -0,0 +1,125 @@
+/*
+ * 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.
+ */
+
+import org.objectweb.asm.*;
+import org.objectweb.asm.tree.*;
+import java.io.*;
+import java.util.*;
+
+public class Asm {
+  /*
+
+  Overall class access flags:
+
+      0x0001 |  // public
+      0x0010 |  // final
+      0x0020 |  // super
+      0x0200 |  // interface
+      0x0400 |  // abstract
+      0x1000 |  // synthetic
+      0x2000 |  // annotation
+      0x4000 ;  // enum
+
+  */
+
+  public final static int INTERFACE_DEFINED_BITS =
+      0x0001 |  // public, may be set.
+      0x0010 |  // final, must not be set.
+      0x0020 |  // super, must not be set.
+      0x0200 |  // interface, must be set.
+      0x0400 |  // abstract, must be set.
+      0x1000 |  // synthetic, may be set.
+      0x2000 |  // annotation, may be set (annotation implies interface)
+      0x4000 ;  // enum, must not be set.
+
+  public final static int CLASS_DEFINED_BITS =
+      0x0001 |  // public, may be set.
+      0x0010 |  // final, may be set.
+      0x0020 |  // super, may be set.
+      0x0200 |  // interface, must not be set.
+      0x0400 |  // abstract, may be set.
+      0x1000 |  // synthetic, may be set.
+      0x2000 |  // annotation, must not be set.
+      0x4000 ;  // enum, may be set.
+
+  public final static int FIELD_DEFINED_BITS =
+       0x0001 |  // public
+       0x0002 |  // private
+       0x0004 |  // protected
+       0x0008 |  // static
+       0x0010 |  // final
+       0x0040 |  // volatile
+       0x0080 |  // transient
+       0x1000 |  // synthetic
+       0x4000 ;  // enum
+
+  public final static int METHOD_DEFINED_BITS =
+       0x0001 |  // public
+       0x0002 |  // private
+       0x0004 |  // protected
+       0x0008 |  // static
+       0x0010 |  // final
+       0x0020 |  // synchronized
+       0x0040 |  // bridge
+       0x0080 |  // varargs
+       0x0100 |  // native
+       0x0400 |  // abstract
+       0x0800 |  // strictfp
+       0x1000 ;  // synthetic
+
+  public static void main(String args[]) throws Exception {
+    modify("Inf");
+    modify("NonInf");
+  }
+
+  private static void modify(String clazz) throws Exception {
+    ClassNode classNode = new ClassNode();
+    ClassReader cr = new ClassReader(clazz);
+    cr.accept(classNode, 0);
+
+    modify(classNode);
+
+    ClassWriter cw = new ClassWriter(0);
+    classNode.accept(cw);
+    byte[] b = cw.toByteArray();
+    OutputStream out = new FileOutputStream(clazz + ".out");
+    out.write(b, 0, b.length);
+    out.close();
+  }
+
+  private static void modify(ClassNode classNode) throws Exception {
+    int classFlagsOr = 0xFFFF;
+    // Check whether classNode is an interface or class.
+    if ((classNode.access & Opcodes.ACC_INTERFACE) == 0) {
+      classFlagsOr ^= CLASS_DEFINED_BITS;
+    } else {
+      classFlagsOr ^= INTERFACE_DEFINED_BITS;
+    }
+    classNode.access |= classFlagsOr;
+
+    // Fields.
+    int fieldFlagsOr = 0xFFFF ^ FIELD_DEFINED_BITS;
+    for (FieldNode fieldNode : (List<FieldNode>)classNode.fields) {
+      fieldNode.access |= fieldFlagsOr;
+    }
+
+    // Methods.
+    int methodFlagsOr = 0xFFFF ^ METHOD_DEFINED_BITS;
+    for (MethodNode methodNode :(List<MethodNode>) classNode.methods) {
+      methodNode.access |= methodFlagsOr;
+    }
+  }
+}
diff --git a/test/121-modifiers/src/Inf.java b/test/121-modifiers/src/Inf.java
new file mode 100644
index 0000000..1dadae0
--- /dev/null
+++ b/test/121-modifiers/src/Inf.java
@@ -0,0 +1,21 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+public interface Inf {
+
+  public final int I = 0;
+
+}
\ No newline at end of file
diff --git a/test/121-modifiers/src/Main.java b/test/121-modifiers/src/Main.java
new file mode 100644
index 0000000..e21b789
--- /dev/null
+++ b/test/121-modifiers/src/Main.java
@@ -0,0 +1,211 @@
+/*
+ * 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.
+ */
+
+// These classes are to check the additional flags for inner classes.
+class A {
+  private static class B {
+  }
+  protected static interface C {
+  }
+}
+
+public class Main {
+  public final static int INTERFACE_DEFINED_BITS =
+      0x0001 |  // public, may be set.
+      0x0002 |  // private, may be flagged by inner class.
+      0x0004 |  // protected, may be flagged by inner class.
+      0x0008 |  // static, may be flagged by inner class.
+      0x0010 |  // final, must not be set.
+      0x0020 |  // super, must not be set.
+      0x0200 |  // interface, must be set.
+      0x0400 |  // abstract, must be set.
+      0x1000 |  // synthetic, may be set.
+      0x2000 |  // annotation, may be set (annotation implies interface)
+      0x4000 ;  // enum, must not be set.
+
+  public final static int CLASS_DEFINED_BITS =
+      0x0001 |  // public, may be set.
+      0x0002 |  // private, may be flagged by inner class.
+      0x0004 |  // protected, may be flagged by inner class.
+      0x0008 |  // static, may be flagged by inner class.
+      0x0010 |  // final, may be set.
+      0x0020 |  // super, may be set.
+      0x0200 |  // interface, must not be set.
+      0x0400 |  // abstract, may be set.
+      0x1000 |  // synthetic, may be set.
+      0x2000 |  // annotation, must not be set.
+      0x4000 ;  // enum, may be set.
+
+  public final static int FIELD_DEFINED_BITS =
+       0x0001 |  // public
+       0x0002 |  // private
+       0x0004 |  // protected
+       0x0008 |  // static
+       0x0010 |  // final
+       0x0040 |  // volatile
+       0x0080 |  // transient
+       0x1000 |  // synthetic
+       0x4000 ;  // enum
+
+  public final static int METHOD_DEFINED_BITS =
+       0x0001 |  // public
+       0x0002 |  // private
+       0x0004 |  // protected
+       0x0008 |  // static
+       0x0010 |  // final
+       0x0020 |  // synchronized
+       0x0040 |  // bridge
+       0x0080 |  // varargs
+       0x0100 |  // native
+       0x0400 |  // abstract
+       0x0800 |  // strictfp
+       0x1000 ;  // synthetic
+
+  public static void main(String args[]) throws Exception {
+    check("Inf");
+    check("NonInf");
+    check("A");
+    check("A$B");
+  }
+
+  private static void check(String className) throws Exception {
+    Class<?> clazz = Class.forName(className);
+    if (className.equals("Inf")) {
+      if (!clazz.isInterface()) {
+        throw new RuntimeException("Expected an interface.");
+      }
+      int undefinedBits = 0xFFFF ^ INTERFACE_DEFINED_BITS;
+      if ((clazz.getModifiers() & undefinedBits) != 0) {
+        System.out.println("Clazz.getModifiers(): " + Integer.toBinaryString(clazz.getModifiers()));
+        System.out.println("INTERFACE_DEF_BITS: " + Integer.toBinaryString(INTERFACE_DEFINED_BITS));
+        throw new RuntimeException("Undefined bits for an interface: " + className);
+      }
+    } else {
+      if (clazz.isInterface()) {
+        throw new RuntimeException("Expected a class.");
+      }
+      int undefinedBits = 0xFFFF ^ CLASS_DEFINED_BITS;
+      if ((clazz.getModifiers() & undefinedBits) != 0) {
+        System.out.println("Clazz.getModifiers(): " + Integer.toBinaryString(clazz.getModifiers()));
+        System.out.println("CLASS_DEF_BITS: " + Integer.toBinaryString(CLASS_DEFINED_BITS));
+        throw new RuntimeException("Undefined bits for a class: " + className);
+      }
+    }
+
+    // Check fields.
+    for (java.lang.reflect.Field f : clazz.getDeclaredFields()) {
+      String name = f.getName();
+      int undefinedBits = 0xFFFF ^ FIELD_DEFINED_BITS;
+      if ((f.getModifiers() & undefinedBits) != 0) {
+        System.out.println("f.getModifiers(): " + Integer.toBinaryString(f.getModifiers()));
+        System.out.println("FIELD_DEF_BITS: " + Integer.toBinaryString(FIELD_DEFINED_BITS));
+        throw new RuntimeException("Unexpected field bits: " + name);
+      }
+      if (name.equals("I")) {
+        // Interface field, just check generically.
+      } else {
+        // Check the name, see that the corresponding bit is set.
+        int bitmask = getFieldMask(name);
+        if ((bitmask & f.getModifiers()) == 0) {
+          throw new RuntimeException("Expected field bit not set.");
+        }
+      }
+    }
+
+    // Check methods.
+    for (java.lang.reflect.Method m : clazz.getDeclaredMethods()) {
+      String name = m.getName();
+      int undefinedBits = 0xFFFF ^ METHOD_DEFINED_BITS;
+      if ((m.getModifiers() & undefinedBits) != 0) {
+          System.out.println("m.getModifiers(): " + Integer.toBinaryString(m.getModifiers()));
+          System.out.println("METHOD_DEF_BITS: " + Integer.toBinaryString(METHOD_DEFINED_BITS));
+        throw new RuntimeException("Unexpected method bits: " + name);
+      }
+      // Check the name, see that the corresponding bit is set.
+      int bitmask = getMethodMask(name);
+      if ((bitmask & m.getModifiers()) == 0) {
+        throw new RuntimeException("Expected method bit not set.");
+      }
+    }
+  }
+
+  private static int getFieldMask(String name) {
+    int index = name.indexOf("Field");
+    if (index > 0) {
+      String shortS = name.substring(0, index);
+      if (shortS.equals("public")) {
+        return 0x0001;
+      }
+      if (shortS.equals("private")) {
+        return 0x0002;
+      }
+      if (shortS.equals("protected")) {
+        return 0x0004;
+      }
+      if (shortS.equals("static")) {
+        return 0x0008;
+      }
+      if (shortS.equals("transient")) {
+        return 0x0080;
+      }
+      if (shortS.equals("volatile")) {
+        return 0x0040;
+      }
+      if (shortS.equals("final")) {
+        return 0x0010;
+      }
+    }
+    throw new RuntimeException("Unexpected field name " + name);
+  }
+
+  private static int getMethodMask(String name) {
+    int index = name.indexOf("Method");
+    if (index > 0) {
+      String shortS = name.substring(0, index);
+      if (shortS.equals("public")) {
+        return 0x0001;
+      }
+      if (shortS.equals("private")) {
+        return 0x0002;
+      }
+      if (shortS.equals("protected")) {
+        return 0x0004;
+      }
+      if (shortS.equals("static")) {
+        return 0x0008;
+      }
+      if (shortS.equals("synchronized")) {
+        return 0x0020;
+      }
+      if (shortS.equals("varargs")) {
+        return 0x0080;
+      }
+      if (shortS.equals("final")) {
+        return 0x0010;
+      }
+      if (shortS.equals("native")) {
+        return 0x0100;
+      }
+      if (shortS.equals("abstract")) {
+        return 0x0400;
+      }
+      if (shortS.equals("strictfp")) {
+        return 0x0800;
+      }
+    }
+    throw new RuntimeException("Unexpected method name " + name);
+  }
+}
diff --git a/test/121-modifiers/src/NonInf.java b/test/121-modifiers/src/NonInf.java
new file mode 100644
index 0000000..52e4882
--- /dev/null
+++ b/test/121-modifiers/src/NonInf.java
@@ -0,0 +1,72 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+public abstract class NonInf {
+
+  public int publicField;
+  private int privateField;
+  protected int protectedField;
+  static int staticField;
+  transient int transientField;
+  volatile int volatileField;
+  final int finalField;
+
+  public NonInf() {
+    publicField = 0;
+    privateField = 1;
+    protectedField = 2;
+    staticField = 3;
+    transientField = 4;
+    volatileField = 5;
+    finalField = 6;
+  }
+
+  public native void nativeMethod();
+
+  private int privateMethod() {
+    return 0;
+  }
+
+  protected int protectedMethod() {
+    return 0;
+  }
+
+  public int publicMethod() {
+    return 0;
+  }
+
+  public abstract int abstractMethod();
+
+  public synchronized int synchronizedMethod() {
+    return 0;
+  }
+
+  public static int staticMethod() {
+    return 0;
+  }
+
+  public strictfp double strictfpMethod() {
+    return 0.0;
+  }
+
+  public int varargsMethod(Object... args) {
+    return 0;
+  }
+
+  public final int finalMethod() {
+    return 0;
+  }
+}
\ No newline at end of file
diff --git a/test/121-simple-suspend-check/expected.txt b/test/121-simple-suspend-check/expected.txt
new file mode 100644
index 0000000..7ef22e9
--- /dev/null
+++ b/test/121-simple-suspend-check/expected.txt
@@ -0,0 +1 @@
+PASS
diff --git a/test/121-simple-suspend-check/info.txt b/test/121-simple-suspend-check/info.txt
new file mode 100644
index 0000000..61611f9
--- /dev/null
+++ b/test/121-simple-suspend-check/info.txt
@@ -0,0 +1 @@
+Simple test to ensure the compiler emits suspend checks on loops.
diff --git a/test/121-simple-suspend-check/src/Main.java b/test/121-simple-suspend-check/src/Main.java
new file mode 100644
index 0000000..80daf37
--- /dev/null
+++ b/test/121-simple-suspend-check/src/Main.java
@@ -0,0 +1,35 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+public class Main {
+  public static void main(String args[]) {
+    SpinThread thread = new SpinThread();
+    thread.setDaemon(true);
+    thread.start();
+    Runtime.getRuntime().gc();
+    try {
+      Thread.sleep(3000);
+    } catch (InterruptedException ie) {/*ignore */}
+    Runtime.getRuntime().gc();
+    System.out.println("PASS");
+  }
+}
+
+class SpinThread extends Thread {
+  public void run() {
+    while (true) {}
+  }
+}
diff --git a/test/401-optimizing-compiler/src/Main.java b/test/401-optimizing-compiler/src/Main.java
index 2c6d1c2..07c407b 100644
--- a/test/401-optimizing-compiler/src/Main.java
+++ b/test/401-optimizing-compiler/src/Main.java
@@ -97,6 +97,11 @@
     if (exception == null) {
       throw new Error("Missing NullPointerException");
     }
+
+    result = $opt$InvokeVirtualMethod();
+    if (result != 42) {
+      throw new Error("Unexpected result: " + result);
+    }
   }
 
   public static void invokePrivate() {
@@ -205,5 +210,13 @@
     m.o = new Main();
   }
 
+  public static int $opt$InvokeVirtualMethod() {
+    return new Main().virtualMethod();
+  }
+
+  public int virtualMethod() {
+    return 42;
+  }
+
   Object o;
 }
diff --git a/test/etc/host-run-test-jar b/test/etc/host-run-test-jar
index 49aa912..d2b3fb1 100755
--- a/test/etc/host-run-test-jar
+++ b/test/etc/host-run-test-jar
@@ -27,6 +27,8 @@
 DEX2OAT=""
 FALSE_BIN="/bin/false"
 HAVE_IMAGE="y"
+TIME_OUT="y"
+TIME_OUT_VALUE=5m
 exe="${ANDROID_HOST_OUT}/bin/dalvikvm32"
 main="Main"
 
@@ -65,10 +67,12 @@
         shift
     elif [ "x$1" = "x--debug" ]; then
         DEBUGGER="y"
+        TIME_OUT="n"
         shift
     elif [ "x$1" = "x--gdb" ]; then
         GDB="y"
         DEV_MODE="y"
+        TIME_OUT="n"
         shift
     elif [ "x$1" = "x--invoke-with" ]; then
         shift
@@ -199,6 +203,10 @@
 
 JNI_OPTS="-Xjnigreflimit:512 -Xcheck:jni"
 cmdline="$INVOKE_WITH $gdb $exe $gdbargs -XXlib:$LIB $PATCHOAT $DEX2OAT $JNI_OPTS $FLAGS $INT_OPTS $DEBUGGER_OPTS $BOOT_OPT -cp $DEX_LOCATION/$TEST_NAME.jar $main"
+if [ "$TIME_OUT" = "y" ]; then
+  # Add timeout command if time out is desired.
+  cmdline="timeout $TIME_OUT_VALUE $cmdline"
+fi
 if [ "$DEV_MODE" = "y" ]; then
   if [ "$PREBUILD" = "y" ]; then
     echo "$mkdir_cmd && $prebuild_cmd && $cmdline"
@@ -221,5 +229,9 @@
   # If we are execing /bin/false we might not be on the same ISA as libsigchain.so
   # ld.so will helpfully warn us of this. Unfortunately this messes up our error
   # checking so we will just filter out the error with a grep.
-  LD_PRELOAD=libsigchain.so $cmdline "$@" 2>&1 | grep -v -E "^ERROR: ld\.so: object '.+\.so' from LD_PRELOAD cannot be preloaded: ignored\.$"
+  LD_PRELOAD=libsigchain.so $cmdline "$@" 2>&1 | grep -v -E "^ERROR: ld\.so: object '.+\.so' from LD_PRELOAD cannot be preloaded.*: ignored\.$"
+  # Add extra detail if time out is enabled.
+  if [ ${PIPESTATUS[0]} = 124 ] && [ "$TIME_OUT" = "y" ]; then
+    echo -e "\e[91mTEST TIMED OUT!\e[0m" >&2
+  fi
 fi
\ No newline at end of file