Merge "Fixed Literal String intern mismatch."
diff --git a/Android.mk b/Android.mk
index 803ba50..c0935a7 100644
--- a/Android.mk
+++ b/Android.mk
@@ -87,11 +87,20 @@
   $(ART_HOST_EXECUTABLES) \
   $(ART_HOST_DEX_DEPENDENCIES) \
   $(ART_HOST_SHARED_LIBRARY_DEPENDENCIES)
+
+ifeq ($(ART_BUILD_HOST_DEBUG),true)
+ART_HOST_DEPENDENCIES += $(ART_HOST_SHARED_LIBRARY_DEBUG_DEPENDENCIES)
+endif
+
 ART_TARGET_DEPENDENCIES := \
   $(ART_TARGET_EXECUTABLES) \
   $(ART_TARGET_DEX_DEPENDENCIES) \
   $(ART_TARGET_SHARED_LIBRARY_DEPENDENCIES)
 
+ifeq ($(ART_BUILD_TARGET_DEBUG),true)
+ART_TARGET_DEPENDENCIES += $(ART_TARGET_SHARED_LIBRARY_DEBUG_DEPENDENCIES)
+endif
+
 ########################################################################
 # test rules
 
diff --git a/build/Android.common_path.mk b/build/Android.common_path.mk
index 6de5aef..4466118 100644
--- a/build/Android.common_path.mk
+++ b/build/Android.common_path.mk
@@ -97,14 +97,19 @@
 ART_TARGET_DEX_DEPENDENCIES := $(foreach jar,$(TARGET_CORE_JARS),$(TARGET_OUT_JAVA_LIBRARIES)/$(jar).jar)
 
 ART_CORE_SHARED_LIBRARIES := libjavacore libopenjdk libopenjdkjvm libopenjdkjvmti
+ART_CORE_SHARED_DEBUG_LIBRARIES := libopenjdkd libopenjdkjvmd libopenjdkjvmtid
 ART_HOST_SHARED_LIBRARY_DEPENDENCIES := $(foreach lib,$(ART_CORE_SHARED_LIBRARIES), $(ART_HOST_OUT_SHARED_LIBRARIES)/$(lib)$(ART_HOST_SHLIB_EXTENSION))
+ART_HOST_SHARED_LIBRARY_DEBUG_DEPENDENCIES := $(foreach lib,$(ART_CORE_SHARED_DEBUG_LIBRARIES), $(ART_HOST_OUT_SHARED_LIBRARIES)/$(lib)$(ART_HOST_SHLIB_EXTENSION))
 ifdef HOST_2ND_ARCH
 ART_HOST_SHARED_LIBRARY_DEPENDENCIES += $(foreach lib,$(ART_CORE_SHARED_LIBRARIES), $(2ND_HOST_OUT_SHARED_LIBRARIES)/$(lib).so)
+ART_HOST_SHARED_LIBRARY_DEBUG_DEPENDENCIES += $(foreach lib,$(ART_CORE_SHARED_DEBUG_LIBRARIES), $(2ND_HOST_OUT_SHARED_LIBRARIES)/$(lib).so)
 endif
 
 ART_TARGET_SHARED_LIBRARY_DEPENDENCIES := $(foreach lib,$(ART_CORE_SHARED_LIBRARIES), $(TARGET_OUT_SHARED_LIBRARIES)/$(lib).so)
+ART_TARGET_SHARED_LIBRARY_DEBUG_DEPENDENCIES := $(foreach lib,$(ART_CORE_SHARED_DEBUG_LIBRARIES), $(TARGET_OUT_SHARED_LIBRARIES)/$(lib).so)
 ifdef TARGET_2ND_ARCH
 ART_TARGET_SHARED_LIBRARY_DEPENDENCIES += $(foreach lib,$(ART_CORE_SHARED_LIBRARIES), $(2ND_TARGET_OUT_SHARED_LIBRARIES)/$(lib).so)
+ART_TARGET_SHARED_LIBRARY_DEBUG_DEPENDENCIES += $(foreach lib,$(ART_CORE_SHARED_DEBUG_LIBRARIES), $(2ND_TARGET_OUT_SHARED_LIBRARIES)/$(lib).so)
 endif
 
 ART_CORE_DEBUGGABLE_EXECUTABLES := \
diff --git a/build/Android.gtest.mk b/build/Android.gtest.mk
index 0a465c4..bcf48fd 100644
--- a/build/Android.gtest.mk
+++ b/build/Android.gtest.mk
@@ -40,6 +40,7 @@
   Interfaces \
   Lookup \
   Main \
+  ManyMethods \
   MethodTypes \
   MultiDex \
   MultiDexModifiedSecondary \
@@ -103,6 +104,7 @@
 ART_GTEST_compiler_driver_test_DEX_DEPS := AbstractMethod StaticLeafMethods ProfileTestMultiDex
 ART_GTEST_dex_cache_test_DEX_DEPS := Main Packages MethodTypes
 ART_GTEST_dex_file_test_DEX_DEPS := GetMethodSignature Main Nested MultiDex
+ART_GTEST_dexlayout_test_DEX_DEPS := ManyMethods
 ART_GTEST_dex2oat_test_DEX_DEPS := $(ART_GTEST_dex2oat_environment_tests_DEX_DEPS) Statics VerifierDeps
 ART_GTEST_exception_test_DEX_DEPS := ExceptionHandle
 ART_GTEST_image_test_DEX_DEPS := ImageLayoutA ImageLayoutB DefaultMethods
diff --git a/cmdline/cmdline_parser_test.cc b/cmdline/cmdline_parser_test.cc
index 1a2b9cd..9f12f64 100644
--- a/cmdline/cmdline_parser_test.cc
+++ b/cmdline/cmdline_parser_test.cc
@@ -22,6 +22,7 @@
 #include <numeric>
 #include "gtest/gtest.h"
 #include "runtime/experimental_flags.h"
+#include "runtime/runtime.h"
 
 #define EXPECT_NULL(expected) EXPECT_EQ(reinterpret_cast<const void*>(expected), \
                                         reinterpret_cast<void*>(nullptr));
diff --git a/cmdline/cmdline_types.h b/cmdline/cmdline_types.h
index e33a207..0d2aed8 100644
--- a/cmdline/cmdline_types.h
+++ b/cmdline/cmdline_types.h
@@ -18,6 +18,8 @@
 
 #define CMDLINE_NDEBUG 1  // Do not output any debugging information for parsing.
 
+#include <list>
+
 #include "memory_representation.h"
 #include "detail/cmdline_debug_detail.h"
 #include "cmdline_type_parser.h"
diff --git a/compiler/compiler.h b/compiler/compiler.h
index 908d366..cd4c591 100644
--- a/compiler/compiler.h
+++ b/compiler/compiler.h
@@ -25,11 +25,11 @@
 
 namespace jit {
   class JitCodeCache;
-}
+}  // namespace jit
 namespace mirror {
   class ClassLoader;
   class DexCache;
-}
+}  // namespace mirror
 
 class ArtMethod;
 class CompilerDriver;
diff --git a/compiler/debug/elf_debug_loc_writer.h b/compiler/debug/elf_debug_loc_writer.h
index cbfdbdd..bf47e8f 100644
--- a/compiler/debug/elf_debug_loc_writer.h
+++ b/compiler/debug/elf_debug_loc_writer.h
@@ -85,7 +85,7 @@
 // The result will cover all ranges where the variable is in scope.
 // PCs corresponding to stackmap with dex register map are accurate,
 // all other PCs are best-effort only.
-std::vector<VariableLocation> GetVariableLocations(
+static std::vector<VariableLocation> GetVariableLocations(
     const MethodDebugInfo* method_info,
     const std::vector<DexRegisterMap>& dex_register_maps,
     uint16_t vreg,
diff --git a/compiler/debug/elf_debug_writer.h b/compiler/debug/elf_debug_writer.h
index 07f7229..5d68810 100644
--- a/compiler/debug/elf_debug_writer.h
+++ b/compiler/debug/elf_debug_writer.h
@@ -29,7 +29,7 @@
 class OatHeader;
 namespace mirror {
 class Class;
-}
+}  // namespace mirror
 namespace debug {
 struct MethodDebugInfo;
 
diff --git a/compiler/driver/compiler_driver-inl.h b/compiler/driver/compiler_driver-inl.h
index 5823306..8cc1cc3 100644
--- a/compiler/driver/compiler_driver-inl.h
+++ b/compiler/driver/compiler_driver-inl.h
@@ -24,10 +24,11 @@
 #include "base/enums.h"
 #include "class_linker-inl.h"
 #include "dex_compilation_unit.h"
+#include "handle_scope-inl.h"
 #include "mirror/class_loader.h"
 #include "mirror/dex_cache-inl.h"
+#include "runtime.h"
 #include "scoped_thread_state_change-inl.h"
-#include "handle_scope-inl.h"
 
 namespace art {
 
@@ -149,6 +150,11 @@
   return resolved_method;
 }
 
+inline VerificationResults* CompilerDriver::GetVerificationResults() const {
+  DCHECK(Runtime::Current()->IsAotCompiler());
+  return verification_results_;
+}
+
 }  // namespace art
 
 #endif  // ART_COMPILER_DRIVER_COMPILER_DRIVER_INL_H_
diff --git a/compiler/driver/compiler_driver.h b/compiler/driver/compiler_driver.h
index e0d97b7..17c20b4 100644
--- a/compiler/driver/compiler_driver.h
+++ b/compiler/driver/compiler_driver.h
@@ -38,7 +38,6 @@
 #include "method_reference.h"
 #include "mirror/class.h"  // For mirror::Class::Status.
 #include "os.h"
-#include "runtime.h"
 #include "safe_map.h"
 #include "thread_pool.h"
 #include "utils/atomic_method_ref_map.h"
@@ -61,6 +60,7 @@
 class DexCompilationUnit;
 struct InlineIGetIPutData;
 class InstructionSetFeatures;
+class InternTable;
 class ParallelCompilationManager;
 class ScopedObjectAccess;
 template <class Allocator> class SrcMap;
@@ -131,10 +131,7 @@
       REQUIRES_SHARED(Locks::mutator_lock_)
       REQUIRES(!compiled_classes_lock_, !dex_to_dex_references_lock_);
 
-  VerificationResults* GetVerificationResults() const {
-    DCHECK(Runtime::Current()->IsAotCompiler());
-    return verification_results_;
-  }
+  VerificationResults* GetVerificationResults() const;
 
   InstructionSet GetInstructionSet() const {
     return instruction_set_;
diff --git a/compiler/driver/compiler_options.h b/compiler/driver/compiler_options.h
index 5a82021..89c2537 100644
--- a/compiler/driver/compiler_options.h
+++ b/compiler/driver/compiler_options.h
@@ -31,7 +31,7 @@
 
 namespace verifier {
   class VerifierDepsTest;
-}
+}  // namespace verifier
 
 class DexFile;
 
diff --git a/compiler/oat_writer.cc b/compiler/oat_writer.cc
index bc411df..fed2d34 100644
--- a/compiler/oat_writer.cc
+++ b/compiler/oat_writer.cc
@@ -33,7 +33,7 @@
 #include "dex/verification_results.h"
 #include "dex_file-inl.h"
 #include "dexlayout.h"
-#include "driver/compiler_driver.h"
+#include "driver/compiler_driver-inl.h"
 #include "driver/compiler_options.h"
 #include "gc/space/image_space.h"
 #include "gc/space/space.h"
diff --git a/compiler/oat_writer.h b/compiler/oat_writer.h
index e778f75..66b70ad 100644
--- a/compiler/oat_writer.h
+++ b/compiler/oat_writer.h
@@ -31,7 +31,7 @@
 #include "os.h"
 #include "safe_map.h"
 #include "string_reference.h"
-#include "utils/type_reference.h"
+#include "type_reference.h"
 
 namespace art {
 
diff --git a/compiler/optimizing/code_generator.h b/compiler/optimizing/code_generator.h
index 9ef692a..c2b2ebf 100644
--- a/compiler/optimizing/code_generator.h
+++ b/compiler/optimizing/code_generator.h
@@ -33,8 +33,8 @@
 #include "read_barrier_option.h"
 #include "stack_map_stream.h"
 #include "string_reference.h"
+#include "type_reference.h"
 #include "utils/label.h"
-#include "utils/type_reference.h"
 
 namespace art {
 
diff --git a/compiler/optimizing/code_generator_arm.h b/compiler/optimizing/code_generator_arm.h
index fa1c14d..2409a4d 100644
--- a/compiler/optimizing/code_generator_arm.h
+++ b/compiler/optimizing/code_generator_arm.h
@@ -24,8 +24,8 @@
 #include "nodes.h"
 #include "string_reference.h"
 #include "parallel_move_resolver.h"
+#include "type_reference.h"
 #include "utils/arm/assembler_thumb2.h"
-#include "utils/type_reference.h"
 
 namespace art {
 namespace arm {
diff --git a/compiler/optimizing/code_generator_arm64.h b/compiler/optimizing/code_generator_arm64.h
index 71e221d..7a4b3d4 100644
--- a/compiler/optimizing/code_generator_arm64.h
+++ b/compiler/optimizing/code_generator_arm64.h
@@ -25,8 +25,8 @@
 #include "nodes.h"
 #include "parallel_move_resolver.h"
 #include "string_reference.h"
+#include "type_reference.h"
 #include "utils/arm64/assembler_arm64.h"
-#include "utils/type_reference.h"
 
 // TODO(VIXL): Make VIXL compile with -Wshadow.
 #pragma GCC diagnostic push
diff --git a/compiler/optimizing/code_generator_arm_vixl.h b/compiler/optimizing/code_generator_arm_vixl.h
index 91e9a3ed..ef80951 100644
--- a/compiler/optimizing/code_generator_arm_vixl.h
+++ b/compiler/optimizing/code_generator_arm_vixl.h
@@ -24,8 +24,8 @@
 #include "nodes.h"
 #include "string_reference.h"
 #include "parallel_move_resolver.h"
+#include "type_reference.h"
 #include "utils/arm/assembler_arm_vixl.h"
-#include "utils/type_reference.h"
 
 // TODO(VIXL): make vixl clean wrt -Wshadow.
 #pragma GCC diagnostic push
diff --git a/compiler/optimizing/code_generator_mips.cc b/compiler/optimizing/code_generator_mips.cc
index d8ac99a..1978534 100644
--- a/compiler/optimizing/code_generator_mips.cc
+++ b/compiler/optimizing/code_generator_mips.cc
@@ -1674,6 +1674,7 @@
 void CodeGeneratorMIPS::EmitPcRelativeAddressPlaceholderHigh(PcRelativePatchInfo* info,
                                                              Register out,
                                                              Register base) {
+  DCHECK_NE(out, base);
   if (GetInstructionSetFeatures().IsR6()) {
     DCHECK_EQ(base, ZERO);
     __ Bind(&info->high_label);
@@ -7139,8 +7140,8 @@
       PcRelativePatchInfo* info = NewPcRelativeMethodPatch(invoke->GetTargetMethod());
       bool reordering = __ SetReorder(false);
       Register temp_reg = temp.AsRegister<Register>();
-      EmitPcRelativeAddressPlaceholderHigh(info, temp_reg, base_reg);
-      __ Addiu(temp_reg, temp_reg, /* placeholder */ 0x5678);
+      EmitPcRelativeAddressPlaceholderHigh(info, TMP, base_reg);
+      __ Addiu(temp_reg, TMP, /* placeholder */ 0x5678);
       __ SetReorder(reordering);
       break;
     }
diff --git a/compiler/optimizing/code_generator_mips.h b/compiler/optimizing/code_generator_mips.h
index ff1fde6..736b507 100644
--- a/compiler/optimizing/code_generator_mips.h
+++ b/compiler/optimizing/code_generator_mips.h
@@ -23,8 +23,8 @@
 #include "nodes.h"
 #include "parallel_move_resolver.h"
 #include "string_reference.h"
+#include "type_reference.h"
 #include "utils/mips/assembler_mips.h"
-#include "utils/type_reference.h"
 
 namespace art {
 namespace mips {
diff --git a/compiler/optimizing/code_generator_mips64.h b/compiler/optimizing/code_generator_mips64.h
index f49ad49..8405040 100644
--- a/compiler/optimizing/code_generator_mips64.h
+++ b/compiler/optimizing/code_generator_mips64.h
@@ -21,8 +21,8 @@
 #include "driver/compiler_options.h"
 #include "nodes.h"
 #include "parallel_move_resolver.h"
+#include "type_reference.h"
 #include "utils/mips64/assembler_mips64.h"
-#include "utils/type_reference.h"
 
 namespace art {
 namespace mips64 {
diff --git a/compiler/optimizing/intrinsics_arm64.h b/compiler/optimizing/intrinsics_arm64.h
index 3c53517..ff59ce9 100644
--- a/compiler/optimizing/intrinsics_arm64.h
+++ b/compiler/optimizing/intrinsics_arm64.h
@@ -24,7 +24,8 @@
 
 class MacroAssembler;
 
-}}  // namespace vixl::aarch64
+}  // namespace aarch64
+}  // namespace vixl
 
 namespace art {
 
diff --git a/compiler/utils/label.h b/compiler/utils/label.h
index 0f82ad5..4c6ae8e 100644
--- a/compiler/utils/label.h
+++ b/compiler/utils/label.h
@@ -29,24 +29,24 @@
 namespace arm {
   class ArmAssembler;
   class Thumb2Assembler;
-}
+}  // namespace arm
 namespace arm64 {
   class Arm64Assembler;
-}
+}  // namespace arm64
 namespace mips {
   class MipsAssembler;
-}
+}  // namespace mips
 namespace mips64 {
   class Mips64Assembler;
-}
+}  // namespace mips64
 namespace x86 {
   class X86Assembler;
   class NearLabel;
-}
+}  // namespace x86
 namespace x86_64 {
   class X86_64Assembler;
   class NearLabel;
-}
+}  // namespace x86_64
 
 class ExternalLabel {
  public:
diff --git a/compiler/utils/managed_register.h b/compiler/utils/managed_register.h
index 184cdf5..2b7b2aa 100644
--- a/compiler/utils/managed_register.h
+++ b/compiler/utils/managed_register.h
@@ -26,24 +26,24 @@
 
 namespace arm {
 class ArmManagedRegister;
-}
+}  // namespace arm
 namespace arm64 {
 class Arm64ManagedRegister;
-}
+}  // namespace arm64
 namespace mips {
 class MipsManagedRegister;
-}
+}  // namespace mips
 namespace mips64 {
 class Mips64ManagedRegister;
-}
+}  // namespace mips64
 
 namespace x86 {
 class X86ManagedRegister;
-}
+}  // namespace x86
 
 namespace x86_64 {
 class X86_64ManagedRegister;
-}
+}  // namespace x86_64
 
 class ManagedRegister : public ValueObject {
  public:
diff --git a/compiler/verifier_deps_test.cc b/compiler/verifier_deps_test.cc
index 4d55eb0..dd09fed 100644
--- a/compiler/verifier_deps_test.cc
+++ b/compiler/verifier_deps_test.cc
@@ -25,8 +25,8 @@
 #include "dex/verified_method.h"
 #include "dex_file.h"
 #include "dex_file_types.h"
+#include "driver/compiler_driver-inl.h"
 #include "driver/compiler_options.h"
-#include "driver/compiler_driver.h"
 #include "handle_scope-inl.h"
 #include "indenter.h"
 #include "mirror/class_loader.h"
diff --git a/dex2oat/include/dex2oat_return_codes.h b/dex2oat/include/dex2oat_return_codes.h
index cc5400f..ad09d47 100644
--- a/dex2oat/include/dex2oat_return_codes.h
+++ b/dex2oat/include/dex2oat_return_codes.h
@@ -21,9 +21,10 @@
 namespace dex2oat {
 
 enum class ReturnCode : int {
-  kNoFailure = 0,
-  kOther = 1,
-  kCreateRuntime = 2,
+  kNoFailure = 0,          // No failure, execution completed successfully.
+  kOther = 1,              // Some other not closer specified error occurred.
+  kCreateRuntime = 2,      // Dex2oat failed creating a runtime. This may be indicative
+                           // of a missing or out of date boot image, for example.
 };
 
 }  // namespace dex2oat
diff --git a/dexlayout/dexlayout_test.cc b/dexlayout/dexlayout_test.cc
index a0533f2..1d09a7f 100644
--- a/dexlayout/dexlayout_test.cc
+++ b/dexlayout/dexlayout_test.cc
@@ -23,7 +23,9 @@
 
 #include "base/unix_file/fd_file.h"
 #include "common_runtime_test.h"
+#include "dex_file-inl.h"
 #include "exec_utils.h"
+#include "jit/profile_compilation_info.h"
 #include "utils.h"
 
 namespace art {
@@ -40,9 +42,6 @@
     "qAAAAAYAAAACAAAAwAAAAAEgAAACAAAAAAEAAAIgAAAHAAAAMAEAAAMgAAACAAAAaQEAAAAgAAAC"
     "AAAAdQEAAAAQAAABAAAAjAEAAA==";
 
-static const char kDexFileLayoutInputProfile[] =
-    "cHJvADAwNwAAAAAAAAgAAAB4AQMAAAAAAQ==";
-
 // Dex file with catch handler unreferenced by try blocks.
 // Constructed by building a dex file with try/catch blocks and hex editing.
 static const char kUnreferencedCatchHandlerInputDex[] =
@@ -317,6 +316,56 @@
     return true;
   }
 
+  // Create a profile with some subset of methods and classes.
+  void CreateProfile(const std::string& input_dex,
+                     const std::string& out_profile,
+                     const std::string& dex_location) {
+    std::vector<std::unique_ptr<const DexFile>> dex_files;
+    std::string error_msg;
+    bool result = DexFile::Open(input_dex.c_str(),
+                                input_dex,
+                                false,
+                                &error_msg,
+                                &dex_files);
+
+    ASSERT_TRUE(result) << error_msg;
+    ASSERT_GE(dex_files.size(), 1u);
+
+    size_t profile_methods = 0;
+    size_t profile_classes = 0;
+    ProfileCompilationInfo pfi;
+    std::vector<ProfileMethodInfo> pmis;
+    std::set<DexCacheResolvedClasses> classes;
+    for (const std::unique_ptr<const DexFile>& dex_file : dex_files) {
+      for (uint32_t i = 0; i < dex_file->NumMethodIds(); i += 2) {
+        if ((i & 3) != 0) {
+          pfi.AddMethodIndex(dex_location,
+                             dex_file->GetLocationChecksum(),
+                             i);
+          ++profile_methods;
+        }
+      }
+      DexCacheResolvedClasses cur_classes(dex_location,
+                                          dex_location,
+                                          dex_file->GetLocationChecksum());
+      // Add every even class too.
+      for (uint32_t i = 0; i < dex_file->NumClassDefs(); i += 1) {
+        cur_classes.AddClass(dex_file->GetClassDef(i).class_idx_);
+        ++profile_classes;
+      }
+    }
+    pfi.AddMethodsAndClasses(pmis, classes);
+    // Write to provided file.
+    std::unique_ptr<File> file(OS::CreateEmptyFile(out_profile.c_str()));
+    ASSERT_TRUE(file != nullptr);
+    pfi.Save(file->Fd());
+    if (file->FlushCloseOrErase() != 0) {
+      PLOG(FATAL) << "Could not flush and close test file.";
+    }
+    EXPECT_GE(profile_methods, 0u);
+    EXPECT_GE(profile_classes, 0u);
+  }
+
   // Runs DexFileLayout test.
   bool DexFileLayoutExec(std::string* error_msg) {
     ScratchFile tmp_file;
@@ -328,7 +377,8 @@
     std::string dex_file = tmp_dir + "classes.dex";
     WriteFileBase64(kDexFileLayoutInputDex, dex_file.c_str());
     std::string profile_file = tmp_dir + "primary.prof";
-    WriteFileBase64(kDexFileLayoutInputProfile, profile_file.c_str());
+    CreateProfile(dex_file, profile_file, dex_file);
+    // WriteFileBase64(kDexFileLayoutInputProfile, profile_file.c_str());
     std::string output_dex = tmp_dir + "classes.dex.new";
 
     std::string dexlayout = GetTestAndroidRoot() + "/bin/dexlayout";
@@ -358,11 +408,24 @@
     size_t tmp_last_slash = tmp_name.rfind("/");
     std::string tmp_dir = tmp_name.substr(0, tmp_last_slash + 1);
 
-    // Write inputs and expected outputs.
+    // Unzip the test dex file to the classes.dex destination. It is required to unzip since
+    // opening from jar recalculates the dex location checksum.
     std::string dex_file = tmp_dir + "classes.dex";
-    WriteFileBase64(kDexFileLayoutInputDex, dex_file.c_str());
+
+    std::vector<std::string> unzip_args = {
+        "/usr/bin/unzip",
+        GetTestDexFileName("ManyMethods"),
+        "classes.dex",
+        "-d",
+        tmp_dir,
+    };
+    if (!art::Exec(unzip_args, error_msg)) {
+      LOG(ERROR) << "Failed to unzip dex";
+      return false;
+    }
+
     std::string profile_file = tmp_dir + "primary.prof";
-    WriteFileBase64(kDexFileLayoutInputProfile, profile_file.c_str());
+    CreateProfile(dex_file, profile_file, dex_file);
     std::string output_dex = tmp_dir + "classes.dex.new";
     std::string second_output_dex = tmp_dir + "classes.dex.new.new";
 
@@ -371,14 +434,19 @@
 
     // -v makes sure that the layout did not corrupt the dex file.
     std::vector<std::string> dexlayout_exec_argv =
-        { dexlayout, "-v", "-w", tmp_dir, "-o", tmp_name, "-p", profile_file, dex_file };
+        { dexlayout, "-i", "-v", "-w", tmp_dir, "-o", tmp_name, "-p", profile_file, dex_file };
     if (!::art::Exec(dexlayout_exec_argv, error_msg)) {
       return false;
     }
 
+    // Recreate the profile with the new dex location. This is required so that the profile dex
+    // location matches.
+    CreateProfile(dex_file, profile_file, output_dex);
+
     // -v makes sure that the layout did not corrupt the dex file.
+    // -i since the checksum won't match from the first layout.
     std::vector<std::string> second_dexlayout_exec_argv =
-        { dexlayout, "-v", "-w", tmp_dir, "-o", tmp_name, "-p", profile_file, output_dex };
+        { dexlayout, "-i", "-v", "-w", tmp_dir, "-o", tmp_name, "-p", profile_file, output_dex };
     if (!::art::Exec(second_dexlayout_exec_argv, error_msg)) {
       return false;
     }
@@ -436,13 +504,11 @@
   bool DexLayoutExec(ScratchFile* dex_file,
                      const char* dex_filename,
                      ScratchFile* profile_file,
-                     const char* profile_filename,
                      std::vector<std::string>& dexlayout_exec_argv) {
     WriteBase64ToFile(dex_filename, dex_file->GetFile());
     EXPECT_EQ(dex_file->GetFile()->Flush(), 0);
     if (profile_file != nullptr) {
-      WriteBase64ToFile(profile_filename, profile_file->GetFile());
-      EXPECT_EQ(profile_file->GetFile()->Flush(), 0);
+      CreateProfile(dex_file->GetFilename(), profile_file->GetFilename(), dex_file->GetFilename());
     }
     std::string error_msg;
     const bool result = ::art::Exec(dexlayout_exec_argv, &error_msg);
@@ -516,7 +582,6 @@
   ASSERT_TRUE(DexLayoutExec(&temp_dex,
                             kDexFileDuplicateOffset,
                             nullptr /* profile_file */,
-                            nullptr /* profile_filename */,
                             dexlayout_exec_argv));
 }
 
@@ -529,7 +594,6 @@
   ASSERT_TRUE(DexLayoutExec(&temp_dex,
                             kNullSetRefListElementInputDex,
                             nullptr /* profile_file */,
-                            nullptr /* profile_filename */,
                             dexlayout_exec_argv));
 }
 
@@ -543,7 +607,6 @@
   ASSERT_TRUE(DexLayoutExec(&temp_dex,
                             kMultiClassDataInputDex,
                             &temp_profile,
-                            kDexFileLayoutInputProfile,
                             dexlayout_exec_argv));
 }
 
@@ -557,7 +620,6 @@
   ASSERT_TRUE(DexLayoutExec(&temp_dex,
                             kUnalignedCodeInfoInputDex,
                             &temp_profile,
-                            kDexFileLayoutInputProfile,
                             dexlayout_exec_argv));
 }
 
@@ -571,7 +633,6 @@
   ASSERT_TRUE(DexLayoutExec(&temp_dex,
                             kClassDataBeforeCodeInputDex,
                             &temp_profile,
-                            kDexFileLayoutInputProfile,
                             dexlayout_exec_argv));
 }
 
@@ -584,7 +645,6 @@
   ASSERT_TRUE(DexLayoutExec(&temp_dex,
                             kUnknownTypeDebugInfoInputDex,
                             nullptr /* profile_file */,
-                            nullptr /* profile_filename */,
                             dexlayout_exec_argv));
 }
 
@@ -597,7 +657,6 @@
   ASSERT_TRUE(DexLayoutExec(&temp_dex,
                             kDuplicateCodeItemInputDex,
                             nullptr /* profile_file */,
-                            nullptr /* profile_filename */,
                             dexlayout_exec_argv));
 }
 
diff --git a/profman/profman.cc b/profman/profman.cc
index 366b4de..e565171 100644
--- a/profman/profman.cc
+++ b/profman/profman.cc
@@ -39,10 +39,11 @@
 #include "bytecode_utils.h"
 #include "dex_file.h"
 #include "jit/profile_compilation_info.h"
+#include "profile_assistant.h"
 #include "runtime.h"
+#include "type_reference.h"
 #include "utils.h"
 #include "zip_archive.h"
-#include "profile_assistant.h"
 
 namespace art {
 
@@ -560,7 +561,7 @@
   // Return true if the definition of the class was found in any of the dex_files.
   bool FindClass(const std::vector<std::unique_ptr<const DexFile>>& dex_files,
                  const std::string& klass_descriptor,
-                 /*out*/ProfileMethodInfo::ProfileClassReference* class_ref) {
+                 /*out*/TypeReference* class_ref) {
     for (const std::unique_ptr<const DexFile>& dex_file_ptr : dex_files) {
       const DexFile* dex_file = dex_file_ptr.get();
       const DexFile::TypeId* type_id = dex_file->FindTypeId(klass_descriptor.c_str());
@@ -580,8 +581,7 @@
   }
 
   // Find the method specified by method_spec in the class class_ref.
-  uint32_t FindMethodIndex(const ProfileMethodInfo::ProfileClassReference& class_ref,
-                           const std::string& method_spec) {
+  uint32_t FindMethodIndex(const TypeReference& class_ref, const std::string& method_spec) {
     std::vector<std::string> name_and_signature;
     Split(method_spec, kProfileParsingFirstCharInSignature, &name_and_signature);
     if (name_and_signature.size() != 2) {
@@ -623,7 +623,7 @@
   // The format of the method spec is "inlinePolymorphic(LSuper;)I+LSubA;,LSubB;,LSubC;".
   //
   // TODO(calin): support INVOKE_INTERFACE and the range variants.
-  bool HasSingleInvoke(const ProfileMethodInfo::ProfileClassReference& class_ref,
+  bool HasSingleInvoke(const TypeReference& class_ref,
                        uint16_t method_index,
                        /*out*/uint32_t* dex_pc) {
     const DexFile* dex_file = class_ref.dex_file;
@@ -672,7 +672,7 @@
       method_str = line.substr(method_sep_index + kMethodSep.size());
     }
 
-    ProfileMethodInfo::ProfileClassReference class_ref;
+    TypeReference class_ref;
     if (!FindClass(dex_files, klass, &class_ref)) {
       LOG(WARNING) << "Could not find class: " << klass;
       return false;
@@ -743,7 +743,7 @@
       if (!HasSingleInvoke(class_ref, method_index, &dex_pc)) {
         return false;
       }
-      std::vector<ProfileMethodInfo::ProfileClassReference> classes(inline_cache_elems.size());
+      std::vector<TypeReference> classes(inline_cache_elems.size());
       size_t class_it = 0;
       for (const std::string& ic_class : inline_cache_elems) {
         if (!FindClass(dex_files, ic_class, &(classes[class_it++]))) {
diff --git a/runtime/arch/instruction_set_features.cc b/runtime/arch/instruction_set_features.cc
index 00d22c4..43c1711 100644
--- a/runtime/arch/instruction_set_features.cc
+++ b/runtime/arch/instruction_set_features.cc
@@ -33,33 +33,26 @@
 
 std::unique_ptr<const InstructionSetFeatures> InstructionSetFeatures::FromVariant(
     InstructionSet isa, const std::string& variant, std::string* error_msg) {
-  std::unique_ptr<const InstructionSetFeatures> result;
   switch (isa) {
     case kArm:
     case kThumb2:
-      result.reset(ArmInstructionSetFeatures::FromVariant(variant, error_msg).release());
-      break;
+      return ArmInstructionSetFeatures::FromVariant(variant, error_msg);
     case kArm64:
-      result.reset(Arm64InstructionSetFeatures::FromVariant(variant, error_msg).release());
-      break;
+      return Arm64InstructionSetFeatures::FromVariant(variant, error_msg);
     case kMips:
-      result.reset(MipsInstructionSetFeatures::FromVariant(variant, error_msg).release());
-      break;
+      return MipsInstructionSetFeatures::FromVariant(variant, error_msg);
     case kMips64:
-      result = Mips64InstructionSetFeatures::FromVariant(variant, error_msg);
-      break;
+      return Mips64InstructionSetFeatures::FromVariant(variant, error_msg);
     case kX86:
-      result.reset(X86InstructionSetFeatures::FromVariant(variant, error_msg).release());
-      break;
+      return X86InstructionSetFeatures::FromVariant(variant, error_msg);
     case kX86_64:
-      result.reset(X86_64InstructionSetFeatures::FromVariant(variant, error_msg).release());
+      return X86_64InstructionSetFeatures::FromVariant(variant, error_msg);
+
+    case kNone:
       break;
-    default:
-      UNIMPLEMENTED(FATAL) << isa;
-      UNREACHABLE();
   }
-  CHECK_EQ(result == nullptr, error_msg->size() != 0);
-  return result;
+  UNIMPLEMENTED(FATAL) << isa;
+  UNREACHABLE();
 }
 
 std::unique_ptr<const InstructionSetFeatures> InstructionSetFeatures::FromBitmap(InstructionSet isa,
@@ -68,23 +61,25 @@
   switch (isa) {
     case kArm:
     case kThumb2:
-      result.reset(ArmInstructionSetFeatures::FromBitmap(bitmap).release());
+      result = ArmInstructionSetFeatures::FromBitmap(bitmap);
       break;
     case kArm64:
-      result.reset(Arm64InstructionSetFeatures::FromBitmap(bitmap).release());
+      result = Arm64InstructionSetFeatures::FromBitmap(bitmap);
       break;
     case kMips:
-      result.reset(MipsInstructionSetFeatures::FromBitmap(bitmap).release());
+      result = MipsInstructionSetFeatures::FromBitmap(bitmap);
       break;
     case kMips64:
       result = Mips64InstructionSetFeatures::FromBitmap(bitmap);
       break;
     case kX86:
-      result.reset(X86InstructionSetFeatures::FromBitmap(bitmap).release());
+      result = X86InstructionSetFeatures::FromBitmap(bitmap);
       break;
     case kX86_64:
-      result.reset(X86_64InstructionSetFeatures::FromBitmap(bitmap).release());
+      result = X86_64InstructionSetFeatures::FromBitmap(bitmap);
       break;
+
+    case kNone:
     default:
       UNIMPLEMENTED(FATAL) << isa;
       UNREACHABLE();
@@ -94,120 +89,96 @@
 }
 
 std::unique_ptr<const InstructionSetFeatures> InstructionSetFeatures::FromCppDefines() {
-  std::unique_ptr<const InstructionSetFeatures> result;
   switch (kRuntimeISA) {
     case kArm:
     case kThumb2:
-      result.reset(ArmInstructionSetFeatures::FromCppDefines().release());
-      break;
+      return ArmInstructionSetFeatures::FromCppDefines();
     case kArm64:
-      result.reset(Arm64InstructionSetFeatures::FromCppDefines().release());
-      break;
+      return Arm64InstructionSetFeatures::FromCppDefines();
     case kMips:
-      result.reset(MipsInstructionSetFeatures::FromCppDefines().release());
-      break;
+      return MipsInstructionSetFeatures::FromCppDefines();
     case kMips64:
-      result = Mips64InstructionSetFeatures::FromCppDefines();
-      break;
+      return Mips64InstructionSetFeatures::FromCppDefines();
     case kX86:
-      result.reset(X86InstructionSetFeatures::FromCppDefines().release());
-      break;
+      return X86InstructionSetFeatures::FromCppDefines();
     case kX86_64:
-      result.reset(X86_64InstructionSetFeatures::FromCppDefines().release());
+      return X86_64InstructionSetFeatures::FromCppDefines();
+
+    case kNone:
       break;
-    default:
-      UNIMPLEMENTED(FATAL) << kRuntimeISA;
-      UNREACHABLE();
   }
-  return result;
+  UNIMPLEMENTED(FATAL) << kRuntimeISA;
+  UNREACHABLE();
 }
 
 
 std::unique_ptr<const InstructionSetFeatures> InstructionSetFeatures::FromCpuInfo() {
-  std::unique_ptr<const InstructionSetFeatures> result;
   switch (kRuntimeISA) {
     case kArm:
     case kThumb2:
-      result.reset(ArmInstructionSetFeatures::FromCpuInfo().release());
-      break;
+      return ArmInstructionSetFeatures::FromCpuInfo();
     case kArm64:
-      result.reset(Arm64InstructionSetFeatures::FromCpuInfo().release());
-      break;
+      return Arm64InstructionSetFeatures::FromCpuInfo();
     case kMips:
-      result.reset(MipsInstructionSetFeatures::FromCpuInfo().release());
-      break;
+      return MipsInstructionSetFeatures::FromCpuInfo();
     case kMips64:
-      result = Mips64InstructionSetFeatures::FromCpuInfo();
-      break;
+      return Mips64InstructionSetFeatures::FromCpuInfo();
     case kX86:
-      result.reset(X86InstructionSetFeatures::FromCpuInfo().release());
-      break;
+      return X86InstructionSetFeatures::FromCpuInfo();
     case kX86_64:
-      result.reset(X86_64InstructionSetFeatures::FromCpuInfo().release());
+      return X86_64InstructionSetFeatures::FromCpuInfo();
+
+    case kNone:
       break;
-    default:
-      UNIMPLEMENTED(FATAL) << kRuntimeISA;
-      UNREACHABLE();
   }
-  return result;
+  UNIMPLEMENTED(FATAL) << kRuntimeISA;
+  UNREACHABLE();
 }
 
 std::unique_ptr<const InstructionSetFeatures> InstructionSetFeatures::FromHwcap() {
-  std::unique_ptr<const InstructionSetFeatures> result;
   switch (kRuntimeISA) {
     case kArm:
     case kThumb2:
-      result.reset(ArmInstructionSetFeatures::FromHwcap().release());
-      break;
+      return ArmInstructionSetFeatures::FromHwcap();
     case kArm64:
-      result.reset(Arm64InstructionSetFeatures::FromHwcap().release());
-      break;
+      return Arm64InstructionSetFeatures::FromHwcap();
     case kMips:
-      result.reset(MipsInstructionSetFeatures::FromHwcap().release());
-      break;
+      return MipsInstructionSetFeatures::FromHwcap();
     case kMips64:
-      result = Mips64InstructionSetFeatures::FromHwcap();
-      break;
+      return Mips64InstructionSetFeatures::FromHwcap();
     case kX86:
-      result.reset(X86InstructionSetFeatures::FromHwcap().release());
-      break;
+      return X86InstructionSetFeatures::FromHwcap();
     case kX86_64:
-      result.reset(X86_64InstructionSetFeatures::FromHwcap().release());
+      return X86_64InstructionSetFeatures::FromHwcap();
+
+    case kNone:
       break;
-    default:
-      UNIMPLEMENTED(FATAL) << kRuntimeISA;
-      UNREACHABLE();
   }
-  return result;
+  UNIMPLEMENTED(FATAL) << kRuntimeISA;
+  UNREACHABLE();
 }
 
 std::unique_ptr<const InstructionSetFeatures> InstructionSetFeatures::FromAssembly() {
-  std::unique_ptr<const InstructionSetFeatures> result;
   switch (kRuntimeISA) {
     case kArm:
     case kThumb2:
-      result.reset(ArmInstructionSetFeatures::FromAssembly().release());
-      break;
+      return ArmInstructionSetFeatures::FromAssembly();
     case kArm64:
-      result.reset(Arm64InstructionSetFeatures::FromAssembly().release());
-      break;
+      return Arm64InstructionSetFeatures::FromAssembly();
     case kMips:
-      result.reset(MipsInstructionSetFeatures::FromAssembly().release());
-      break;
+      return MipsInstructionSetFeatures::FromAssembly();
     case kMips64:
-      result = Mips64InstructionSetFeatures::FromAssembly();
-      break;
+      return Mips64InstructionSetFeatures::FromAssembly();
     case kX86:
-      result.reset(X86InstructionSetFeatures::FromAssembly().release());
-      break;
+      return X86InstructionSetFeatures::FromAssembly();
     case kX86_64:
-      result.reset(X86_64InstructionSetFeatures::FromAssembly().release());
+      return X86_64InstructionSetFeatures::FromAssembly();
+
+    case kNone:
       break;
-    default:
-      UNIMPLEMENTED(FATAL) << kRuntimeISA;
-      UNREACHABLE();
   }
-  return result;
+  UNIMPLEMENTED(FATAL) << kRuntimeISA;
+  UNREACHABLE();
 }
 
 std::unique_ptr<const InstructionSetFeatures> InstructionSetFeatures::AddFeaturesFromString(
diff --git a/runtime/arch/memcmp16.cc b/runtime/arch/memcmp16.cc
index 813df2f..e714cfc 100644
--- a/runtime/arch/memcmp16.cc
+++ b/runtime/arch/memcmp16.cc
@@ -37,7 +37,7 @@
   return MemCmp16(s0, s1, count);
 }
 
-}
+}  // namespace testing
 
 }  // namespace art
 
diff --git a/runtime/arch/memcmp16.h b/runtime/arch/memcmp16.h
index c449a14..b051a1c 100644
--- a/runtime/arch/memcmp16.h
+++ b/runtime/arch/memcmp16.h
@@ -59,7 +59,7 @@
 // implementation.
 int32_t MemCmp16Testing(const uint16_t* s0, const uint16_t* s1, size_t count);
 
-}
+}  // namespace testing
 
 }  // namespace art
 
diff --git a/runtime/cha.cc b/runtime/cha.cc
index 7948c29..e6bdb84 100644
--- a/runtime/cha.cc
+++ b/runtime/cha.cc
@@ -31,34 +31,24 @@
 void ClassHierarchyAnalysis::AddDependency(ArtMethod* method,
                                            ArtMethod* dependent_method,
                                            OatQuickMethodHeader* dependent_header) {
-  auto it = cha_dependency_map_.find(method);
-  if (it == cha_dependency_map_.end()) {
-    cha_dependency_map_[method] =
-        new std::vector<std::pair<art::ArtMethod*, art::OatQuickMethodHeader*>>();
-    it = cha_dependency_map_.find(method);
-  } else {
-    DCHECK(it->second != nullptr);
-  }
-  it->second->push_back(std::make_pair(dependent_method, dependent_header));
+  const auto it = cha_dependency_map_.insert(
+      decltype(cha_dependency_map_)::value_type(method, ListOfDependentPairs())).first;
+  it->second.push_back({dependent_method, dependent_header});
 }
 
-std::vector<std::pair<ArtMethod*, OatQuickMethodHeader*>>*
-    ClassHierarchyAnalysis::GetDependents(ArtMethod* method) {
+static const ClassHierarchyAnalysis::ListOfDependentPairs s_empty_vector;
+
+const ClassHierarchyAnalysis::ListOfDependentPairs& ClassHierarchyAnalysis::GetDependents(
+    ArtMethod* method) {
   auto it = cha_dependency_map_.find(method);
   if (it != cha_dependency_map_.end()) {
-    DCHECK(it->second != nullptr);
     return it->second;
   }
-  return nullptr;
+  return s_empty_vector;
 }
 
-void ClassHierarchyAnalysis::RemoveDependencyFor(ArtMethod* method) {
-  auto it = cha_dependency_map_.find(method);
-  if (it != cha_dependency_map_.end()) {
-    auto dependents = it->second;
-    cha_dependency_map_.erase(it);
-    delete dependents;
-  }
+void ClassHierarchyAnalysis::RemoveAllDependenciesFor(ArtMethod* method) {
+  cha_dependency_map_.erase(method);
 }
 
 void ClassHierarchyAnalysis::RemoveDependentsWithMethodHeaders(
@@ -66,20 +56,19 @@
   // Iterate through all entries in the dependency map and remove any entry that
   // contains one of those in method_headers.
   for (auto map_it = cha_dependency_map_.begin(); map_it != cha_dependency_map_.end(); ) {
-    auto dependents = map_it->second;
-    for (auto vec_it = dependents->begin(); vec_it != dependents->end(); ) {
-      OatQuickMethodHeader* method_header = vec_it->second;
-      auto it = std::find(method_headers.begin(), method_headers.end(), method_header);
-      if (it != method_headers.end()) {
-        vec_it = dependents->erase(vec_it);
-      } else {
-        vec_it++;
-      }
-    }
+    ListOfDependentPairs& dependents = map_it->second;
+    dependents.erase(
+        std::remove_if(
+            dependents.begin(),
+            dependents.end(),
+            [&method_headers](MethodAndMethodHeaderPair& dependent) {
+              return method_headers.find(dependent.second) != method_headers.end();
+            }),
+        dependents.end());
+
     // Remove the map entry if there are no more dependents.
-    if (dependents->empty()) {
+    if (dependents.empty()) {
       map_it = cha_dependency_map_.erase(map_it);
-      delete dependents;
     } else {
       map_it++;
     }
@@ -554,11 +543,7 @@
         }
 
         // Invalidate all dependents.
-        auto dependents = GetDependents(invalidated);
-        if (dependents == nullptr) {
-          continue;
-        }
-        for (const auto& dependent : *dependents) {
+        for (const auto& dependent : GetDependents(invalidated)) {
           ArtMethod* method = dependent.first;;
           OatQuickMethodHeader* method_header = dependent.second;
           VLOG(class_linker) << "CHA invalidated compiled code for " << method->PrettyMethod();
@@ -567,7 +552,7 @@
               method, method_header);
           dependent_method_headers.insert(method_header);
         }
-        RemoveDependencyFor(invalidated);
+        RemoveAllDependenciesFor(invalidated);
       }
     }
 
diff --git a/runtime/cha.h b/runtime/cha.h
index 99c49d2..d9692a6 100644
--- a/runtime/cha.h
+++ b/runtime/cha.h
@@ -94,12 +94,11 @@
                      OatQuickMethodHeader* dependent_header) REQUIRES(Locks::cha_lock_);
 
   // Return compiled code that assumes that `method` has single-implementation.
-  std::vector<MethodAndMethodHeaderPair>* GetDependents(ArtMethod* method)
-      REQUIRES(Locks::cha_lock_);
+  const ListOfDependentPairs& GetDependents(ArtMethod* method) REQUIRES(Locks::cha_lock_);
 
   // Remove dependency tracking for compiled code that assumes that
   // `method` has single-implementation.
-  void RemoveDependencyFor(ArtMethod* method) REQUIRES(Locks::cha_lock_);
+  void RemoveAllDependenciesFor(ArtMethod* method) REQUIRES(Locks::cha_lock_);
 
   // Remove from cha_dependency_map_ all entries that contain OatQuickMethodHeader from
   // the given `method_headers` set.
@@ -158,7 +157,7 @@
 
   // A map that maps a method to a set of compiled code that assumes that method has a
   // single implementation, which is used to do CHA-based devirtualization.
-  std::unordered_map<ArtMethod*, ListOfDependentPairs*> cha_dependency_map_
+  std::unordered_map<ArtMethod*, ListOfDependentPairs> cha_dependency_map_
     GUARDED_BY(Locks::cha_lock_);
 
   DISALLOW_COPY_AND_ASSIGN(ClassHierarchyAnalysis);
diff --git a/runtime/cha_test.cc b/runtime/cha_test.cc
index d2f335e..c60720f 100644
--- a/runtime/cha_test.cc
+++ b/runtime/cha_test.cc
@@ -36,58 +36,58 @@
   ClassHierarchyAnalysis cha;
   MutexLock cha_mu(Thread::Current(), *Locks::cha_lock_);
 
-  ASSERT_EQ(cha.GetDependents(METHOD1), nullptr);
-  ASSERT_EQ(cha.GetDependents(METHOD2), nullptr);
-  ASSERT_EQ(cha.GetDependents(METHOD3), nullptr);
+  ASSERT_TRUE(cha.GetDependents(METHOD1).empty());
+  ASSERT_TRUE(cha.GetDependents(METHOD2).empty());
+  ASSERT_TRUE(cha.GetDependents(METHOD3).empty());
 
   cha.AddDependency(METHOD1, METHOD2, METHOD_HEADER2);
-  ASSERT_EQ(cha.GetDependents(METHOD2), nullptr);
-  ASSERT_EQ(cha.GetDependents(METHOD3), nullptr);
+  ASSERT_TRUE(cha.GetDependents(METHOD2).empty());
+  ASSERT_TRUE(cha.GetDependents(METHOD3).empty());
   auto dependents = cha.GetDependents(METHOD1);
-  ASSERT_EQ(dependents->size(), 1u);
-  ASSERT_EQ(dependents->at(0).first, METHOD2);
-  ASSERT_EQ(dependents->at(0).second, METHOD_HEADER2);
+  ASSERT_EQ(dependents.size(), 1u);
+  ASSERT_EQ(dependents[0].first, METHOD2);
+  ASSERT_EQ(dependents[0].second, METHOD_HEADER2);
 
   cha.AddDependency(METHOD1, METHOD3, METHOD_HEADER3);
-  ASSERT_EQ(cha.GetDependents(METHOD2), nullptr);
-  ASSERT_EQ(cha.GetDependents(METHOD3), nullptr);
+  ASSERT_TRUE(cha.GetDependents(METHOD2).empty());
+  ASSERT_TRUE(cha.GetDependents(METHOD3).empty());
   dependents = cha.GetDependents(METHOD1);
-  ASSERT_EQ(dependents->size(), 2u);
-  ASSERT_EQ(dependents->at(0).first, METHOD2);
-  ASSERT_EQ(dependents->at(0).second, METHOD_HEADER2);
-  ASSERT_EQ(dependents->at(1).first, METHOD3);
-  ASSERT_EQ(dependents->at(1).second, METHOD_HEADER3);
+  ASSERT_EQ(dependents.size(), 2u);
+  ASSERT_EQ(dependents[0].first, METHOD2);
+  ASSERT_EQ(dependents[0].second, METHOD_HEADER2);
+  ASSERT_EQ(dependents[1].first, METHOD3);
+  ASSERT_EQ(dependents[1].second, METHOD_HEADER3);
 
   std::unordered_set<OatQuickMethodHeader*> headers;
   headers.insert(METHOD_HEADER2);
   cha.RemoveDependentsWithMethodHeaders(headers);
-  ASSERT_EQ(cha.GetDependents(METHOD2), nullptr);
-  ASSERT_EQ(cha.GetDependents(METHOD3), nullptr);
+  ASSERT_TRUE(cha.GetDependents(METHOD2).empty());
+  ASSERT_TRUE(cha.GetDependents(METHOD3).empty());
   dependents = cha.GetDependents(METHOD1);
-  ASSERT_EQ(dependents->size(), 1u);
-  ASSERT_EQ(dependents->at(0).first, METHOD3);
-  ASSERT_EQ(dependents->at(0).second, METHOD_HEADER3);
+  ASSERT_EQ(dependents.size(), 1u);
+  ASSERT_EQ(dependents[0].first, METHOD3);
+  ASSERT_EQ(dependents[0].second, METHOD_HEADER3);
 
   cha.AddDependency(METHOD2, METHOD1, METHOD_HEADER1);
-  ASSERT_EQ(cha.GetDependents(METHOD3), nullptr);
+  ASSERT_TRUE(cha.GetDependents(METHOD3).empty());
   dependents = cha.GetDependents(METHOD1);
-  ASSERT_EQ(dependents->size(), 1u);
+  ASSERT_EQ(dependents.size(), 1u);
   dependents = cha.GetDependents(METHOD2);
-  ASSERT_EQ(dependents->size(), 1u);
+  ASSERT_EQ(dependents.size(), 1u);
 
   headers.insert(METHOD_HEADER3);
   cha.RemoveDependentsWithMethodHeaders(headers);
-  ASSERT_EQ(cha.GetDependents(METHOD1), nullptr);
-  ASSERT_EQ(cha.GetDependents(METHOD3), nullptr);
+  ASSERT_TRUE(cha.GetDependents(METHOD1).empty());
+  ASSERT_TRUE(cha.GetDependents(METHOD3).empty());
   dependents = cha.GetDependents(METHOD2);
-  ASSERT_EQ(dependents->size(), 1u);
-  ASSERT_EQ(dependents->at(0).first, METHOD1);
-  ASSERT_EQ(dependents->at(0).second, METHOD_HEADER1);
+  ASSERT_EQ(dependents.size(), 1u);
+  ASSERT_EQ(dependents[0].first, METHOD1);
+  ASSERT_EQ(dependents[0].second, METHOD_HEADER1);
 
-  cha.RemoveDependencyFor(METHOD2);
-  ASSERT_EQ(cha.GetDependents(METHOD1), nullptr);
-  ASSERT_EQ(cha.GetDependents(METHOD2), nullptr);
-  ASSERT_EQ(cha.GetDependents(METHOD3), nullptr);
+  cha.RemoveAllDependenciesFor(METHOD2);
+  ASSERT_TRUE(cha.GetDependents(METHOD1).empty());
+  ASSERT_TRUE(cha.GetDependents(METHOD2).empty());
+  ASSERT_TRUE(cha.GetDependents(METHOD3).empty());
 }
 
 }  // namespace art
diff --git a/runtime/class_linker.cc b/runtime/class_linker.cc
index 52bd86b..81ca764 100644
--- a/runtime/class_linker.cc
+++ b/runtime/class_linker.cc
@@ -354,7 +354,8 @@
 }
 
 ClassLinker::ClassLinker(InternTable* intern_table)
-    : failed_dex_cache_class_lookups_(0),
+    : boot_class_table_(new ClassTable()),
+      failed_dex_cache_class_lookups_(0),
       class_roots_(nullptr),
       array_iftable_(nullptr),
       find_array_class_cache_next_victim_(0),
@@ -1281,15 +1282,36 @@
   }
 }
 
-bool ClassLinker::UpdateAppImageClassLoadersAndDexCaches(
+// new_class_set is the set of classes that were read from the class table section in the image.
+// If there was no class table section, it is null.
+// Note: using a class here to avoid having to make ClassLinker internals public.
+class AppImageClassLoadersAndDexCachesHelper {
+ public:
+  static bool Update(
+      ClassLinker* class_linker,
+      gc::space::ImageSpace* space,
+      Handle<mirror::ClassLoader> class_loader,
+      Handle<mirror::ObjectArray<mirror::DexCache>> dex_caches,
+      ClassTable::ClassSet* new_class_set,
+      bool* out_forward_dex_cache_array,
+      std::string* out_error_msg)
+      REQUIRES(!Locks::dex_lock_)
+      REQUIRES_SHARED(Locks::mutator_lock_);
+};
+
+bool AppImageClassLoadersAndDexCachesHelper::Update(
+    ClassLinker* class_linker,
     gc::space::ImageSpace* space,
     Handle<mirror::ClassLoader> class_loader,
     Handle<mirror::ObjectArray<mirror::DexCache>> dex_caches,
     ClassTable::ClassSet* new_class_set,
     bool* out_forward_dex_cache_array,
-    std::string* out_error_msg) {
+    std::string* out_error_msg)
+    REQUIRES(!Locks::dex_lock_)
+    REQUIRES_SHARED(Locks::mutator_lock_) {
   DCHECK(out_forward_dex_cache_array != nullptr);
   DCHECK(out_error_msg != nullptr);
+  PointerSize image_pointer_size = class_linker->GetImagePointerSize();
   Thread* const self = Thread::Current();
   gc::Heap* const heap = Runtime::Current()->GetHeap();
   const ImageHeader& header = space->GetImageHeader();
@@ -1355,7 +1377,7 @@
         CHECK_EQ(num_fields, dex_cache->NumResolvedFields());
         CHECK_EQ(num_method_types, dex_cache->NumResolvedMethodTypes());
         CHECK_EQ(num_call_sites, dex_cache->NumResolvedCallSites());
-        DexCacheArraysLayout layout(image_pointer_size_, dex_file);
+        DexCacheArraysLayout layout(image_pointer_size, dex_file);
         uint8_t* const raw_arrays = oat_dex_file->GetDexCacheArrays();
         if (num_strings != 0u) {
           mirror::StringDexCacheType* const image_resolved_strings = dex_cache->GetStrings();
@@ -1391,17 +1413,17 @@
           mirror::FieldDexCacheType* const fields =
               reinterpret_cast<mirror::FieldDexCacheType*>(raw_arrays + layout.FieldsOffset());
           for (size_t j = 0; j < num_fields; ++j) {
-            DCHECK_EQ(mirror::DexCache::GetNativePairPtrSize(fields, j, image_pointer_size_).index,
+            DCHECK_EQ(mirror::DexCache::GetNativePairPtrSize(fields, j, image_pointer_size).index,
                       0u);
-            DCHECK(mirror::DexCache::GetNativePairPtrSize(fields, j, image_pointer_size_).object ==
+            DCHECK(mirror::DexCache::GetNativePairPtrSize(fields, j, image_pointer_size).object ==
                    nullptr);
             mirror::DexCache::SetNativePairPtrSize(
                 fields,
                 j,
                 mirror::DexCache::GetNativePairPtrSize(image_resolved_fields,
                                                        j,
-                                                       image_pointer_size_),
-                image_pointer_size_);
+                                                       image_pointer_size),
+                image_pointer_size);
           }
           dex_cache->SetResolvedFields(fields);
         }
@@ -1439,8 +1461,8 @@
         // Make sure to do this after we update the arrays since we store the resolved types array
         // in DexCacheData in RegisterDexFileLocked. We need the array pointer to be the one in the
         // BSS.
-        CHECK(!FindDexCacheDataLocked(*dex_file).IsValid());
-        RegisterDexFileLocked(*dex_file, dex_cache, class_loader.Get());
+        CHECK(!class_linker->FindDexCacheDataLocked(*dex_file).IsValid());
+        class_linker->RegisterDexFileLocked(*dex_file, dex_cache, class_loader.Get());
       }
       if (kIsDebugBuild) {
         CHECK(new_class_set != nullptr);
@@ -1462,20 +1484,20 @@
             }
             for (ArtMethod& m : klass->GetDirectMethods(kRuntimePointerSize)) {
               const void* code = m.GetEntryPointFromQuickCompiledCode();
-              const void* oat_code = m.IsInvokable() ? GetQuickOatCodeFor(&m) : code;
-              if (!IsQuickResolutionStub(code) &&
-                  !IsQuickGenericJniStub(code) &&
-                  !IsQuickToInterpreterBridge(code) &&
+              const void* oat_code = m.IsInvokable() ? class_linker->GetQuickOatCodeFor(&m) : code;
+              if (!class_linker->IsQuickResolutionStub(code) &&
+                  !class_linker->IsQuickGenericJniStub(code) &&
+                  !class_linker->IsQuickToInterpreterBridge(code) &&
                   !m.IsNative()) {
                 DCHECK_EQ(code, oat_code) << m.PrettyMethod();
               }
             }
             for (ArtMethod& m : klass->GetVirtualMethods(kRuntimePointerSize)) {
               const void* code = m.GetEntryPointFromQuickCompiledCode();
-              const void* oat_code = m.IsInvokable() ? GetQuickOatCodeFor(&m) : code;
-              if (!IsQuickResolutionStub(code) &&
-                  !IsQuickGenericJniStub(code) &&
-                  !IsQuickToInterpreterBridge(code) &&
+              const void* oat_code = m.IsInvokable() ? class_linker->GetQuickOatCodeFor(&m) : code;
+              if (!class_linker->IsQuickResolutionStub(code) &&
+                  !class_linker->IsQuickGenericJniStub(code) &&
+                  !class_linker->IsQuickToInterpreterBridge(code) &&
                   !m.IsNative()) {
                 DCHECK_EQ(code, oat_code) << m.PrettyMethod();
               }
@@ -1950,12 +1972,13 @@
   }
   if (app_image) {
     bool forward_dex_cache_arrays = false;
-    if (!UpdateAppImageClassLoadersAndDexCaches(space,
-                                                class_loader,
-                                                dex_caches,
-                                                &temp_set,
-                                                /*out*/&forward_dex_cache_arrays,
-                                                /*out*/error_msg)) {
+    if (!AppImageClassLoadersAndDexCachesHelper::Update(this,
+                                                        space,
+                                                        class_loader,
+                                                        dex_caches,
+                                                        &temp_set,
+                                                        /*out*/&forward_dex_cache_arrays,
+                                                        /*out*/error_msg)) {
       return false;
     }
     // Update class loader and resolved strings. If added_class_table is false, the resolved
@@ -2054,7 +2077,7 @@
     // ClassTable::TableSlot. The buffered root visiting would access a stale stack location for
     // these objects.
     UnbufferedRootVisitor root_visitor(visitor, RootInfo(kRootStickyClass));
-    boot_class_table_.VisitRoots(root_visitor);
+    boot_class_table_->VisitRoots(root_visitor);
     // If tracing is enabled, then mark all the class loaders to prevent unloading.
     if ((flags & kVisitRootFlagClassLoader) != 0 || tracing_enabled) {
       for (const ClassLoaderData& data : class_loaders_) {
@@ -2153,7 +2176,7 @@
 };
 
 void ClassLinker::VisitClassesInternal(ClassVisitor* visitor) {
-  if (boot_class_table_.Visit(*visitor)) {
+  if (boot_class_table_->Visit(*visitor)) {
     VisitClassLoaderClassesVisitor loader_visitor(visitor);
     VisitClassLoaders(&loader_visitor);
   }
@@ -3956,7 +3979,7 @@
 
 void ClassLinker::MoveClassTableToPreZygote() {
   WriterMutexLock mu(Thread::Current(), *Locks::classlinker_classes_lock_);
-  boot_class_table_.FreezeSnapshot();
+  boot_class_table_->FreezeSnapshot();
   MoveClassTableToPreZygoteVisitor visitor;
   VisitClassLoaders(&visitor);
 }
@@ -3993,7 +4016,7 @@
   Thread* const self = Thread::Current();
   ReaderMutexLock mu(self, *Locks::classlinker_classes_lock_);
   const size_t hash = ComputeModifiedUtf8Hash(descriptor);
-  ObjPtr<mirror::Class> klass = boot_class_table_.Lookup(descriptor, hash);
+  ObjPtr<mirror::Class> klass = boot_class_table_->Lookup(descriptor, hash);
   if (klass != nullptr) {
     DCHECK(klass->GetClassLoader() == nullptr);
     result.push_back(klass);
@@ -5277,7 +5300,7 @@
 
 ClassTable* ClassLinker::InsertClassTableForClassLoader(ObjPtr<mirror::ClassLoader> class_loader) {
   if (class_loader == nullptr) {
-    return &boot_class_table_;
+    return boot_class_table_.get();
   }
   ClassTable* class_table = class_loader->GetClassTable();
   if (class_table == nullptr) {
@@ -5289,7 +5312,7 @@
 }
 
 ClassTable* ClassLinker::ClassTableForClassLoader(ObjPtr<mirror::ClassLoader> class_loader) {
-  return class_loader == nullptr ? &boot_class_table_ : class_loader->GetClassTable();
+  return class_loader == nullptr ? boot_class_table_.get() : class_loader->GetClassTable();
 }
 
 static ImTable* FindSuperImt(ObjPtr<mirror::Class> klass, PointerSize pointer_size)
@@ -8646,13 +8669,13 @@
 size_t ClassLinker::NumZygoteClasses() const {
   CountClassesVisitor visitor;
   VisitClassLoaders(&visitor);
-  return visitor.num_zygote_classes + boot_class_table_.NumZygoteClasses(nullptr);
+  return visitor.num_zygote_classes + boot_class_table_->NumZygoteClasses(nullptr);
 }
 
 size_t ClassLinker::NumNonZygoteClasses() const {
   CountClassesVisitor visitor;
   VisitClassLoaders(&visitor);
-  return visitor.num_non_zygote_classes + boot_class_table_.NumNonZygoteClasses(nullptr);
+  return visitor.num_non_zygote_classes + boot_class_table_->NumNonZygoteClasses(nullptr);
 }
 
 size_t ClassLinker::NumLoadedClasses() {
diff --git a/runtime/class_linker.h b/runtime/class_linker.h
index 7f652ec..205ea1e 100644
--- a/runtime/class_linker.h
+++ b/runtime/class_linker.h
@@ -27,7 +27,6 @@
 #include "base/enums.h"
 #include "base/macros.h"
 #include "base/mutex.h"
-#include "class_table.h"
 #include "dex_cache_resolved_classes.h"
 #include "dex_file.h"
 #include "dex_file_types.h"
@@ -35,7 +34,6 @@
 #include "handle.h"
 #include "jni.h"
 #include "mirror/class.h"
-#include "object_callbacks.h"
 #include "verifier/verifier_enums.h"
 
 namespace art {
@@ -59,11 +57,13 @@
   class StackTraceElement;
 }  // namespace mirror
 
+class ClassTable;
 template<class T> class Handle;
 class ImtConflictTable;
 template<typename T> class LengthPrefixedArray;
 template<class T> class MutableHandle;
 class InternTable;
+class LinearAlloc;
 class OatFile;
 template<class T> class ObjectLock;
 class Runtime;
@@ -640,8 +640,11 @@
       REQUIRES_SHARED(Locks::mutator_lock_);
 
   // Returns null if not found.
+  // This returns a pointer to the class-table, without requiring any locking - including the
+  // boot class-table. It is the caller's responsibility to access this under lock, if required.
   ClassTable* ClassTableForClassLoader(ObjPtr<mirror::ClassLoader> class_loader)
-      REQUIRES_SHARED(Locks::mutator_lock_);
+      REQUIRES_SHARED(Locks::mutator_lock_)
+      NO_THREAD_SAFETY_ANALYSIS;
 
   void AppendToBootClassPath(Thread* self, const DexFile& dex_file)
       REQUIRES_SHARED(Locks::mutator_lock_)
@@ -1110,18 +1113,6 @@
       REQUIRES_SHARED(Locks::mutator_lock_)
       REQUIRES(!Locks::classlinker_classes_lock_);
 
-  // new_class_set is the set of classes that were read from the class table section in the image.
-  // If there was no class table section, it is null.
-  bool UpdateAppImageClassLoadersAndDexCaches(
-      gc::space::ImageSpace* space,
-      Handle<mirror::ClassLoader> class_loader,
-      Handle<mirror::ObjectArray<mirror::DexCache>> dex_caches,
-      ClassTable::ClassSet* new_class_set,
-      bool* out_forward_dex_cache_array,
-      std::string* out_error_msg)
-      REQUIRES(!Locks::dex_lock_)
-      REQUIRES_SHARED(Locks::mutator_lock_);
-
   // Check that c1 == FindSystemClass(self, descriptor). Abort with class dumps otherwise.
   void CheckSystemClass(Thread* self, Handle<mirror::Class> c1, const char* descriptor)
       REQUIRES(!Locks::dex_lock_)
@@ -1171,7 +1162,7 @@
       GUARDED_BY(Locks::classlinker_classes_lock_);
 
   // Boot class path table. Since the class loader for this is null.
-  ClassTable boot_class_table_ GUARDED_BY(Locks::classlinker_classes_lock_);
+  std::unique_ptr<ClassTable> boot_class_table_ GUARDED_BY(Locks::classlinker_classes_lock_);
 
   // New class roots, only used by CMS since the GC needs to mark these in the pause.
   std::vector<GcRoot<mirror::Class>> new_class_roots_ GUARDED_BY(Locks::classlinker_classes_lock_);
@@ -1212,12 +1203,14 @@
   PointerSize image_pointer_size_;
 
   class FindVirtualMethodHolderVisitor;
+
+  friend class AppImageClassLoadersAndDexCachesHelper;
   friend struct CompilationHelper;  // For Compile in ImageTest.
   friend class ImageDumper;  // for DexLock
   friend class ImageWriter;  // for GetClassRoots
-  friend class VMClassLoader;  // for LookupClass and FindClassInBaseDexClassLoader.
   friend class JniCompilerTest;  // for GetRuntimeQuickGenericJniStub
   friend class JniInternalTest;  // for GetRuntimeQuickGenericJniStub
+  friend class VMClassLoader;  // for LookupClass and FindClassInBaseDexClassLoader.
   ART_FRIEND_TEST(ClassLinkerTest, RegisterDexFileName);  // for DexLock, and RegisterDexFileLocked
   ART_FRIEND_TEST(mirror::DexCacheMethodHandlesTest, Open);  // for AllocDexCache
   ART_FRIEND_TEST(mirror::DexCacheTest, Open);  // for AllocDexCache
diff --git a/runtime/class_table.h b/runtime/class_table.h
index 430edbb..8616dfb 100644
--- a/runtime/class_table.h
+++ b/runtime/class_table.h
@@ -25,18 +25,17 @@
 #include "base/hash_set.h"
 #include "base/macros.h"
 #include "base/mutex.h"
-#include "dex_file.h"
 #include "gc_root.h"
 #include "obj_ptr.h"
-#include "object_callbacks.h"
-#include "runtime.h"
 
 namespace art {
 
 class OatFile;
 
 namespace mirror {
+  class Class;
   class ClassLoader;
+  class Object;
 }  // namespace mirror
 
 // Each loader has a ClassTable
diff --git a/runtime/common_dex_operations.h b/runtime/common_dex_operations.h
index 6693eef..133ddb0 100644
--- a/runtime/common_dex_operations.h
+++ b/runtime/common_dex_operations.h
@@ -36,8 +36,8 @@
 
   void ArtInterpreterToCompiledCodeBridge(Thread* self,
                                           ArtMethod* caller,
-                                          const DexFile::CodeItem* code_item,
                                           ShadowFrame* shadow_frame,
+                                          uint16_t arg_offset,
                                           JValue* result);
 }  // namespace interpreter
 
@@ -46,17 +46,15 @@
                         ArtMethod* caller_method,
                         const size_t first_dest_reg,
                         ShadowFrame* callee_frame,
-                        JValue* result)
+                        JValue* result,
+                        bool use_interpreter_entrypoint)
     REQUIRES_SHARED(Locks::mutator_lock_) {
   if (LIKELY(Runtime::Current()->IsStarted())) {
-    ArtMethod* target = callee_frame->GetMethod();
-    if (ClassLinker::ShouldUseInterpreterEntrypoint(
-        target,
-        target->GetEntryPointFromQuickCompiledCode())) {
+    if (use_interpreter_entrypoint) {
       interpreter::ArtInterpreterToInterpreterBridge(self, code_item, callee_frame, result);
     } else {
       interpreter::ArtInterpreterToCompiledCodeBridge(
-          self, caller_method, code_item, callee_frame, result);
+          self, caller_method, callee_frame, first_dest_reg, result);
     }
   } else {
     interpreter::UnstartedRuntime::Invoke(self, code_item, callee_frame, result, first_dest_reg);
diff --git a/runtime/common_runtime_test.h b/runtime/common_runtime_test.h
index a29cc6c..24dbd05 100644
--- a/runtime/common_runtime_test.h
+++ b/runtime/common_runtime_test.h
@@ -98,9 +98,12 @@
   // Returns bin directory which contains host's prebuild tools.
   static std::string GetAndroidHostToolsDir();
 
-  // Returns bin directory wahich contains target's prebuild tools.
+  // Returns bin directory which contains target's prebuild tools.
   static std::string GetAndroidTargetToolsDir(InstructionSet isa);
 
+  // Retuerns the filename for a test dex (i.e. XandY or ManyMethods).
+  std::string GetTestDexFileName(const char* name) const;
+
  protected:
   // Allow subclases such as CommonCompilerTest to add extra options.
   virtual void SetUpRuntimeOptions(RuntimeOptions* options ATTRIBUTE_UNUSED) {}
@@ -127,8 +130,6 @@
 
   std::string GetTestAndroidRoot();
 
-  std::string GetTestDexFileName(const char* name) const;
-
   std::vector<std::unique_ptr<const DexFile>> OpenTestDexFiles(const char* name);
 
   std::unique_ptr<const DexFile> OpenTestDexFile(const char* name)
diff --git a/runtime/dex_file.cc b/runtime/dex_file.cc
index 3d68af1..aace8eb 100644
--- a/runtime/dex_file.cc
+++ b/runtime/dex_file.cc
@@ -204,7 +204,7 @@
                                                  verify_checksum,
                                                  error_msg);
   if (dex_file != nullptr) {
-    dex_file->mem_map_.reset(map.release());
+    dex_file->mem_map_ = std::move(map);
   }
   return dex_file;
 }
@@ -323,7 +323,7 @@
                                                  verify_checksum,
                                                  error_msg);
   if (dex_file != nullptr) {
-    dex_file->mem_map_.reset(map.release());
+    dex_file->mem_map_ = std::move(map);
   }
 
   return dex_file;
@@ -397,7 +397,7 @@
     }
     return nullptr;
   }
-  dex_file->mem_map_.reset(map.release());
+  dex_file->mem_map_ = std::move(map);
   if (!dex_file->DisableWrite()) {
     *error_msg = StringPrintf("Failed to make dex file '%s' read only", location.c_str());
     *error_code = ZipOpenErrorCode::kMakeReadOnlyError;
diff --git a/runtime/entrypoints/quick/quick_default_init_entrypoints.h b/runtime/entrypoints/quick/quick_default_init_entrypoints.h
index 6481b97..267f384 100644
--- a/runtime/entrypoints/quick/quick_default_init_entrypoints.h
+++ b/runtime/entrypoints/quick/quick_default_init_entrypoints.h
@@ -26,7 +26,7 @@
 
 namespace art {
 
-void DefaultInitEntryPoints(JniEntryPoints* jpoints, QuickEntryPoints* qpoints) {
+static void DefaultInitEntryPoints(JniEntryPoints* jpoints, QuickEntryPoints* qpoints) {
   // JNI
   jpoints->pDlsymLookup = art_jni_dlsym_lookup_stub;
 
diff --git a/runtime/gc/allocation_listener.h b/runtime/gc/allocation_listener.h
index f60bc0c..d694a68 100644
--- a/runtime/gc/allocation_listener.h
+++ b/runtime/gc/allocation_listener.h
@@ -30,7 +30,7 @@
 
 namespace mirror {
   class Object;
-}
+}  // namespace mirror
 
 class Thread;
 
diff --git a/runtime/gc/allocation_record.h b/runtime/gc/allocation_record.h
index 90cff6a..227c7ad 100644
--- a/runtime/gc/allocation_record.h
+++ b/runtime/gc/allocation_record.h
@@ -33,7 +33,7 @@
 namespace mirror {
   class Class;
   class Object;
-}
+}  // namespace mirror
 
 namespace gc {
 
diff --git a/runtime/gc/space/image_space.cc b/runtime/gc/space/image_space.cc
index 748d378..b6bff5b 100644
--- a/runtime/gc/space/image_space.cc
+++ b/runtime/gc/space/image_space.cc
@@ -42,6 +42,7 @@
 #include "mirror/object-refvisitor-inl.h"
 #include "oat_file.h"
 #include "os.h"
+#include "runtime.h"
 #include "space-inl.h"
 #include "utils.h"
 
diff --git a/runtime/gc/space/image_space.h b/runtime/gc/space/image_space.h
index aa3dd42..a4065bf 100644
--- a/runtime/gc/space/image_space.h
+++ b/runtime/gc/space/image_space.h
@@ -19,7 +19,6 @@
 
 #include "arch/instruction_set.h"
 #include "gc/accounting/space_bitmap.h"
-#include "runtime.h"
 #include "space.h"
 
 namespace art {
diff --git a/runtime/handle_scope.h b/runtime/handle_scope.h
index c43a482..f248a11 100644
--- a/runtime/handle_scope.h
+++ b/runtime/handle_scope.h
@@ -36,7 +36,7 @@
 
 namespace mirror {
 class Object;
-}
+}  // namespace mirror
 
 // Basic handle scope, tracked by a list. May be variable sized.
 class PACKED(4) BaseHandleScope {
diff --git a/runtime/interpreter/interpreter.cc b/runtime/interpreter/interpreter.cc
index bf49e84..d2f5232 100644
--- a/runtime/interpreter/interpreter.cc
+++ b/runtime/interpreter/interpreter.cc
@@ -264,7 +264,11 @@
 
           // Pop the shadow frame before calling into compiled code.
           self->PopShadowFrame();
-          ArtInterpreterToCompiledCodeBridge(self, nullptr, code_item, &shadow_frame, &result);
+          // Calculate the offset of the first input reg. The input registers are in the high regs.
+          // It's ok to access the code item here since JIT code will have been touched by the
+          // interpreter and compiler already.
+          uint16_t arg_offset = code_item->registers_size_ - code_item->ins_size_;
+          ArtInterpreterToCompiledCodeBridge(self, nullptr, &shadow_frame, arg_offset, &result);
           // Push the shadow frame back as the caller will expect it.
           self->PushShadowFrame(&shadow_frame);
 
diff --git a/runtime/interpreter/interpreter_common.cc b/runtime/interpreter/interpreter_common.cc
index ef0ddb3..084cb42 100644
--- a/runtime/interpreter/interpreter_common.cc
+++ b/runtime/interpreter/interpreter_common.cc
@@ -458,8 +458,8 @@
 
 void ArtInterpreterToCompiledCodeBridge(Thread* self,
                                         ArtMethod* caller,
-                                        const DexFile::CodeItem* code_item,
                                         ShadowFrame* shadow_frame,
+                                        uint16_t arg_offset,
                                         JValue* result)
     REQUIRES_SHARED(Locks::mutator_lock_) {
   ArtMethod* method = shadow_frame->GetMethod();
@@ -482,9 +482,17 @@
       method = shadow_frame->GetMethod();
     }
   }
-  uint16_t arg_offset = (code_item == nullptr)
-                            ? 0
-                            : code_item->registers_size_ - code_item->ins_size_;
+  // Basic checks for the arg_offset. If there's no code item, the arg_offset must be 0. Otherwise,
+  // check that the arg_offset isn't greater than the number of registers. A stronger check is
+  // difficult since the frame may contain space for all the registers in the method, or only enough
+  // space for the arguments.
+  if (kIsDebugBuild) {
+    if (method->GetCodeItem() == nullptr) {
+      DCHECK_EQ(0u, arg_offset) << method->PrettyMethod();
+    } else {
+      DCHECK_LE(arg_offset, shadow_frame->NumberOfVRegs());
+    }
+  }
   jit::Jit* jit = Runtime::Current()->GetJit();
   if (jit != nullptr && caller != nullptr) {
     jit->NotifyInterpreterToCompiledCodeTransition(self, caller);
@@ -918,12 +926,23 @@
 
   // Compute method information.
   const DexFile::CodeItem* code_item = called_method->GetCodeItem();
-
   // Number of registers for the callee's call frame.
   uint16_t num_regs;
+  // Test whether to use the interpreter or compiler entrypoint, and save that result to pass to
+  // PerformCall. A deoptimization could occur at any time, and we shouldn't change which
+  // entrypoint to use once we start building the shadow frame.
+  bool use_interpreter_entrypoint = ClassLinker::ShouldUseInterpreterEntrypoint(
+      called_method, called_method->GetEntryPointFromQuickCompiledCode());
   if (LIKELY(code_item != nullptr)) {
-    num_regs = code_item->registers_size_;
-    DCHECK_EQ(string_init ? number_of_inputs - 1 : number_of_inputs, code_item->ins_size_);
+    // When transitioning to compiled code, space only needs to be reserved for the input registers.
+    // The rest of the frame gets discarded. This also prevents accessing the called method's code
+    // item, saving memory by keeping code items of compiled code untouched.
+    if (Runtime::Current()->IsStarted() && !use_interpreter_entrypoint) {
+      num_regs = number_of_inputs;
+    } else {
+      num_regs = code_item->registers_size_;
+      DCHECK_EQ(string_init ? number_of_inputs - 1 : number_of_inputs, code_item->ins_size_);
+    }
   } else {
     DCHECK(called_method->IsNative() || called_method->IsProxyMethod());
     num_regs = number_of_inputs;
@@ -1077,7 +1096,13 @@
     self->EndAssertNoThreadSuspension(old_cause);
   }
 
-  PerformCall(self, code_item, shadow_frame.GetMethod(), first_dest_reg, new_shadow_frame, result);
+  PerformCall(self,
+              code_item,
+              shadow_frame.GetMethod(),
+              first_dest_reg,
+              new_shadow_frame,
+              result,
+              use_interpreter_entrypoint);
 
   if (string_init && !self->IsExceptionPending()) {
     SetStringInitValueToAllAliases(&shadow_frame, string_init_vreg_this, *result);
diff --git a/runtime/interpreter/interpreter_common.h b/runtime/interpreter/interpreter_common.h
index fdc0505..38edc7a 100644
--- a/runtime/interpreter/interpreter_common.h
+++ b/runtime/interpreter/interpreter_common.h
@@ -527,10 +527,11 @@
   }
 }
 
+// The arg_offset is the offset to the first input register in the frame.
 void ArtInterpreterToCompiledCodeBridge(Thread* self,
                                         ArtMethod* caller,
-                                        const DexFile::CodeItem* code_item,
                                         ShadowFrame* shadow_frame,
+                                        uint16_t arg_offset,
                                         JValue* result);
 
 // Set string value created from StringFactory.newStringFromXXX() into all aliases of
diff --git a/runtime/interpreter/mterp/mips/op_double_to_int.S b/runtime/interpreter/mterp/mips/op_double_to_int.S
index 3b44964..6d7c6ca 100644
--- a/runtime/interpreter/mterp/mips/op_double_to_int.S
+++ b/runtime/interpreter/mterp/mips/op_double_to_int.S
@@ -3,7 +3,8 @@
      *
      * We have to clip values to int min/max per the specification.  The
      * expected common case is a "reasonable" value that converts directly
-     * to modest integer.  The EABI convert function isn't doing this for us.
+     * to modest integer.  The EABI convert function isn't doing this for us
+     * for pre-R6.
      */
     /* unop vA, vB */
     GET_OPB(a3)                            #  a3 <- B
@@ -11,29 +12,20 @@
     EAS2(a3, rFP, a3)                      #  a3 <- &fp[B]
     LOAD64_F(fa0, fa0f, a3)
     FETCH_ADVANCE_INST(1)                  #  advance rPC, load rINST
-
+#ifndef MIPS32REVGE6
     li        t0, INT_MIN_AS_DOUBLE_HIGH
     mtc1      zero, fa1
     MOVE_TO_FPU_HIGH(t0, fa1, fa1f)
-#ifdef MIPS32REVGE6
-    /*
-     * TODO: simplify this when the MIPS64R6 emulator
-     * supports NAN2008=1.
-     */
-    cmp.le.d  ft0, fa1, fa0
-    GET_INST_OPCODE(t1)                    #  extract opcode from rINST
-    bc1nez    ft0, 1f                      #  if INT_MIN <= vB, proceed to truncation
-    cmp.eq.d  ft0, fa0, fa0
-    selnez.d  fa0, fa1, ft0                #  fa0 = ordered(vB) ? INT_MIN_AS_DOUBLE : 0
-#else
     c.ole.d   fcc0, fa1, fa0
+#endif
     GET_INST_OPCODE(t1)                    #  extract opcode from rINST
+#ifndef MIPS32REVGE6
     bc1t      fcc0, 1f                     #  if INT_MIN <= vB, proceed to truncation
     c.eq.d    fcc0, fa0, fa0
     mtc1      zero, fa0
     MOVE_TO_FPU_HIGH(zero, fa0, fa0f)
     movt.d    fa0, fa1, fcc0               #  fa0 = ordered(vB) ? INT_MIN_AS_DOUBLE : 0
-#endif
 1:
+#endif
     trunc.w.d fa0, fa0
     SET_VREG_F_GOTO(fa0, rOBJ, t1)         #  vA <- result
diff --git a/runtime/interpreter/mterp/mips/op_double_to_long.S b/runtime/interpreter/mterp/mips/op_double_to_long.S
index 78d4a8f..459ab7e 100644
--- a/runtime/interpreter/mterp/mips/op_double_to_long.S
+++ b/runtime/interpreter/mterp/mips/op_double_to_long.S
@@ -3,7 +3,8 @@
      *
      * We have to clip values to long min/max per the specification.  The
      * expected common case is a "reasonable" value that converts directly
-     * to modest integer.  The EABI convert function isn't doing this for us.
+     * to modest integer.  The EABI convert function isn't doing this for us
+     * for pre-R6.
      */
     /* unop vA, vB */
     GET_OPA4(rOBJ)                         #  rOBJ <- A+
@@ -13,19 +14,7 @@
     FETCH_ADVANCE_INST(1)                  #  advance rPC, load rINST
 
 #ifdef MIPS32REVGE6
-    /*
-     * TODO: simplify this when the MIPS64R6 emulator
-     * supports NAN2008=1.
-     */
-    li        t0, LONG_MIN_AS_DOUBLE_HIGH
-    mtc1      zero, fa1
-    mthc1     t0, fa1
-    cmp.le.d  ft0, fa1, fa0
     GET_INST_OPCODE(t1)                    #  extract opcode from rINST
-    bc1nez    ft0, 1f                      #  if LONG_MIN <= vB, proceed to truncation
-    cmp.eq.d  ft0, fa0, fa0
-    selnez.d  fa0, fa1, ft0                #  fa0 = ordered(vB) ? LONG_MIN_AS_DOUBLE : 0
-1:
     trunc.l.d fa0, fa0
     SET_VREG64_F_GOTO(fa0, fa0f, rOBJ, t1) #  vA <- result
 #else
diff --git a/runtime/interpreter/mterp/mips/op_float_to_int.S b/runtime/interpreter/mterp/mips/op_float_to_int.S
index 087e50f..26a0988 100644
--- a/runtime/interpreter/mterp/mips/op_float_to_int.S
+++ b/runtime/interpreter/mterp/mips/op_float_to_int.S
@@ -3,7 +3,8 @@
      *
      * We have to clip values to int min/max per the specification.  The
      * expected common case is a "reasonable" value that converts directly
-     * to modest integer.  The EABI convert function isn't doing this for us.
+     * to modest integer.  The EABI convert function isn't doing this for us
+     * for pre-R6.
      */
     /* unop vA, vB */
     GET_OPB(a3)                            #  a3 <- B
@@ -11,26 +12,18 @@
     GET_VREG_F(fa0, a3)
     FETCH_ADVANCE_INST(1)                  #  advance rPC, load rINST
 
+#ifndef MIPS32REVGE6
     li        t0, INT_MIN_AS_FLOAT
     mtc1      t0, fa1
-#ifdef MIPS32REVGE6
-    /*
-     * TODO: simplify this when the MIPS64R6 emulator
-     * supports NAN2008=1.
-     */
-    cmp.le.s  ft0, fa1, fa0
-    GET_INST_OPCODE(t1)                    #  extract opcode from rINST
-    bc1nez    ft0, 1f                      #  if INT_MIN <= vB, proceed to truncation
-    cmp.eq.s  ft0, fa0, fa0
-    selnez.s  fa0, fa1, ft0                #  fa0 = ordered(vB) ? INT_MIN_AS_FLOAT : 0
-#else
     c.ole.s   fcc0, fa1, fa0
+#endif
     GET_INST_OPCODE(t1)                    #  extract opcode from rINST
+#ifndef MIPS32REVGE6
     bc1t      fcc0, 1f                     #  if INT_MIN <= vB, proceed to truncation
     c.eq.s    fcc0, fa0, fa0
     mtc1      zero, fa0
     movt.s    fa0, fa1, fcc0               #  fa0 = ordered(vB) ? INT_MIN_AS_FLOAT : 0
-#endif
 1:
+#endif
     trunc.w.s fa0, fa0
     SET_VREG_F_GOTO(fa0, rOBJ, t1)         #  vA <- result
diff --git a/runtime/interpreter/mterp/mips/op_float_to_long.S b/runtime/interpreter/mterp/mips/op_float_to_long.S
index dc88a78..b8f8efb 100644
--- a/runtime/interpreter/mterp/mips/op_float_to_long.S
+++ b/runtime/interpreter/mterp/mips/op_float_to_long.S
@@ -3,7 +3,8 @@
      *
      * We have to clip values to long min/max per the specification.  The
      * expected common case is a "reasonable" value that converts directly
-     * to modest integer.  The EABI convert function isn't doing this for us.
+     * to modest integer.  The EABI convert function isn't doing this for us
+     * for pre-R6.
      */
     /* unop vA, vB */
     GET_OPA4(rOBJ)                         #  rOBJ <- A+
@@ -12,18 +13,7 @@
     FETCH_ADVANCE_INST(1)                  #  advance rPC, load rINST
 
 #ifdef MIPS32REVGE6
-    /*
-     * TODO: simplify this when the MIPS64R6 emulator
-     * supports NAN2008=1.
-     */
-    li        t0, LONG_MIN_AS_FLOAT
-    mtc1      t0, fa1
-    cmp.le.s  ft0, fa1, fa0
     GET_INST_OPCODE(t1)                    #  extract opcode from rINST
-    bc1nez    ft0, 1f                      #  if LONG_MIN <= vB, proceed to truncation
-    cmp.eq.s  ft0, fa0, fa0
-    selnez.s  fa0, fa1, ft0                #  fa0 = ordered(vB) ? LONG_MIN_AS_FLOAT : 0
-1:
     trunc.l.s fa0, fa0
     SET_VREG64_F_GOTO(fa0, fa0f, rOBJ, t1) #  vA <- result
 #else
diff --git a/runtime/interpreter/mterp/mips64/op_double_to_int.S b/runtime/interpreter/mterp/mips64/op_double_to_int.S
index aa2cbca..d099522 100644
--- a/runtime/interpreter/mterp/mips64/op_double_to_int.S
+++ b/runtime/interpreter/mterp/mips64/op_double_to_int.S
@@ -1,23 +1,3 @@
 %include "mips64/fcvtHeader.S" { "suffix":"_DOUBLE", "valreg":"f0" }
-    /*
-     * TODO: simplify this when the MIPS64R6 emulator
-     * supports NAN2008=1.
-     */
-    dli     t0, INT_MIN_AS_DOUBLE
-    dmtc1   t0, f1
-    cmp.le.d f1, f1, f0
-    bc1nez  f1, .L${opcode}_trunc
-    cmp.eq.d f1, f0, f0
-    li      t0, INT_MIN
-    mfc1    t1, f1
-    and     t0, t0, t1
-    b       .L${opcode}_done
-%break
-.L${opcode}_trunc:
     trunc.w.d f0, f0
-    mfc1    t0, f0
-.L${opcode}_done:
-    /* Can't include fcvtFooter.S after break */
-    GET_INST_OPCODE v0                  # extract opcode from rINST
-    SET_VREG t0, a1
-    GOTO_OPCODE v0                      # jump to next instruction
+%include "mips64/fcvtFooter.S" { "suffix":"_FLOAT", "valreg":"f0" }
diff --git a/runtime/interpreter/mterp/mips64/op_double_to_long.S b/runtime/interpreter/mterp/mips64/op_double_to_long.S
index 777cfeb..9b65da5 100644
--- a/runtime/interpreter/mterp/mips64/op_double_to_long.S
+++ b/runtime/interpreter/mterp/mips64/op_double_to_long.S
@@ -1,23 +1,3 @@
 %include "mips64/fcvtHeader.S" { "suffix":"_DOUBLE", "valreg":"f0" }
-    /*
-     * TODO: simplify this when the MIPS64R6 emulator
-     * supports NAN2008=1.
-     */
-    dli     t0, LONG_MIN_AS_DOUBLE
-    dmtc1   t0, f1
-    cmp.le.d f1, f1, f0
-    bc1nez  f1, .L${opcode}_trunc
-    cmp.eq.d f1, f0, f0
-    dli     t0, LONG_MIN
-    mfc1    t1, f1
-    and     t0, t0, t1
-    b       .L${opcode}_done
-%break
-.L${opcode}_trunc:
     trunc.l.d f0, f0
-    dmfc1   t0, f0
-.L${opcode}_done:
-    /* Can't include fcvtFooter.S after break */
-    GET_INST_OPCODE v0                  # extract opcode from rINST
-    SET_VREG_WIDE t0, a1
-    GOTO_OPCODE v0                      # jump to next instruction
+%include "mips64/fcvtFooter.S" { "suffix":"_DOUBLE", "valreg":"f0" }
diff --git a/runtime/interpreter/mterp/mips64/op_float_to_int.S b/runtime/interpreter/mterp/mips64/op_float_to_int.S
index d957540..2806973 100644
--- a/runtime/interpreter/mterp/mips64/op_float_to_int.S
+++ b/runtime/interpreter/mterp/mips64/op_float_to_int.S
@@ -1,23 +1,3 @@
 %include "mips64/fcvtHeader.S" { "suffix":"_FLOAT", "valreg":"f0" }
-    /*
-     * TODO: simplify this when the MIPS64R6 emulator
-     * supports NAN2008=1.
-     */
-    li      t0, INT_MIN_AS_FLOAT
-    mtc1    t0, f1
-    cmp.le.s f1, f1, f0
-    bc1nez  f1, .L${opcode}_trunc
-    cmp.eq.s f1, f0, f0
-    li      t0, INT_MIN
-    mfc1    t1, f1
-    and     t0, t0, t1
-    b       .L${opcode}_done
-%break
-.L${opcode}_trunc:
     trunc.w.s f0, f0
-    mfc1    t0, f0
-.L${opcode}_done:
-    /* Can't include fcvtFooter.S after break */
-    GET_INST_OPCODE v0                  # extract opcode from rINST
-    SET_VREG t0, a1
-    GOTO_OPCODE v0                      # jump to next instruction
+%include "mips64/fcvtFooter.S" { "suffix":"_FLOAT", "valreg":"f0" }
diff --git a/runtime/interpreter/mterp/mips64/op_float_to_long.S b/runtime/interpreter/mterp/mips64/op_float_to_long.S
index 5d036c8..c40c8a6 100644
--- a/runtime/interpreter/mterp/mips64/op_float_to_long.S
+++ b/runtime/interpreter/mterp/mips64/op_float_to_long.S
@@ -1,23 +1,3 @@
 %include "mips64/fcvtHeader.S" { "suffix":"_FLOAT", "valreg":"f0" }
-    /*
-     * TODO: simplify this when the MIPS64R6 emulator
-     * supports NAN2008=1.
-     */
-    li      t0, LONG_MIN_AS_FLOAT
-    mtc1    t0, f1
-    cmp.le.s f1, f1, f0
-    bc1nez  f1, .L${opcode}_trunc
-    cmp.eq.s f1, f0, f0
-    dli     t0, LONG_MIN
-    mfc1    t1, f1
-    and     t0, t0, t1
-    b       .L${opcode}_done
-%break
-.L${opcode}_trunc:
     trunc.l.s f0, f0
-    dmfc1   t0, f0
-.L${opcode}_done:
-    /* Can't include fcvtFooter.S after break */
-    GET_INST_OPCODE v0                  # extract opcode from rINST
-    SET_VREG_WIDE t0, a1
-    GOTO_OPCODE v0                      # jump to next instruction
+%include "mips64/fcvtFooter.S" { "suffix":"_DOUBLE", "valreg":"f0" }
diff --git a/runtime/interpreter/mterp/out/mterp_mips.S b/runtime/interpreter/mterp/out/mterp_mips.S
index 579afc2..6362897 100644
--- a/runtime/interpreter/mterp/out/mterp_mips.S
+++ b/runtime/interpreter/mterp/out/mterp_mips.S
@@ -3967,7 +3967,8 @@
      *
      * We have to clip values to int min/max per the specification.  The
      * expected common case is a "reasonable" value that converts directly
-     * to modest integer.  The EABI convert function isn't doing this for us.
+     * to modest integer.  The EABI convert function isn't doing this for us
+     * for pre-R6.
      */
     /* unop vA, vB */
     GET_OPB(a3)                            #  a3 <- B
@@ -3975,27 +3976,19 @@
     GET_VREG_F(fa0, a3)
     FETCH_ADVANCE_INST(1)                  #  advance rPC, load rINST
 
+#ifndef MIPS32REVGE6
     li        t0, INT_MIN_AS_FLOAT
     mtc1      t0, fa1
-#ifdef MIPS32REVGE6
-    /*
-     * TODO: simplify this when the MIPS64R6 emulator
-     * supports NAN2008=1.
-     */
-    cmp.le.s  ft0, fa1, fa0
-    GET_INST_OPCODE(t1)                    #  extract opcode from rINST
-    bc1nez    ft0, 1f                      #  if INT_MIN <= vB, proceed to truncation
-    cmp.eq.s  ft0, fa0, fa0
-    selnez.s  fa0, fa1, ft0                #  fa0 = ordered(vB) ? INT_MIN_AS_FLOAT : 0
-#else
     c.ole.s   fcc0, fa1, fa0
+#endif
     GET_INST_OPCODE(t1)                    #  extract opcode from rINST
+#ifndef MIPS32REVGE6
     bc1t      fcc0, 1f                     #  if INT_MIN <= vB, proceed to truncation
     c.eq.s    fcc0, fa0, fa0
     mtc1      zero, fa0
     movt.s    fa0, fa1, fcc0               #  fa0 = ordered(vB) ? INT_MIN_AS_FLOAT : 0
-#endif
 1:
+#endif
     trunc.w.s fa0, fa0
     SET_VREG_F_GOTO(fa0, rOBJ, t1)         #  vA <- result
 
@@ -4008,7 +4001,8 @@
      *
      * We have to clip values to long min/max per the specification.  The
      * expected common case is a "reasonable" value that converts directly
-     * to modest integer.  The EABI convert function isn't doing this for us.
+     * to modest integer.  The EABI convert function isn't doing this for us
+     * for pre-R6.
      */
     /* unop vA, vB */
     GET_OPA4(rOBJ)                         #  rOBJ <- A+
@@ -4017,18 +4011,7 @@
     FETCH_ADVANCE_INST(1)                  #  advance rPC, load rINST
 
 #ifdef MIPS32REVGE6
-    /*
-     * TODO: simplify this when the MIPS64R6 emulator
-     * supports NAN2008=1.
-     */
-    li        t0, LONG_MIN_AS_FLOAT
-    mtc1      t0, fa1
-    cmp.le.s  ft0, fa1, fa0
     GET_INST_OPCODE(t1)                    #  extract opcode from rINST
-    bc1nez    ft0, 1f                      #  if LONG_MIN <= vB, proceed to truncation
-    cmp.eq.s  ft0, fa0, fa0
-    selnez.s  fa0, fa1, ft0                #  fa0 = ordered(vB) ? LONG_MIN_AS_FLOAT : 0
-1:
     trunc.l.s fa0, fa0
     SET_VREG64_F_GOTO(fa0, fa0f, rOBJ, t1) #  vA <- result
 #else
@@ -4084,7 +4067,8 @@
      *
      * We have to clip values to int min/max per the specification.  The
      * expected common case is a "reasonable" value that converts directly
-     * to modest integer.  The EABI convert function isn't doing this for us.
+     * to modest integer.  The EABI convert function isn't doing this for us
+     * for pre-R6.
      */
     /* unop vA, vB */
     GET_OPB(a3)                            #  a3 <- B
@@ -4092,30 +4076,21 @@
     EAS2(a3, rFP, a3)                      #  a3 <- &fp[B]
     LOAD64_F(fa0, fa0f, a3)
     FETCH_ADVANCE_INST(1)                  #  advance rPC, load rINST
-
+#ifndef MIPS32REVGE6
     li        t0, INT_MIN_AS_DOUBLE_HIGH
     mtc1      zero, fa1
     MOVE_TO_FPU_HIGH(t0, fa1, fa1f)
-#ifdef MIPS32REVGE6
-    /*
-     * TODO: simplify this when the MIPS64R6 emulator
-     * supports NAN2008=1.
-     */
-    cmp.le.d  ft0, fa1, fa0
-    GET_INST_OPCODE(t1)                    #  extract opcode from rINST
-    bc1nez    ft0, 1f                      #  if INT_MIN <= vB, proceed to truncation
-    cmp.eq.d  ft0, fa0, fa0
-    selnez.d  fa0, fa1, ft0                #  fa0 = ordered(vB) ? INT_MIN_AS_DOUBLE : 0
-#else
     c.ole.d   fcc0, fa1, fa0
+#endif
     GET_INST_OPCODE(t1)                    #  extract opcode from rINST
+#ifndef MIPS32REVGE6
     bc1t      fcc0, 1f                     #  if INT_MIN <= vB, proceed to truncation
     c.eq.d    fcc0, fa0, fa0
     mtc1      zero, fa0
     MOVE_TO_FPU_HIGH(zero, fa0, fa0f)
     movt.d    fa0, fa1, fcc0               #  fa0 = ordered(vB) ? INT_MIN_AS_DOUBLE : 0
-#endif
 1:
+#endif
     trunc.w.d fa0, fa0
     SET_VREG_F_GOTO(fa0, rOBJ, t1)         #  vA <- result
 
@@ -4128,7 +4103,8 @@
      *
      * We have to clip values to long min/max per the specification.  The
      * expected common case is a "reasonable" value that converts directly
-     * to modest integer.  The EABI convert function isn't doing this for us.
+     * to modest integer.  The EABI convert function isn't doing this for us
+     * for pre-R6.
      */
     /* unop vA, vB */
     GET_OPA4(rOBJ)                         #  rOBJ <- A+
@@ -4138,19 +4114,7 @@
     FETCH_ADVANCE_INST(1)                  #  advance rPC, load rINST
 
 #ifdef MIPS32REVGE6
-    /*
-     * TODO: simplify this when the MIPS64R6 emulator
-     * supports NAN2008=1.
-     */
-    li        t0, LONG_MIN_AS_DOUBLE_HIGH
-    mtc1      zero, fa1
-    mthc1     t0, fa1
-    cmp.le.d  ft0, fa1, fa0
     GET_INST_OPCODE(t1)                    #  extract opcode from rINST
-    bc1nez    ft0, 1f                      #  if LONG_MIN <= vB, proceed to truncation
-    cmp.eq.d  ft0, fa0, fa0
-    selnez.d  fa0, fa1, ft0                #  fa0 = ordered(vB) ? LONG_MIN_AS_DOUBLE : 0
-1:
     trunc.l.d fa0, fa0
     SET_VREG64_F_GOTO(fa0, fa0f, rOBJ, t1) #  vA <- result
 #else
diff --git a/runtime/interpreter/mterp/out/mterp_mips64.S b/runtime/interpreter/mterp/out/mterp_mips64.S
index 3656df9..bc0d90c 100644
--- a/runtime/interpreter/mterp/out/mterp_mips64.S
+++ b/runtime/interpreter/mterp/out/mterp_mips64.S
@@ -3699,19 +3699,27 @@
     GET_VREG_FLOAT f0, a2
     FETCH_ADVANCE_INST 1                # advance rPC, load rINST
 
+    trunc.w.s f0, f0
+/* File: mips64/fcvtFooter.S */
     /*
-     * TODO: simplify this when the MIPS64R6 emulator
-     * supports NAN2008=1.
+     * Stores a specified register containing the result of conversion
+     * from or to a floating-point type and jumps to the next instruction.
+     *
+     * Expects a1 to contain the destination Dalvik register number.
+     * a1 is set up by fcvtHeader.S.
+     *
+     * For: int-to-float, int-to-double, long-to-float, long-to-double,
+     *      float-to-int, float-to-long, float-to-double, double-to-int,
+     *      double-to-long, double-to-float, neg-float, neg-double.
+     *
+     * Note that this file can't be included after a break in other files
+     * and in those files its contents appear as a copy.
+     * See: float-to-int, float-to-long, double-to-int, double-to-long.
      */
-    li      t0, INT_MIN_AS_FLOAT
-    mtc1    t0, f1
-    cmp.le.s f1, f1, f0
-    bc1nez  f1, .Lop_float_to_int_trunc
-    cmp.eq.s f1, f0, f0
-    li      t0, INT_MIN
-    mfc1    t1, f1
-    and     t0, t0, t1
-    b       .Lop_float_to_int_done
+    GET_INST_OPCODE v0                  # extract opcode from rINST
+    SET_VREG_FLOAT f0, a1
+    GOTO_OPCODE v0                      # jump to next instruction
+
 
 /* ------------------------------ */
     .balign 128
@@ -3734,19 +3742,28 @@
     GET_VREG_FLOAT f0, a2
     FETCH_ADVANCE_INST 1                # advance rPC, load rINST
 
+    trunc.l.s f0, f0
+/* File: mips64/fcvtFooter.S */
     /*
-     * TODO: simplify this when the MIPS64R6 emulator
-     * supports NAN2008=1.
+     * Stores a specified register containing the result of conversion
+     * from or to a floating-point type and jumps to the next instruction.
+     *
+     * Expects a1 to contain the destination Dalvik register number.
+     * a1 is set up by fcvtHeader.S.
+     *
+     * For: int-to-float, int-to-double, long-to-float, long-to-double,
+     *      float-to-int, float-to-long, float-to-double, double-to-int,
+     *      double-to-long, double-to-float, neg-float, neg-double.
+     *
+     * Note that this file can't be included after a break in other files
+     * and in those files its contents appear as a copy.
+     * See: float-to-int, float-to-long, double-to-int, double-to-long.
      */
-    li      t0, LONG_MIN_AS_FLOAT
-    mtc1    t0, f1
-    cmp.le.s f1, f1, f0
-    bc1nez  f1, .Lop_float_to_long_trunc
-    cmp.eq.s f1, f0, f0
-    dli     t0, LONG_MIN
-    mfc1    t1, f1
-    and     t0, t0, t1
-    b       .Lop_float_to_long_done
+    GET_INST_OPCODE v0                  # extract opcode from rINST
+    SET_VREG_DOUBLE f0, a1
+    GOTO_OPCODE v0                      # jump to next instruction
+
+
 
 /* ------------------------------ */
     .balign 128
@@ -3817,19 +3834,27 @@
     GET_VREG_DOUBLE f0, a2
     FETCH_ADVANCE_INST 1                # advance rPC, load rINST
 
+    trunc.w.d f0, f0
+/* File: mips64/fcvtFooter.S */
     /*
-     * TODO: simplify this when the MIPS64R6 emulator
-     * supports NAN2008=1.
+     * Stores a specified register containing the result of conversion
+     * from or to a floating-point type and jumps to the next instruction.
+     *
+     * Expects a1 to contain the destination Dalvik register number.
+     * a1 is set up by fcvtHeader.S.
+     *
+     * For: int-to-float, int-to-double, long-to-float, long-to-double,
+     *      float-to-int, float-to-long, float-to-double, double-to-int,
+     *      double-to-long, double-to-float, neg-float, neg-double.
+     *
+     * Note that this file can't be included after a break in other files
+     * and in those files its contents appear as a copy.
+     * See: float-to-int, float-to-long, double-to-int, double-to-long.
      */
-    dli     t0, INT_MIN_AS_DOUBLE
-    dmtc1   t0, f1
-    cmp.le.d f1, f1, f0
-    bc1nez  f1, .Lop_double_to_int_trunc
-    cmp.eq.d f1, f0, f0
-    li      t0, INT_MIN
-    mfc1    t1, f1
-    and     t0, t0, t1
-    b       .Lop_double_to_int_done
+    GET_INST_OPCODE v0                  # extract opcode from rINST
+    SET_VREG_FLOAT f0, a1
+    GOTO_OPCODE v0                      # jump to next instruction
+
 
 /* ------------------------------ */
     .balign 128
@@ -3852,19 +3877,27 @@
     GET_VREG_DOUBLE f0, a2
     FETCH_ADVANCE_INST 1                # advance rPC, load rINST
 
+    trunc.l.d f0, f0
+/* File: mips64/fcvtFooter.S */
     /*
-     * TODO: simplify this when the MIPS64R6 emulator
-     * supports NAN2008=1.
+     * Stores a specified register containing the result of conversion
+     * from or to a floating-point type and jumps to the next instruction.
+     *
+     * Expects a1 to contain the destination Dalvik register number.
+     * a1 is set up by fcvtHeader.S.
+     *
+     * For: int-to-float, int-to-double, long-to-float, long-to-double,
+     *      float-to-int, float-to-long, float-to-double, double-to-int,
+     *      double-to-long, double-to-float, neg-float, neg-double.
+     *
+     * Note that this file can't be included after a break in other files
+     * and in those files its contents appear as a copy.
+     * See: float-to-int, float-to-long, double-to-int, double-to-long.
      */
-    dli     t0, LONG_MIN_AS_DOUBLE
-    dmtc1   t0, f1
-    cmp.le.d f1, f1, f0
-    bc1nez  f1, .Lop_double_to_long_trunc
-    cmp.eq.d f1, f0, f0
-    dli     t0, LONG_MIN
-    mfc1    t1, f1
-    and     t0, t0, t1
-    b       .Lop_double_to_long_done
+    GET_INST_OPCODE v0                  # extract opcode from rINST
+    SET_VREG_DOUBLE f0, a1
+    GOTO_OPCODE v0                      # jump to next instruction
+
 
 /* ------------------------------ */
     .balign 128
@@ -7132,46 +7165,6 @@
     .balign 4
 artMterpAsmSisterStart:
 
-/* continuation for op_float_to_int */
-.Lop_float_to_int_trunc:
-    trunc.w.s f0, f0
-    mfc1    t0, f0
-.Lop_float_to_int_done:
-    /* Can't include fcvtFooter.S after break */
-    GET_INST_OPCODE v0                  # extract opcode from rINST
-    SET_VREG t0, a1
-    GOTO_OPCODE v0                      # jump to next instruction
-
-/* continuation for op_float_to_long */
-.Lop_float_to_long_trunc:
-    trunc.l.s f0, f0
-    dmfc1   t0, f0
-.Lop_float_to_long_done:
-    /* Can't include fcvtFooter.S after break */
-    GET_INST_OPCODE v0                  # extract opcode from rINST
-    SET_VREG_WIDE t0, a1
-    GOTO_OPCODE v0                      # jump to next instruction
-
-/* continuation for op_double_to_int */
-.Lop_double_to_int_trunc:
-    trunc.w.d f0, f0
-    mfc1    t0, f0
-.Lop_double_to_int_done:
-    /* Can't include fcvtFooter.S after break */
-    GET_INST_OPCODE v0                  # extract opcode from rINST
-    SET_VREG t0, a1
-    GOTO_OPCODE v0                      # jump to next instruction
-
-/* continuation for op_double_to_long */
-.Lop_double_to_long_trunc:
-    trunc.l.d f0, f0
-    dmfc1   t0, f0
-.Lop_double_to_long_done:
-    /* Can't include fcvtFooter.S after break */
-    GET_INST_OPCODE v0                  # extract opcode from rINST
-    SET_VREG_WIDE t0, a1
-    GOTO_OPCODE v0                      # jump to next instruction
-
     .size   artMterpAsmSisterStart, .-artMterpAsmSisterStart
     .global artMterpAsmSisterEnd
 artMterpAsmSisterEnd:
diff --git a/runtime/jit/jit_code_cache.cc b/runtime/jit/jit_code_cache.cc
index 5ce5447..42d7653 100644
--- a/runtime/jit/jit_code_cache.cc
+++ b/runtime/jit/jit_code_cache.cc
@@ -192,19 +192,26 @@
 
 class ScopedCodeCacheWrite : ScopedTrace {
  public:
-  explicit ScopedCodeCacheWrite(MemMap* code_map)
+  explicit ScopedCodeCacheWrite(MemMap* code_map, bool only_for_tlb_shootdown = false)
       : ScopedTrace("ScopedCodeCacheWrite"),
-        code_map_(code_map) {
+        code_map_(code_map),
+        only_for_tlb_shootdown_(only_for_tlb_shootdown) {
     ScopedTrace trace("mprotect all");
-    CHECKED_MPROTECT(code_map_->Begin(), code_map_->Size(), kProtAll);
+    CHECKED_MPROTECT(
+        code_map_->Begin(), only_for_tlb_shootdown_ ? kPageSize : code_map_->Size(), kProtAll);
   }
   ~ScopedCodeCacheWrite() {
     ScopedTrace trace("mprotect code");
-    CHECKED_MPROTECT(code_map_->Begin(), code_map_->Size(), kProtCode);
+    CHECKED_MPROTECT(
+        code_map_->Begin(), only_for_tlb_shootdown_ ? kPageSize : code_map_->Size(), kProtCode);
   }
  private:
   MemMap* const code_map_;
 
+  // If we're using ScopedCacheWrite only for TLB shootdown, we limit the scope of mprotect to
+  // one page.
+  const bool only_for_tlb_shootdown_;
+
   DISALLOW_COPY_AND_ASSIGN(ScopedCodeCacheWrite);
 };
 
@@ -565,11 +572,6 @@
           core_spill_mask,
           fp_spill_mask,
           code_size);
-      DCHECK_EQ(FromStackMapToRoots(stack_map), roots_data);
-      DCHECK_LE(roots_data, stack_map);
-      // Flush data cache, as compiled code references literals in it.
-      FlushDataCache(reinterpret_cast<char*>(roots_data),
-                     reinterpret_cast<char*>(roots_data + data_size));
       // Flush caches before we remove write permission because some ARMv8 Qualcomm kernels may
       // trigger a segfault if a page fault occurs when requesting a cache maintenance operation.
       // This is a kernel bug that we need to work around until affected devices (e.g. Nexus 5X and
@@ -595,11 +597,10 @@
     bool single_impl_still_valid = true;
     for (ArtMethod* single_impl : cha_single_implementation_list) {
       if (!single_impl->HasSingleImplementation()) {
-        // We simply discard the compiled code. Clear the
-        // counter so that it may be recompiled later. Hopefully the
-        // class hierarchy will be more stable when compilation is retried.
+        // Simply discard the compiled code. Clear the counter so that it may be recompiled later.
+        // Hopefully the class hierarchy will be more stable when compilation is retried.
         single_impl_still_valid = false;
-        method->ClearCounter();
+        method->SetCounter(1);
         break;
       }
     }
@@ -621,10 +622,18 @@
     // possible that the compiled code is considered invalidated by some class linking,
     // but below we still make the compiled code valid for the method.
     MutexLock mu(self, lock_);
-    method_code_map_.Put(code_ptr, method);
     // Fill the root table before updating the entry point.
     DCHECK_EQ(FromStackMapToRoots(stack_map), roots_data);
+    DCHECK_LE(roots_data, stack_map);
     FillRootTable(roots_data, roots);
+    {
+      // Flush data cache, as compiled code references literals in it.
+      // We also need a TLB shootdown to act as memory barrier across cores.
+      ScopedCodeCacheWrite ccw(code_map_.get(), /* only_for_tlb_shootdown */ true);
+      FlushDataCache(reinterpret_cast<char*>(roots_data),
+                     reinterpret_cast<char*>(roots_data + data_size));
+    }
+    method_code_map_.Put(code_ptr, method);
     if (osr) {
       number_of_osr_compilations_++;
       osr_code_map_.Put(method, code_ptr);
@@ -1059,8 +1068,9 @@
         if (info->GetSavedEntryPoint() != nullptr) {
           info->SetSavedEntryPoint(nullptr);
           // We are going to move this method back to interpreter. Clear the counter now to
-          // give it a chance to be hot again.
-          info->GetMethod()->ClearCounter();
+          // give it a chance to be hot again, but set it to 1 so that this method can still be
+          // considered a startup method in case it's not executed again.
+          info->GetMethod()->SetCounter(1);
         }
       }
     } else if (kIsDebugBuild) {
@@ -1289,7 +1299,7 @@
     }
 
     for (size_t i = 0; i < info->number_of_inline_caches_; ++i) {
-      std::vector<ProfileMethodInfo::ProfileClassReference> profile_classes;
+      std::vector<TypeReference> profile_classes;
       const InlineCache& cache = info->cache_[i];
       ArtMethod* caller = info->GetMethod();
       bool is_missing_types = false;
@@ -1367,10 +1377,9 @@
   ProfilingInfo* info = method->GetProfilingInfo(kRuntimePointerSize);
   if (info == nullptr) {
     VLOG(jit) << method->PrettyMethod() << " needs a ProfilingInfo to be compiled";
-    // Because the counter is not atomic, there are some rare cases where we may not
-    // hit the threshold for creating the ProfilingInfo. Reset the counter now to
-    // "correct" this.
-    method->ClearCounter();
+    // Because the counter is not atomic, there are some rare cases where we may not hit the
+    // threshold for creating the ProfilingInfo. Reset the counter now to "correct" this.
+    method->SetCounter(1);
     return false;
   }
 
@@ -1422,12 +1431,12 @@
   }
 
   if (method->GetEntryPointFromQuickCompiledCode() == header->GetEntryPoint()) {
-    // The entrypoint is the one to invalidate, so we just update
-    // it to the interpreter entry point and clear the counter to get the method
-    // Jitted again.
+    // The entrypoint is the one to invalidate, so we just update it to the interpreter entry point
+    // and clear the counter to get the method Jitted again. We reset the counter to 1 to preserve
+    // it as a potential startup method.
     Runtime::Current()->GetInstrumentation()->UpdateMethodsCode(
         method, GetQuickToInterpreterBridge());
-    method->ClearCounter();
+    method->SetCounter(1);
   } else {
     MutexLock mu(Thread::Current(), lock_);
     auto it = osr_code_map_.find(method);
diff --git a/runtime/jit/profile_compilation_info.cc b/runtime/jit/profile_compilation_info.cc
index 10ab62f..1e720c0 100644
--- a/runtime/jit/profile_compilation_info.cc
+++ b/runtime/jit/profile_compilation_info.cc
@@ -603,7 +603,7 @@
       FindOrAddDexPc(inline_cache, cache.dex_pc)->SetIsMissingTypes();
       continue;
     }
-    for (const ProfileMethodInfo::ProfileClassReference& class_ref : cache.classes) {
+    for (const TypeReference& class_ref : cache.classes) {
       DexFileData* class_dex_data = GetOrAddDexFileData(
           GetProfileDexFileKey(class_ref.dex_file->GetLocation()),
           class_ref.dex_file->GetLocationChecksum());
diff --git a/runtime/jit/profile_compilation_info.h b/runtime/jit/profile_compilation_info.h
index 09f1548..a9a5b13 100644
--- a/runtime/jit/profile_compilation_info.h
+++ b/runtime/jit/profile_compilation_info.h
@@ -28,6 +28,7 @@
 #include "dex_file_types.h"
 #include "method_reference.h"
 #include "safe_map.h"
+#include "type_reference.h"
 
 namespace art {
 
@@ -36,24 +37,15 @@
  *  without the need to hold GC-able objects.
  */
 struct ProfileMethodInfo {
-  struct ProfileClassReference {
-    ProfileClassReference() : dex_file(nullptr) {}
-    ProfileClassReference(const DexFile* dex, const dex::TypeIndex index)
-        : dex_file(dex), type_index(index) {}
-
-    const DexFile* dex_file;
-    dex::TypeIndex type_index;
-  };
-
   struct ProfileInlineCache {
     ProfileInlineCache(uint32_t pc,
                        bool missing_types,
-                       const std::vector<ProfileClassReference>& profile_classes)
+                       const std::vector<TypeReference>& profile_classes)
         : dex_pc(pc), is_missing_types(missing_types), classes(profile_classes) {}
 
     const uint32_t dex_pc;
     const bool is_missing_types;
-    const std::vector<ProfileClassReference> classes;
+    const std::vector<TypeReference> classes;
   };
 
   ProfileMethodInfo(const DexFile* dex, uint32_t method_index)
@@ -284,6 +276,9 @@
 
   ArenaAllocator* GetArena() { return &arena_; }
 
+  // Add a method index to the profile (without inline caches).
+  bool AddMethodIndex(const std::string& dex_location, uint32_t checksum, uint16_t method_idx);
+
  private:
   enum ProfileLoadSatus {
     kProfileLoadWouldOverwiteData,
@@ -341,9 +336,6 @@
   // already exists but has a different checksum
   DexFileData* GetOrAddDexFileData(const std::string& profile_key, uint32_t checksum);
 
-  // Add a method index to the profile (without inline caches).
-  bool AddMethodIndex(const std::string& dex_location, uint32_t checksum, uint16_t method_idx);
-
   // Add a method to the profile using its online representation (containing runtime structures).
   bool AddMethod(const ProfileMethodInfo& pmi);
 
diff --git a/runtime/jit/profile_compilation_info_test.cc b/runtime/jit/profile_compilation_info_test.cc
index b0fceee..1cfa355 100644
--- a/runtime/jit/profile_compilation_info_test.cc
+++ b/runtime/jit/profile_compilation_info_test.cc
@@ -25,9 +25,10 @@
 #include "mirror/class-inl.h"
 #include "mirror/class_loader.h"
 #include "handle_scope-inl.h"
-#include "linear_alloc.h"
 #include "jit/profile_compilation_info.h"
+#include "linear_alloc.h"
 #include "scoped_thread_state_change-inl.h"
+#include "type_reference.h"
 
 namespace art {
 
@@ -123,13 +124,13 @@
       std::vector<ProfileMethodInfo::ProfileInlineCache> caches;
       // Monomorphic
       for (uint16_t dex_pc = 0; dex_pc < 11; dex_pc++) {
-        std::vector<ProfileMethodInfo::ProfileClassReference> classes;
+        std::vector<TypeReference> classes;
         classes.emplace_back(method->GetDexFile(), dex::TypeIndex(0));
         caches.emplace_back(dex_pc, /*is_missing_types*/false, classes);
       }
       // Polymorphic
       for (uint16_t dex_pc = 11; dex_pc < 22; dex_pc++) {
-        std::vector<ProfileMethodInfo::ProfileClassReference> classes;
+        std::vector<TypeReference> classes;
         for (uint16_t k = 0; k < InlineCache::kIndividualCacheSize / 2; k++) {
           classes.emplace_back(method->GetDexFile(), dex::TypeIndex(k));
         }
@@ -137,7 +138,7 @@
       }
       // Megamorphic
       for (uint16_t dex_pc = 22; dex_pc < 33; dex_pc++) {
-        std::vector<ProfileMethodInfo::ProfileClassReference> classes;
+        std::vector<TypeReference> classes;
         for (uint16_t k = 0; k < 2 * InlineCache::kIndividualCacheSize; k++) {
           classes.emplace_back(method->GetDexFile(), dex::TypeIndex(k));
         }
@@ -145,7 +146,7 @@
       }
       // Missing types
       for (uint16_t dex_pc = 33; dex_pc < 44; dex_pc++) {
-        std::vector<ProfileMethodInfo::ProfileClassReference> classes;
+        std::vector<TypeReference> classes;
         caches.emplace_back(dex_pc, /*is_missing_types*/true, classes);
       }
       ProfileMethodInfo pmi(method->GetDexFile(), method->GetDexMethodIndex(), caches);
diff --git a/runtime/jit/profiling_info.h b/runtime/jit/profiling_info.h
index d6881aa..788fa1f 100644
--- a/runtime/jit/profiling_info.h
+++ b/runtime/jit/profiling_info.h
@@ -29,11 +29,11 @@
 
 namespace jit {
 class JitCodeCache;
-}
+}  // namespace jit
 
 namespace mirror {
 class Class;
-}
+}  // namespace mirror
 
 // Structure to store the classes seen at runtime for a specific instruction.
 // Once the classes_ array is full, we consider the INVOKE to be megamorphic.
diff --git a/runtime/jni_internal.h b/runtime/jni_internal.h
index 580a42b..24bee6f 100644
--- a/runtime/jni_internal.h
+++ b/runtime/jni_internal.h
@@ -19,7 +19,6 @@
 
 #include <jni.h>
 #include <iosfwd>
-#include "nativehelper/jni_macros.h"
 
 #include "base/macros.h"
 
diff --git a/runtime/method_handles.cc b/runtime/method_handles.cc
index 54d45b1..090bac1 100644
--- a/runtime/method_handles.cc
+++ b/runtime/method_handles.cc
@@ -514,7 +514,15 @@
     }
   }
 
-  PerformCall(self, code_item, shadow_frame.GetMethod(), first_dest_reg, new_shadow_frame, result);
+  bool use_interpreter_entrypoint = ClassLinker::ShouldUseInterpreterEntrypoint(
+      called_method, called_method->GetEntryPointFromQuickCompiledCode());
+  PerformCall(self,
+              code_item,
+              shadow_frame.GetMethod(),
+              first_dest_reg,
+              new_shadow_frame,
+              result,
+              use_interpreter_entrypoint);
   if (self->IsExceptionPending()) {
     return false;
   }
@@ -602,12 +610,15 @@
   new_shadow_frame->SetVRegReference(0, receiver.Get());
   new_shadow_frame->SetVRegReference(1, sf.Get());
 
+  bool use_interpreter_entrypoint = ClassLinker::ShouldUseInterpreterEntrypoint(
+      called_method, called_method->GetEntryPointFromQuickCompiledCode());
   PerformCall(self,
               code_item,
               shadow_frame.GetMethod(),
               0 /* first destination register */,
               new_shadow_frame,
-              result);
+              result,
+              use_interpreter_entrypoint);
   if (self->IsExceptionPending()) {
     return false;
   }
@@ -1091,7 +1102,15 @@
                                          num_input_regs);
   self->EndAssertNoThreadSuspension(old_cause);
 
-  PerformCall(self, code_item, shadow_frame.GetMethod(), first_dest_reg, new_shadow_frame, result);
+  bool use_interpreter_entrypoint = ClassLinker::ShouldUseInterpreterEntrypoint(
+      called_method, called_method->GetEntryPointFromQuickCompiledCode());
+  PerformCall(self,
+              code_item,
+              shadow_frame.GetMethod(),
+              first_dest_reg,
+              new_shadow_frame,
+              result,
+              use_interpreter_entrypoint);
   if (self->IsExceptionPending()) {
     return false;
   }
diff --git a/runtime/method_handles.h b/runtime/method_handles.h
index 5bea0ab..e8a2dce 100644
--- a/runtime/method_handles.h
+++ b/runtime/method_handles.h
@@ -29,7 +29,7 @@
 namespace mirror {
   class MethodHandle;
   class MethodType;
-}  // mirror
+}  // namespace mirror
 
 class ShadowFrame;
 
diff --git a/runtime/mirror/class_loader.h b/runtime/mirror/class_loader.h
index a62a460..6e1f44b 100644
--- a/runtime/mirror/class_loader.h
+++ b/runtime/mirror/class_loader.h
@@ -23,6 +23,7 @@
 
 struct ClassLoaderOffsets;
 class ClassTable;
+class LinearAlloc;
 
 namespace mirror {
 
diff --git a/runtime/mirror/field-inl.h b/runtime/mirror/field-inl.h
index 2496989..d33df5c 100644
--- a/runtime/mirror/field-inl.h
+++ b/runtime/mirror/field-inl.h
@@ -21,7 +21,6 @@
 
 #include "art_field-inl.h"
 #include "mirror/dex_cache-inl.h"
-#include "runtime-inl.h"
 
 namespace art {
 
diff --git a/runtime/mirror/reference.h b/runtime/mirror/reference.h
index f2fa589..cfcbd5a 100644
--- a/runtime/mirror/reference.h
+++ b/runtime/mirror/reference.h
@@ -22,10 +22,7 @@
 #include "gc_root.h"
 #include "obj_ptr.h"
 #include "object.h"
-#include "object_callbacks.h"
 #include "read_barrier_option.h"
-#include "runtime.h"
-#include "thread.h"
 
 namespace art {
 
diff --git a/runtime/native/dalvik_system_DexFile.cc b/runtime/native/dalvik_system_DexFile.cc
index e618323..870402d 100644
--- a/runtime/native/dalvik_system_DexFile.cc
+++ b/runtime/native/dalvik_system_DexFile.cc
@@ -19,6 +19,7 @@
 #include <sstream>
 
 #include "android-base/stringprintf.h"
+#include "nativehelper/jni_macros.h"
 
 #include "base/logging.h"
 #include "base/stl_util.h"
diff --git a/runtime/native/dalvik_system_VMDebug.cc b/runtime/native/dalvik_system_VMDebug.cc
index 5c4e242..bb8233b 100644
--- a/runtime/native/dalvik_system_VMDebug.cc
+++ b/runtime/native/dalvik_system_VMDebug.cc
@@ -21,6 +21,8 @@
 
 #include <sstream>
 
+#include "nativehelper/jni_macros.h"
+
 #include "base/histogram-inl.h"
 #include "base/time_utils.h"
 #include "class_linker.h"
diff --git a/runtime/native/dalvik_system_VMRuntime.cc b/runtime/native/dalvik_system_VMRuntime.cc
index ff4d931..18b871c 100644
--- a/runtime/native/dalvik_system_VMRuntime.cc
+++ b/runtime/native/dalvik_system_VMRuntime.cc
@@ -30,6 +30,7 @@
 #pragma GCC diagnostic pop
 
 #include "android-base/stringprintf.h"
+#include "nativehelper/jni_macros.h"
 
 #include "art_method-inl.h"
 #include "arch/instruction_set.h"
diff --git a/runtime/native/dalvik_system_VMStack.cc b/runtime/native/dalvik_system_VMStack.cc
index 0dfafa4..6c41d51 100644
--- a/runtime/native/dalvik_system_VMStack.cc
+++ b/runtime/native/dalvik_system_VMStack.cc
@@ -16,6 +16,8 @@
 
 #include "dalvik_system_VMStack.h"
 
+#include "nativehelper/jni_macros.h"
+
 #include "art_method-inl.h"
 #include "gc/task_processor.h"
 #include "jni_internal.h"
diff --git a/runtime/native/dalvik_system_ZygoteHooks.cc b/runtime/native/dalvik_system_ZygoteHooks.cc
index 0515ec6..4c6f530 100644
--- a/runtime/native/dalvik_system_ZygoteHooks.cc
+++ b/runtime/native/dalvik_system_ZygoteHooks.cc
@@ -19,6 +19,7 @@
 #include <stdlib.h>
 
 #include "android-base/stringprintf.h"
+#include "nativehelper/jni_macros.h"
 
 #include "arch/instruction_set.h"
 #include "art_method-inl.h"
diff --git a/runtime/native/java_lang_Class.cc b/runtime/native/java_lang_Class.cc
index 4f99947..9e07a5c 100644
--- a/runtime/native/java_lang_Class.cc
+++ b/runtime/native/java_lang_Class.cc
@@ -18,6 +18,8 @@
 
 #include <iostream>
 
+#include "nativehelper/jni_macros.h"
+
 #include "art_field-inl.h"
 #include "art_method-inl.h"
 #include "base/enums.h"
diff --git a/runtime/native/java_lang_Object.cc b/runtime/native/java_lang_Object.cc
index fb4f99a..c9841d1 100644
--- a/runtime/native/java_lang_Object.cc
+++ b/runtime/native/java_lang_Object.cc
@@ -16,6 +16,8 @@
 
 #include "java_lang_Object.h"
 
+#include "nativehelper/jni_macros.h"
+
 #include "jni_internal.h"
 #include "mirror/object-inl.h"
 #include "scoped_fast_native_object_access-inl.h"
diff --git a/runtime/native/java_lang_String.cc b/runtime/native/java_lang_String.cc
index bf33bf2..4928c01 100644
--- a/runtime/native/java_lang_String.cc
+++ b/runtime/native/java_lang_String.cc
@@ -16,6 +16,8 @@
 
 #include "java_lang_String.h"
 
+#include "nativehelper/jni_macros.h"
+
 #include "common_throws.h"
 #include "jni_internal.h"
 #include "mirror/array.h"
diff --git a/runtime/native/java_lang_StringFactory.cc b/runtime/native/java_lang_StringFactory.cc
index ec3c7c2..c1292ef 100644
--- a/runtime/native/java_lang_StringFactory.cc
+++ b/runtime/native/java_lang_StringFactory.cc
@@ -16,6 +16,8 @@
 
 #include "java_lang_StringFactory.h"
 
+#include "nativehelper/jni_macros.h"
+
 #include "common_throws.h"
 #include "jni_internal.h"
 #include "mirror/object-inl.h"
diff --git a/runtime/native/java_lang_System.cc b/runtime/native/java_lang_System.cc
index 2cabce8..264b427 100644
--- a/runtime/native/java_lang_System.cc
+++ b/runtime/native/java_lang_System.cc
@@ -16,6 +16,8 @@
 
 #include "java_lang_System.h"
 
+#include "nativehelper/jni_macros.h"
+
 #include "common_throws.h"
 #include "gc/accounting/card_table-inl.h"
 #include "jni_internal.h"
diff --git a/runtime/native/java_lang_Thread.cc b/runtime/native/java_lang_Thread.cc
index 346bd30..f3254c4 100644
--- a/runtime/native/java_lang_Thread.cc
+++ b/runtime/native/java_lang_Thread.cc
@@ -16,6 +16,8 @@
 
 #include "java_lang_Thread.h"
 
+#include "nativehelper/jni_macros.h"
+
 #include "common_throws.h"
 #include "jni_internal.h"
 #include "monitor.h"
diff --git a/runtime/native/java_lang_Throwable.cc b/runtime/native/java_lang_Throwable.cc
index 654b8a8..b69fbef 100644
--- a/runtime/native/java_lang_Throwable.cc
+++ b/runtime/native/java_lang_Throwable.cc
@@ -16,6 +16,8 @@
 
 #include "java_lang_Throwable.h"
 
+#include "nativehelper/jni_macros.h"
+
 #include "jni_internal.h"
 #include "scoped_fast_native_object_access-inl.h"
 #include "thread.h"
diff --git a/runtime/native/java_lang_VMClassLoader.cc b/runtime/native/java_lang_VMClassLoader.cc
index a9ba33e..55955e7 100644
--- a/runtime/native/java_lang_VMClassLoader.cc
+++ b/runtime/native/java_lang_VMClassLoader.cc
@@ -16,12 +16,15 @@
 
 #include "java_lang_VMClassLoader.h"
 
+#include "nativehelper/jni_macros.h"
+
 #include "class_linker.h"
 #include "jni_internal.h"
 #include "mirror/class_loader.h"
 #include "mirror/object-inl.h"
 #include "obj_ptr.h"
 #include "scoped_fast_native_object_access-inl.h"
+#include "ScopedLocalRef.h"
 #include "ScopedUtfChars.h"
 #include "well_known_classes.h"
 #include "zip_archive.h"
@@ -122,16 +125,24 @@
 static jobjectArray VMClassLoader_getBootClassPathEntries(JNIEnv* env, jclass) {
   const std::vector<const DexFile*>& path =
       Runtime::Current()->GetClassLinker()->GetBootClassPath();
-  jclass stringClass = env->FindClass("java/lang/String");
-  jobjectArray array = env->NewObjectArray(path.size(), stringClass, nullptr);
+  jobjectArray array =
+      env->NewObjectArray(path.size(), WellKnownClasses::java_lang_String, nullptr);
+  if (array == nullptr) {
+    DCHECK(env->ExceptionCheck());
+    return nullptr;
+  }
   for (size_t i = 0; i < path.size(); ++i) {
     const DexFile* dex_file = path[i];
 
     // For multidex locations, e.g., x.jar:classes2.dex, we want to look into x.jar.
     const std::string& location(dex_file->GetBaseLocation());
 
-    jstring javaPath = env->NewStringUTF(location.c_str());
-    env->SetObjectArrayElement(array, i, javaPath);
+    ScopedLocalRef<jstring> javaPath(env, env->NewStringUTF(location.c_str()));
+    if (javaPath.get() == nullptr) {
+      DCHECK(env->ExceptionCheck());
+      return nullptr;
+    }
+    env->SetObjectArrayElement(array, i, javaPath.get());
   }
   return array;
 }
diff --git a/runtime/native/java_lang_Void.cc b/runtime/native/java_lang_Void.cc
index e2b4b82..b0d63ef 100644
--- a/runtime/native/java_lang_Void.cc
+++ b/runtime/native/java_lang_Void.cc
@@ -16,6 +16,8 @@
 
 #include "java_lang_Void.h"
 
+#include "nativehelper/jni_macros.h"
+
 #include "class_linker-inl.h"
 #include "jni_internal.h"
 #include "runtime.h"
diff --git a/runtime/native/java_lang_invoke_MethodHandleImpl.cc b/runtime/native/java_lang_invoke_MethodHandleImpl.cc
index 9113841..63168ce 100644
--- a/runtime/native/java_lang_invoke_MethodHandleImpl.cc
+++ b/runtime/native/java_lang_invoke_MethodHandleImpl.cc
@@ -16,6 +16,8 @@
 
 #include "java_lang_invoke_MethodHandleImpl.h"
 
+#include "nativehelper/jni_macros.h"
+
 #include "art_method.h"
 #include "handle_scope-inl.h"
 #include "jni_internal.h"
diff --git a/runtime/native/java_lang_ref_FinalizerReference.cc b/runtime/native/java_lang_ref_FinalizerReference.cc
index afedc5e..c75837a 100644
--- a/runtime/native/java_lang_ref_FinalizerReference.cc
+++ b/runtime/native/java_lang_ref_FinalizerReference.cc
@@ -16,6 +16,8 @@
 
 #include "java_lang_ref_FinalizerReference.h"
 
+#include "nativehelper/jni_macros.h"
+
 #include "gc/heap.h"
 #include "gc/reference_processor.h"
 #include "jni_internal.h"
diff --git a/runtime/native/java_lang_ref_Reference.cc b/runtime/native/java_lang_ref_Reference.cc
index b1cb2f2..606e656 100644
--- a/runtime/native/java_lang_ref_Reference.cc
+++ b/runtime/native/java_lang_ref_Reference.cc
@@ -16,6 +16,8 @@
 
 #include "java_lang_ref_Reference.h"
 
+#include "nativehelper/jni_macros.h"
+
 #include "gc/heap.h"
 #include "gc/reference_processor.h"
 #include "jni_internal.h"
diff --git a/runtime/native/java_lang_reflect_Array.cc b/runtime/native/java_lang_reflect_Array.cc
index 54c2109..9662395 100644
--- a/runtime/native/java_lang_reflect_Array.cc
+++ b/runtime/native/java_lang_reflect_Array.cc
@@ -16,6 +16,8 @@
 
 #include "java_lang_reflect_Array.h"
 
+#include "nativehelper/jni_macros.h"
+
 #include "class_linker-inl.h"
 #include "common_throws.h"
 #include "dex_file-inl.h"
diff --git a/runtime/native/java_lang_reflect_Constructor.cc b/runtime/native/java_lang_reflect_Constructor.cc
index fb78046..d1953ad 100644
--- a/runtime/native/java_lang_reflect_Constructor.cc
+++ b/runtime/native/java_lang_reflect_Constructor.cc
@@ -16,6 +16,8 @@
 
 #include "java_lang_reflect_Constructor.h"
 
+#include "nativehelper/jni_macros.h"
+
 #include "art_method-inl.h"
 #include "base/enums.h"
 #include "class_linker.h"
diff --git a/runtime/native/java_lang_reflect_Executable.cc b/runtime/native/java_lang_reflect_Executable.cc
index 8f226ce..256a3d0 100644
--- a/runtime/native/java_lang_reflect_Executable.cc
+++ b/runtime/native/java_lang_reflect_Executable.cc
@@ -17,6 +17,7 @@
 #include "java_lang_reflect_Executable.h"
 
 #include "android-base/stringprintf.h"
+#include "nativehelper/jni_macros.h"
 
 #include "art_method-inl.h"
 #include "dex_file_annotations.h"
diff --git a/runtime/native/java_lang_reflect_Field.cc b/runtime/native/java_lang_reflect_Field.cc
index 0fb3903..e38bcd6 100644
--- a/runtime/native/java_lang_reflect_Field.cc
+++ b/runtime/native/java_lang_reflect_Field.cc
@@ -17,6 +17,7 @@
 #include "java_lang_reflect_Field.h"
 
 #include "android-base/stringprintf.h"
+#include "nativehelper/jni_macros.h"
 
 #include "art_field-inl.h"
 #include "class_linker.h"
diff --git a/runtime/native/java_lang_reflect_Method.cc b/runtime/native/java_lang_reflect_Method.cc
index 6f0130e..c9e8dba 100644
--- a/runtime/native/java_lang_reflect_Method.cc
+++ b/runtime/native/java_lang_reflect_Method.cc
@@ -16,6 +16,8 @@
 
 #include "java_lang_reflect_Method.h"
 
+#include "nativehelper/jni_macros.h"
+
 #include "art_method-inl.h"
 #include "base/enums.h"
 #include "class_linker.h"
diff --git a/runtime/native/java_lang_reflect_Parameter.cc b/runtime/native/java_lang_reflect_Parameter.cc
index 37aa16c..92a7ac9 100644
--- a/runtime/native/java_lang_reflect_Parameter.cc
+++ b/runtime/native/java_lang_reflect_Parameter.cc
@@ -17,6 +17,7 @@
 #include "java_lang_reflect_Parameter.h"
 
 #include "android-base/stringprintf.h"
+#include "nativehelper/jni_macros.h"
 
 #include "art_method-inl.h"
 #include "common_throws.h"
diff --git a/runtime/native/java_lang_reflect_Proxy.cc b/runtime/native/java_lang_reflect_Proxy.cc
index 0279b5f..518aaa7 100644
--- a/runtime/native/java_lang_reflect_Proxy.cc
+++ b/runtime/native/java_lang_reflect_Proxy.cc
@@ -16,6 +16,8 @@
 
 #include "java_lang_reflect_Proxy.h"
 
+#include "nativehelper/jni_macros.h"
+
 #include "class_linker.h"
 #include "jni_internal.h"
 #include "mirror/class_loader.h"
diff --git a/runtime/native/java_util_concurrent_atomic_AtomicLong.cc b/runtime/native/java_util_concurrent_atomic_AtomicLong.cc
index 4d2ea67..101f386 100644
--- a/runtime/native/java_util_concurrent_atomic_AtomicLong.cc
+++ b/runtime/native/java_util_concurrent_atomic_AtomicLong.cc
@@ -16,6 +16,8 @@
 
 #include "java_util_concurrent_atomic_AtomicLong.h"
 
+#include "nativehelper/jni_macros.h"
+
 #include "arch/instruction_set.h"
 #include "atomic.h"
 #include "jni_internal.h"
diff --git a/runtime/native/libcore_util_CharsetUtils.cc b/runtime/native/libcore_util_CharsetUtils.cc
index 4138ccc..c388ea1 100644
--- a/runtime/native/libcore_util_CharsetUtils.cc
+++ b/runtime/native/libcore_util_CharsetUtils.cc
@@ -14,15 +14,19 @@
  * limitations under the License.
  */
 
+#include "libcore_util_CharsetUtils.h"
+
+#include <string.h>
+
+#include "nativehelper/jni_macros.h"
+
 #include "jni_internal.h"
 #include "mirror/string.h"
 #include "mirror/string-inl.h"
-#include "native/libcore_util_CharsetUtils.h"
 #include "scoped_fast_native_object_access-inl.h"
 #include "ScopedPrimitiveArray.h"
 #include "unicode/utf16.h"
 
-#include <string.h>
 
 namespace art {
 
diff --git a/runtime/native/org_apache_harmony_dalvik_ddmc_DdmServer.cc b/runtime/native/org_apache_harmony_dalvik_ddmc_DdmServer.cc
index 5809708..a860977 100644
--- a/runtime/native/org_apache_harmony_dalvik_ddmc_DdmServer.cc
+++ b/runtime/native/org_apache_harmony_dalvik_ddmc_DdmServer.cc
@@ -16,6 +16,8 @@
 
 #include "org_apache_harmony_dalvik_ddmc_DdmServer.h"
 
+#include "nativehelper/jni_macros.h"
+
 #include "base/logging.h"
 #include "debugger.h"
 #include "jni_internal.h"
diff --git a/runtime/native/org_apache_harmony_dalvik_ddmc_DdmVmInternal.cc b/runtime/native/org_apache_harmony_dalvik_ddmc_DdmVmInternal.cc
index 69ef59e..ac504cc 100644
--- a/runtime/native/org_apache_harmony_dalvik_ddmc_DdmVmInternal.cc
+++ b/runtime/native/org_apache_harmony_dalvik_ddmc_DdmVmInternal.cc
@@ -16,6 +16,8 @@
 
 #include "org_apache_harmony_dalvik_ddmc_DdmVmInternal.h"
 
+#include "nativehelper/jni_macros.h"
+
 #include "base/logging.h"
 #include "base/mutex.h"
 #include "debugger.h"
diff --git a/runtime/native/sun_misc_Unsafe.cc b/runtime/native/sun_misc_Unsafe.cc
index cc5a41a..b42cedf 100644
--- a/runtime/native/sun_misc_Unsafe.cc
+++ b/runtime/native/sun_misc_Unsafe.cc
@@ -15,6 +15,14 @@
  */
 
 #include "sun_misc_Unsafe.h"
+
+#include <atomic>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+#include "nativehelper/jni_macros.h"
+
 #include "common_throws.h"
 #include "gc/accounting/card_table-inl.h"
 #include "jni_internal.h"
@@ -23,10 +31,6 @@
 #include "mirror/object-inl.h"
 #include "scoped_fast_native_object_access-inl.h"
 
-#include <unistd.h>
-#include <stdlib.h>
-#include <string.h>
-#include <atomic>
 
 namespace art {
 
diff --git a/runtime/openjdkjvmti/jvmti_weak_table.h b/runtime/openjdkjvmti/jvmti_weak_table.h
index a6fd247..be6edef 100644
--- a/runtime/openjdkjvmti/jvmti_weak_table.h
+++ b/runtime/openjdkjvmti/jvmti_weak_table.h
@@ -59,19 +59,19 @@
 
   // Remove the mapping for the given object, returning whether such a mapping existed (and the old
   // value).
-  bool Remove(art::mirror::Object* obj, /* out */ T* tag)
+  ALWAYS_INLINE bool Remove(art::mirror::Object* obj, /* out */ T* tag)
       REQUIRES_SHARED(art::Locks::mutator_lock_)
       REQUIRES(!allow_disallow_lock_);
-  bool RemoveLocked(art::mirror::Object* obj, /* out */ T* tag)
+  ALWAYS_INLINE bool RemoveLocked(art::mirror::Object* obj, /* out */ T* tag)
       REQUIRES_SHARED(art::Locks::mutator_lock_)
       REQUIRES(allow_disallow_lock_);
 
   // Set the mapping for the given object. Returns true if this overwrites an already existing
   // mapping.
-  virtual bool Set(art::mirror::Object* obj, T tag)
+  ALWAYS_INLINE virtual bool Set(art::mirror::Object* obj, T tag)
       REQUIRES_SHARED(art::Locks::mutator_lock_)
       REQUIRES(!allow_disallow_lock_);
-  virtual bool SetLocked(art::mirror::Object* obj, T tag)
+  ALWAYS_INLINE virtual bool SetLocked(art::mirror::Object* obj, T tag)
       REQUIRES_SHARED(art::Locks::mutator_lock_)
       REQUIRES(allow_disallow_lock_);
 
@@ -97,11 +97,12 @@
   }
 
   // Sweep the container. DO NOT CALL MANUALLY.
-  void Sweep(art::IsMarkedVisitor* visitor)
+  ALWAYS_INLINE void Sweep(art::IsMarkedVisitor* visitor)
       REQUIRES_SHARED(art::Locks::mutator_lock_)
       REQUIRES(!allow_disallow_lock_);
 
   // Return all objects that have a value mapping in tags.
+  ALWAYS_INLINE
   jvmtiError GetTaggedObjects(jvmtiEnv* jvmti_env,
                               jint tag_count,
                               const T* tags,
@@ -112,11 +113,11 @@
       REQUIRES(!allow_disallow_lock_);
 
   // Locking functions, to allow coarse-grained locking and amortization.
-  void Lock() ACQUIRE(allow_disallow_lock_);
-  void Unlock() RELEASE(allow_disallow_lock_);
-  void AssertLocked() ASSERT_CAPABILITY(allow_disallow_lock_);
+  ALWAYS_INLINE  void Lock() ACQUIRE(allow_disallow_lock_);
+  ALWAYS_INLINE void Unlock() RELEASE(allow_disallow_lock_);
+  ALWAYS_INLINE void AssertLocked() ASSERT_CAPABILITY(allow_disallow_lock_);
 
-  art::mirror::Object* Find(T tag)
+  ALWAYS_INLINE art::mirror::Object* Find(T tag)
       REQUIRES_SHARED(art::Locks::mutator_lock_)
       REQUIRES(!allow_disallow_lock_);
 
@@ -129,10 +130,12 @@
   virtual void HandleNullSweep(T tag ATTRIBUTE_UNUSED) {}
 
  private:
+  ALWAYS_INLINE
   bool SetLocked(art::Thread* self, art::mirror::Object* obj, T tag)
       REQUIRES_SHARED(art::Locks::mutator_lock_)
       REQUIRES(allow_disallow_lock_);
 
+  ALWAYS_INLINE
   bool RemoveLocked(art::Thread* self, art::mirror::Object* obj, /* out */ T* tag)
       REQUIRES_SHARED(art::Locks::mutator_lock_)
       REQUIRES(allow_disallow_lock_);
@@ -160,12 +163,14 @@
 
   // Slow-path for GetTag. We didn't find the object, but we might be storing from-pointers and
   // are asked to retrieve with a to-pointer.
+  ALWAYS_INLINE
   bool GetTagSlowPath(art::Thread* self, art::mirror::Object* obj, /* out */ T* result)
       REQUIRES_SHARED(art::Locks::mutator_lock_)
       REQUIRES(allow_disallow_lock_);
 
   // Update the table by doing read barriers on each element, ensuring that to-space pointers
   // are stored.
+  ALWAYS_INLINE
   void UpdateTableWithReadBarrier()
       REQUIRES_SHARED(art::Locks::mutator_lock_)
       REQUIRES(allow_disallow_lock_);
diff --git a/runtime/openjdkjvmti/ti_thread.h b/runtime/openjdkjvmti/ti_thread.h
index c7f75d8..939aea7 100644
--- a/runtime/openjdkjvmti/ti_thread.h
+++ b/runtime/openjdkjvmti/ti_thread.h
@@ -37,7 +37,7 @@
 
 namespace art {
 class ArtField;
-}
+}  // namespace art
 
 namespace openjdkjvmti {
 
diff --git a/runtime/runtime-inl.h b/runtime/runtime-inl.h
index 75c25dd..9281577 100644
--- a/runtime/runtime-inl.h
+++ b/runtime/runtime-inl.h
@@ -20,10 +20,8 @@
 #include "runtime.h"
 
 #include "art_method.h"
-#include "class_linker.h"
 #include "gc_root-inl.h"
 #include "obj_ptr-inl.h"
-#include "read_barrier-inl.h"
 
 namespace art {
 
diff --git a/runtime/runtime.cc b/runtime/runtime.cc
index 968f02a..74e291e 100644
--- a/runtime/runtime.cc
+++ b/runtime/runtime.cc
@@ -134,6 +134,7 @@
 #include "native_stack_dump.h"
 #include "oat_file.h"
 #include "oat_file_manager.h"
+#include "object_callbacks.h"
 #include "os.h"
 #include "parsed_options.h"
 #include "jit/profile_saver.h"
diff --git a/runtime/runtime.h b/runtime/runtime.h
index 4e143e0..992c5c8 100644
--- a/runtime/runtime.h
+++ b/runtime/runtime.h
@@ -34,10 +34,7 @@
 #include "experimental_flags.h"
 #include "gc_root.h"
 #include "instrumentation.h"
-#include "jobject_comparator.h"
-#include "method_reference.h"
 #include "obj_ptr.h"
-#include "object_callbacks.h"
 #include "offsets.h"
 #include "process_state.h"
 #include "quick/quick_method_frame_info.h"
@@ -79,6 +76,7 @@
 class CompilerCallbacks;
 class DexFile;
 class InternTable;
+class IsMarkedVisitor;
 class JavaVMExt;
 class LinearAlloc;
 class MemMap;
diff --git a/runtime/signal_catcher.cc b/runtime/signal_catcher.cc
index e3dfc74..8c934d5 100644
--- a/runtime/signal_catcher.cc
+++ b/runtime/signal_catcher.cc
@@ -117,7 +117,7 @@
                                        android::base::unique_fd* output_fd) {
   if (use_tombstoned_stack_trace_fd_) {
 #if defined(ART_TARGET_ANDROID)
-    return tombstoned_connect(getpid(), tombstone_fd, output_fd, false /* is_native_crash */);
+    return tombstoned_connect(getpid(), tombstone_fd, output_fd, kDebuggerdJavaBacktrace);
 #else
     UNUSED(tombstone_fd);
     UNUSED(output_fd);
diff --git a/runtime/thread_list.h b/runtime/thread_list.h
index 3375746..0ce1d78 100644
--- a/runtime/thread_list.h
+++ b/runtime/thread_list.h
@@ -34,7 +34,7 @@
 namespace gc {
   namespace collector {
     class GarbageCollector;
-  }  // namespac collector
+  }  // namespace collector
   class GcPauseListener;
 }  // namespace gc
 class Closure;
diff --git a/runtime/ti/agent.h b/runtime/ti/agent.h
index b5ecba1..f98e387 100644
--- a/runtime/ti/agent.h
+++ b/runtime/ti/agent.h
@@ -20,8 +20,7 @@
 #include <dlfcn.h>
 #include <jni.h>  // for jint, JavaVM* etc declarations
 
-#include "runtime.h"
-#include "utils.h"
+#include "base/logging.h"
 
 namespace art {
 namespace ti {
diff --git a/runtime/transaction.h b/runtime/transaction.h
index 0333fe8..921de03 100644
--- a/runtime/transaction.h
+++ b/runtime/transaction.h
@@ -36,7 +36,7 @@
 class DexCache;
 class Object;
 class String;
-}
+}  // namespace mirror
 class InternTable;
 
 class Transaction FINAL {
diff --git a/compiler/utils/type_reference.h b/runtime/type_reference.h
similarity index 85%
rename from compiler/utils/type_reference.h
rename to runtime/type_reference.h
index a0fa1a4..b7e964b 100644
--- a/compiler/utils/type_reference.h
+++ b/runtime/type_reference.h
@@ -14,8 +14,8 @@
  * limitations under the License.
  */
 
-#ifndef ART_COMPILER_UTILS_TYPE_REFERENCE_H_
-#define ART_COMPILER_UTILS_TYPE_REFERENCE_H_
+#ifndef ART_RUNTIME_TYPE_REFERENCE_H_
+#define ART_RUNTIME_TYPE_REFERENCE_H_
 
 #include <stdint.h>
 
@@ -29,7 +29,9 @@
 
 // A type is located by its DexFile and the string_ids_ table index into that DexFile.
 struct TypeReference {
-  TypeReference(const DexFile* file, dex::TypeIndex index) : dex_file(file), type_index(index) { }
+  TypeReference(const DexFile* file = nullptr, dex::TypeIndex index = dex::TypeIndex())
+      : dex_file(file),
+        type_index(index) {}
 
   const DexFile* dex_file;
   dex::TypeIndex type_index;
@@ -48,4 +50,4 @@
 
 }  // namespace art
 
-#endif  // ART_COMPILER_UTILS_TYPE_REFERENCE_H_
+#endif  // ART_RUNTIME_TYPE_REFERENCE_H_
diff --git a/runtime/verifier/method_verifier.cc b/runtime/verifier/method_verifier.cc
index 81bf293..7490611 100644
--- a/runtime/verifier/method_verifier.cc
+++ b/runtime/verifier/method_verifier.cc
@@ -1258,7 +1258,7 @@
 }
 
 inline bool MethodVerifier::CheckRegisterIndex(uint32_t idx) {
-  if (idx >= code_item_->registers_size_) {
+  if (UNLIKELY(idx >= code_item_->registers_size_)) {
     Fail(VERIFY_ERROR_BAD_CLASS_HARD) << "register index out of range (" << idx << " >= "
                                       << code_item_->registers_size_ << ")";
     return false;
@@ -1267,7 +1267,7 @@
 }
 
 inline bool MethodVerifier::CheckWideRegisterIndex(uint32_t idx) {
-  if (idx + 1 >= code_item_->registers_size_) {
+  if (UNLIKELY(idx + 1 >= code_item_->registers_size_)) {
     Fail(VERIFY_ERROR_BAD_CLASS_HARD) << "wide register index out of range (" << idx
                                       << "+1 >= " << code_item_->registers_size_ << ")";
     return false;
@@ -1276,7 +1276,7 @@
 }
 
 inline bool MethodVerifier::CheckFieldIndex(uint32_t idx) {
-  if (idx >= dex_file_->GetHeader().field_ids_size_) {
+  if (UNLIKELY(idx >= dex_file_->GetHeader().field_ids_size_)) {
     Fail(VERIFY_ERROR_BAD_CLASS_HARD) << "bad field index " << idx << " (max "
                                       << dex_file_->GetHeader().field_ids_size_ << ")";
     return false;
@@ -1285,7 +1285,7 @@
 }
 
 inline bool MethodVerifier::CheckMethodIndex(uint32_t idx) {
-  if (idx >= dex_file_->GetHeader().method_ids_size_) {
+  if (UNLIKELY(idx >= dex_file_->GetHeader().method_ids_size_)) {
     Fail(VERIFY_ERROR_BAD_CLASS_HARD) << "bad method index " << idx << " (max "
                                       << dex_file_->GetHeader().method_ids_size_ << ")";
     return false;
@@ -1294,17 +1294,17 @@
 }
 
 inline bool MethodVerifier::CheckNewInstance(dex::TypeIndex idx) {
-  if (idx.index_ >= dex_file_->GetHeader().type_ids_size_) {
+  if (UNLIKELY(idx.index_ >= dex_file_->GetHeader().type_ids_size_)) {
     Fail(VERIFY_ERROR_BAD_CLASS_HARD) << "bad type index " << idx.index_ << " (max "
                                       << dex_file_->GetHeader().type_ids_size_ << ")";
     return false;
   }
   // We don't need the actual class, just a pointer to the class name.
   const char* descriptor = dex_file_->StringByTypeIdx(idx);
-  if (descriptor[0] != 'L') {
+  if (UNLIKELY(descriptor[0] != 'L')) {
     Fail(VERIFY_ERROR_BAD_CLASS_HARD) << "can't call new-instance on type '" << descriptor << "'";
     return false;
-  } else if (strcmp(descriptor, "Ljava/lang/Class;") == 0) {
+  } else if (UNLIKELY(strcmp(descriptor, "Ljava/lang/Class;") == 0)) {
     // An unlikely new instance on Class is not allowed. Fall back to interpreter to ensure an
     // exception is thrown when this statement is executed (compiled code would not do that).
     Fail(VERIFY_ERROR_INSTANTIATION);
@@ -1313,7 +1313,7 @@
 }
 
 inline bool MethodVerifier::CheckPrototypeIndex(uint32_t idx) {
-  if (idx >= dex_file_->GetHeader().proto_ids_size_) {
+  if (UNLIKELY(idx >= dex_file_->GetHeader().proto_ids_size_)) {
     Fail(VERIFY_ERROR_BAD_CLASS_HARD) << "bad prototype index " << idx << " (max "
                                       << dex_file_->GetHeader().proto_ids_size_ << ")";
     return false;
@@ -1322,7 +1322,7 @@
 }
 
 inline bool MethodVerifier::CheckStringIndex(uint32_t idx) {
-  if (idx >= dex_file_->GetHeader().string_ids_size_) {
+  if (UNLIKELY(idx >= dex_file_->GetHeader().string_ids_size_)) {
     Fail(VERIFY_ERROR_BAD_CLASS_HARD) << "bad string index " << idx << " (max "
                                       << dex_file_->GetHeader().string_ids_size_ << ")";
     return false;
@@ -1331,7 +1331,7 @@
 }
 
 inline bool MethodVerifier::CheckTypeIndex(dex::TypeIndex idx) {
-  if (idx.index_ >= dex_file_->GetHeader().type_ids_size_) {
+  if (UNLIKELY(idx.index_ >= dex_file_->GetHeader().type_ids_size_)) {
     Fail(VERIFY_ERROR_BAD_CLASS_HARD) << "bad type index " << idx.index_ << " (max "
                                       << dex_file_->GetHeader().type_ids_size_ << ")";
     return false;
@@ -1340,7 +1340,7 @@
 }
 
 bool MethodVerifier::CheckNewArray(dex::TypeIndex idx) {
-  if (idx.index_ >= dex_file_->GetHeader().type_ids_size_) {
+  if (UNLIKELY(idx.index_ >= dex_file_->GetHeader().type_ids_size_)) {
     Fail(VERIFY_ERROR_BAD_CLASS_HARD) << "bad type index " << idx.index_ << " (max "
                                       << dex_file_->GetHeader().type_ids_size_ << ")";
     return false;
@@ -1351,12 +1351,12 @@
   while (*cp++ == '[') {
     bracket_count++;
   }
-  if (bracket_count == 0) {
+  if (UNLIKELY(bracket_count == 0)) {
     /* The given class must be an array type. */
     Fail(VERIFY_ERROR_BAD_CLASS_HARD)
         << "can't new-array class '" << descriptor << "' (not an array)";
     return false;
-  } else if (bracket_count > 255) {
+  } else if (UNLIKELY(bracket_count > 255)) {
     /* It is illegal to create an array of more than 255 dimensions. */
     Fail(VERIFY_ERROR_BAD_CLASS_HARD)
         << "can't new-array class '" << descriptor << "' (exceeds limit)";
@@ -1374,8 +1374,8 @@
   DCHECK_LT(cur_offset, insn_count);
   /* make sure the start of the array data table is in range */
   array_data_offset = insns[1] | (static_cast<int32_t>(insns[2]) << 16);
-  if (static_cast<int32_t>(cur_offset) + array_data_offset < 0 ||
-      cur_offset + array_data_offset + 2 >= insn_count) {
+  if (UNLIKELY(static_cast<int32_t>(cur_offset) + array_data_offset < 0 ||
+               cur_offset + array_data_offset + 2 >= insn_count)) {
     Fail(VERIFY_ERROR_BAD_CLASS_HARD) << "invalid array data start: at " << cur_offset
                                       << ", data offset " << array_data_offset
                                       << ", count " << insn_count;
@@ -1384,14 +1384,14 @@
   /* offset to array data table is a relative branch-style offset */
   array_data = insns + array_data_offset;
   // Make sure the table is at an even dex pc, that is, 32-bit aligned.
-  if (!IsAligned<4>(array_data)) {
+  if (UNLIKELY(!IsAligned<4>(array_data))) {
     Fail(VERIFY_ERROR_BAD_CLASS_HARD) << "unaligned array data table: at " << cur_offset
                                       << ", data offset " << array_data_offset;
     return false;
   }
   // Make sure the array-data is marked as an opcode. This ensures that it was reached when
   // traversing the code item linearly. It is an approximation for a by-spec padding value.
-  if (!GetInstructionFlags(cur_offset + array_data_offset).IsOpcode()) {
+  if (UNLIKELY(!GetInstructionFlags(cur_offset + array_data_offset).IsOpcode())) {
     Fail(VERIFY_ERROR_BAD_CLASS_HARD) << "array data table at " << cur_offset
                                       << ", data offset " << array_data_offset
                                       << " not correctly visited, probably bad padding.";
@@ -1402,7 +1402,7 @@
   uint32_t value_count = *reinterpret_cast<const uint32_t*>(&array_data[2]);
   uint32_t table_size = 4 + (value_width * value_count + 1) / 2;
   /* make sure the end of the switch is in range */
-  if (cur_offset + array_data_offset + table_size > insn_count) {
+  if (UNLIKELY(cur_offset + array_data_offset + table_size > insn_count)) {
     Fail(VERIFY_ERROR_BAD_CLASS_HARD) << "invalid array data end: at " << cur_offset
                                       << ", data offset " << array_data_offset << ", end "
                                       << cur_offset + array_data_offset + table_size
@@ -1418,23 +1418,23 @@
   if (!GetBranchOffset(cur_offset, &offset, &isConditional, &selfOkay)) {
     return false;
   }
-  if (!selfOkay && offset == 0) {
+  if (UNLIKELY(!selfOkay && offset == 0)) {
     Fail(VERIFY_ERROR_BAD_CLASS_HARD) << "branch offset of zero not allowed at"
                                       << reinterpret_cast<void*>(cur_offset);
     return false;
   }
   // Check for 32-bit overflow. This isn't strictly necessary if we can depend on the runtime
   // to have identical "wrap-around" behavior, but it's unwise to depend on that.
-  if (((int64_t) cur_offset + (int64_t) offset) != (int64_t) (cur_offset + offset)) {
+  if (UNLIKELY(((int64_t) cur_offset + (int64_t) offset) != (int64_t) (cur_offset + offset))) {
     Fail(VERIFY_ERROR_BAD_CLASS_HARD) << "branch target overflow "
                                       << reinterpret_cast<void*>(cur_offset) << " +" << offset;
     return false;
   }
   const uint32_t insn_count = code_item_->insns_size_in_code_units_;
   int32_t abs_offset = cur_offset + offset;
-  if (abs_offset < 0 ||
-      (uint32_t) abs_offset >= insn_count ||
-      !GetInstructionFlags(abs_offset).IsOpcode()) {
+  if (UNLIKELY(abs_offset < 0 ||
+               (uint32_t) abs_offset >= insn_count ||
+               !GetInstructionFlags(abs_offset).IsOpcode())) {
     Fail(VERIFY_ERROR_BAD_CLASS_HARD) << "invalid branch target " << offset << " (-> "
                                       << reinterpret_cast<void*>(abs_offset) << ") at "
                                       << reinterpret_cast<void*>(cur_offset);
@@ -1487,8 +1487,8 @@
   const uint16_t* insns = code_item_->insns_ + cur_offset;
   /* make sure the start of the switch is in range */
   int32_t switch_offset = insns[1] | (static_cast<int32_t>(insns[2]) << 16);
-  if (static_cast<int32_t>(cur_offset) + switch_offset < 0 ||
-      cur_offset + switch_offset + 2 > insn_count) {
+  if (UNLIKELY(static_cast<int32_t>(cur_offset) + switch_offset < 0 ||
+               cur_offset + switch_offset + 2 > insn_count)) {
     Fail(VERIFY_ERROR_BAD_CLASS_HARD) << "invalid switch start: at " << cur_offset
                                       << ", switch offset " << switch_offset
                                       << ", count " << insn_count;
@@ -1497,14 +1497,14 @@
   /* offset to switch table is a relative branch-style offset */
   const uint16_t* switch_insns = insns + switch_offset;
   // Make sure the table is at an even dex pc, that is, 32-bit aligned.
-  if (!IsAligned<4>(switch_insns)) {
+  if (UNLIKELY(!IsAligned<4>(switch_insns))) {
     Fail(VERIFY_ERROR_BAD_CLASS_HARD) << "unaligned switch table: at " << cur_offset
                                       << ", switch offset " << switch_offset;
     return false;
   }
   // Make sure the switch data is marked as an opcode. This ensures that it was reached when
   // traversing the code item linearly. It is an approximation for a by-spec padding value.
-  if (!GetInstructionFlags(cur_offset + switch_offset).IsOpcode()) {
+  if (UNLIKELY(!GetInstructionFlags(cur_offset + switch_offset).IsOpcode())) {
     Fail(VERIFY_ERROR_BAD_CLASS_HARD) << "switch table at " << cur_offset
                                       << ", switch offset " << switch_offset
                                       << " not correctly visited, probably bad padding.";
@@ -1526,14 +1526,14 @@
     expected_signature = Instruction::kSparseSwitchSignature;
   }
   uint32_t table_size = targets_offset + switch_count * 2;
-  if (switch_insns[0] != expected_signature) {
+  if (UNLIKELY(switch_insns[0] != expected_signature)) {
     Fail(VERIFY_ERROR_BAD_CLASS_HARD)
         << StringPrintf("wrong signature for switch table (%x, wanted %x)",
                         switch_insns[0], expected_signature);
     return false;
   }
   /* make sure the end of the switch is in range */
-  if (cur_offset + switch_offset + table_size > (uint32_t) insn_count) {
+  if (UNLIKELY(cur_offset + switch_offset + table_size > (uint32_t) insn_count)) {
     Fail(VERIFY_ERROR_BAD_CLASS_HARD) << "invalid switch end: at " << cur_offset
                                       << ", switch offset " << switch_offset
                                       << ", end " << (cur_offset + switch_offset + table_size)
@@ -1548,7 +1548,7 @@
       int32_t first_key = switch_insns[keys_offset] | (switch_insns[keys_offset + 1] << 16);
       int32_t max_first_key =
           std::numeric_limits<int32_t>::max() - (static_cast<int32_t>(switch_count) - 1);
-      if (first_key > max_first_key) {
+      if (UNLIKELY(first_key > max_first_key)) {
         Fail(VERIFY_ERROR_BAD_CLASS_HARD) << "invalid packed switch: first_key=" << first_key
                                           << ", switch_count=" << switch_count;
         return false;
@@ -1560,7 +1560,7 @@
         int32_t key =
             static_cast<int32_t>(switch_insns[keys_offset + targ * 2]) |
             static_cast<int32_t>(switch_insns[keys_offset + targ * 2 + 1] << 16);
-        if (key <= last_key) {
+        if (UNLIKELY(key <= last_key)) {
           Fail(VERIFY_ERROR_BAD_CLASS_HARD) << "invalid sparse switch: last key=" << last_key
                                             << ", this=" << key;
           return false;
@@ -1574,9 +1574,9 @@
     int32_t offset = static_cast<int32_t>(switch_insns[targets_offset + targ * 2]) |
                      static_cast<int32_t>(switch_insns[targets_offset + targ * 2 + 1] << 16);
     int32_t abs_offset = cur_offset + offset;
-    if (abs_offset < 0 ||
-        abs_offset >= static_cast<int32_t>(insn_count) ||
-        !GetInstructionFlags(abs_offset).IsOpcode()) {
+    if (UNLIKELY(abs_offset < 0 ||
+                 abs_offset >= static_cast<int32_t>(insn_count) ||
+                 !GetInstructionFlags(abs_offset).IsOpcode())) {
       Fail(VERIFY_ERROR_BAD_CLASS_HARD) << "invalid switch target " << offset
                                         << " (-> " << reinterpret_cast<void*>(abs_offset) << ") at "
                                         << reinterpret_cast<void*>(cur_offset)
@@ -1591,7 +1591,7 @@
 bool MethodVerifier::CheckVarArgRegs(uint32_t vA, uint32_t arg[]) {
   uint16_t registers_size = code_item_->registers_size_;
   for (uint32_t idx = 0; idx < vA; idx++) {
-    if (arg[idx] >= registers_size) {
+    if (UNLIKELY(arg[idx] >= registers_size)) {
       Fail(VERIFY_ERROR_BAD_CLASS_HARD) << "invalid reg index (" << arg[idx]
                                         << ") in non-range invoke (>= " << registers_size << ")";
       return false;
@@ -1605,7 +1605,7 @@
   uint16_t registers_size = code_item_->registers_size_;
   // vA/vC are unsigned 8-bit/16-bit quantities for /range instructions, so there's no risk of
   // integer overflow when adding them here.
-  if (vA + vC > registers_size) {
+  if (UNLIKELY(vA + vC > registers_size)) {
     Fail(VERIFY_ERROR_BAD_CLASS_HARD) << "invalid reg index " << vA << "+" << vC
                                       << " in range invoke (> " << registers_size << ")";
     return false;
diff --git a/runtime/verifier/method_verifier.h b/runtime/verifier/method_verifier.h
index b34a3af..9ef98f7 100644
--- a/runtime/verifier/method_verifier.h
+++ b/runtime/verifier/method_verifier.h
@@ -37,12 +37,17 @@
 
 namespace art {
 
+class ClassLinker;
 class CompilerCallbacks;
 class Instruction;
 struct ReferenceMap2Visitor;
 class Thread;
 class VariableIndentationOutputStream;
 
+namespace mirror {
+class DexCache;
+}  // namespace mirror
+
 namespace verifier {
 
 class MethodVerifier;
diff --git a/runtime/verifier/reg_type_cache-inl.h b/runtime/verifier/reg_type_cache-inl.h
index 68af62e..b57a2c8 100644
--- a/runtime/verifier/reg_type_cache-inl.h
+++ b/runtime/verifier/reg_type_cache-inl.h
@@ -43,6 +43,43 @@
   return FromCat1NonSmallConstant(value, precise);
 }
 
+inline const BooleanType& RegTypeCache::Boolean() {
+  return *BooleanType::GetInstance();
+}
+inline const ByteType& RegTypeCache::Byte() {
+  return *ByteType::GetInstance();
+}
+inline const CharType& RegTypeCache::Char() {
+  return *CharType::GetInstance();
+}
+inline const ShortType& RegTypeCache::Short() {
+  return *ShortType::GetInstance();
+}
+inline const IntegerType& RegTypeCache::Integer() {
+  return *IntegerType::GetInstance();
+}
+inline const FloatType& RegTypeCache::Float() {
+  return *FloatType::GetInstance();
+}
+inline const LongLoType& RegTypeCache::LongLo() {
+  return *LongLoType::GetInstance();
+}
+inline const LongHiType& RegTypeCache::LongHi() {
+  return *LongHiType::GetInstance();
+}
+inline const DoubleLoType& RegTypeCache::DoubleLo() {
+  return *DoubleLoType::GetInstance();
+}
+inline const DoubleHiType& RegTypeCache::DoubleHi() {
+  return *DoubleHiType::GetInstance();
+}
+inline const UndefinedType& RegTypeCache::Undefined() {
+  return *UndefinedType::GetInstance();
+}
+inline const ConflictType& RegTypeCache::Conflict() {
+  return *ConflictType::GetInstance();
+}
+
 inline const ImpreciseConstType& RegTypeCache::ByteConstant() {
   const ConstantType& result = FromCat1Const(std::numeric_limits<jbyte>::min(), false);
   DCHECK(result.IsImpreciseConstant());
diff --git a/runtime/verifier/reg_type_cache.h b/runtime/verifier/reg_type_cache.h
index df0fe3d..37f8a1f 100644
--- a/runtime/verifier/reg_type_cache.h
+++ b/runtime/verifier/reg_type_cache.h
@@ -17,15 +17,14 @@
 #ifndef ART_RUNTIME_VERIFIER_REG_TYPE_CACHE_H_
 #define ART_RUNTIME_VERIFIER_REG_TYPE_CACHE_H_
 
+#include <stdint.h>
+#include <vector>
+
 #include "base/casts.h"
 #include "base/macros.h"
 #include "base/scoped_arena_containers.h"
-#include "object_callbacks.h"
-#include "reg_type.h"
-#include "runtime.h"
-
-#include <stdint.h>
-#include <vector>
+#include "gc_root.h"
+#include "primitive.h"
 
 namespace art {
 namespace mirror {
@@ -37,7 +36,24 @@
 
 namespace verifier {
 
+class BooleanType;
+class ByteType;
+class CharType;
+class ConflictType;
+class ConstantType;
+class DoubleHiType;
+class DoubleLoType;
+class FloatType;
+class ImpreciseConstType;
+class IntegerType;
+class LongHiType;
+class LongLoType;
+class PreciseConstType;
+class PreciseReferenceType;
 class RegType;
+class ShortType;
+class UndefinedType;
+class UninitializedType;
 
 // Use 8 bytes since that is the default arena allocator alignment.
 static constexpr size_t kDefaultArenaBitVectorBytes = 8;
@@ -90,42 +106,18 @@
   size_t GetCacheSize() {
     return entries_.size();
   }
-  const BooleanType& Boolean() REQUIRES_SHARED(Locks::mutator_lock_) {
-    return *BooleanType::GetInstance();
-  }
-  const ByteType& Byte() REQUIRES_SHARED(Locks::mutator_lock_) {
-    return *ByteType::GetInstance();
-  }
-  const CharType& Char() REQUIRES_SHARED(Locks::mutator_lock_) {
-    return *CharType::GetInstance();
-  }
-  const ShortType& Short() REQUIRES_SHARED(Locks::mutator_lock_) {
-    return *ShortType::GetInstance();
-  }
-  const IntegerType& Integer() REQUIRES_SHARED(Locks::mutator_lock_) {
-    return *IntegerType::GetInstance();
-  }
-  const FloatType& Float() REQUIRES_SHARED(Locks::mutator_lock_) {
-    return *FloatType::GetInstance();
-  }
-  const LongLoType& LongLo() REQUIRES_SHARED(Locks::mutator_lock_) {
-    return *LongLoType::GetInstance();
-  }
-  const LongHiType& LongHi() REQUIRES_SHARED(Locks::mutator_lock_) {
-    return *LongHiType::GetInstance();
-  }
-  const DoubleLoType& DoubleLo() REQUIRES_SHARED(Locks::mutator_lock_) {
-    return *DoubleLoType::GetInstance();
-  }
-  const DoubleHiType& DoubleHi() REQUIRES_SHARED(Locks::mutator_lock_) {
-    return *DoubleHiType::GetInstance();
-  }
-  const UndefinedType& Undefined() REQUIRES_SHARED(Locks::mutator_lock_) {
-    return *UndefinedType::GetInstance();
-  }
-  const ConflictType& Conflict() {
-    return *ConflictType::GetInstance();
-  }
+  const BooleanType& Boolean() REQUIRES_SHARED(Locks::mutator_lock_);
+  const ByteType& Byte() REQUIRES_SHARED(Locks::mutator_lock_);
+  const CharType& Char() REQUIRES_SHARED(Locks::mutator_lock_);
+  const ShortType& Short() REQUIRES_SHARED(Locks::mutator_lock_);
+  const IntegerType& Integer() REQUIRES_SHARED(Locks::mutator_lock_);
+  const FloatType& Float() REQUIRES_SHARED(Locks::mutator_lock_);
+  const LongLoType& LongLo() REQUIRES_SHARED(Locks::mutator_lock_);
+  const LongHiType& LongHi() REQUIRES_SHARED(Locks::mutator_lock_);
+  const DoubleLoType& DoubleLo() REQUIRES_SHARED(Locks::mutator_lock_);
+  const DoubleHiType& DoubleHi() REQUIRES_SHARED(Locks::mutator_lock_);
+  const UndefinedType& Undefined() REQUIRES_SHARED(Locks::mutator_lock_);
+  const ConflictType& Conflict();
 
   const PreciseReferenceType& JavaLangClass() REQUIRES_SHARED(Locks::mutator_lock_);
   const PreciseReferenceType& JavaLangString() REQUIRES_SHARED(Locks::mutator_lock_);
diff --git a/runtime/verifier/verifier_deps.h b/runtime/verifier/verifier_deps.h
index d69e4dc..70ce0c4 100644
--- a/runtime/verifier/verifier_deps.h
+++ b/runtime/verifier/verifier_deps.h
@@ -39,7 +39,7 @@
 namespace mirror {
 class Class;
 class ClassLoader;
-}
+}  // namespace mirror
 
 namespace verifier {
 
diff --git a/test/137-cfi/cfi.cc b/test/137-cfi/cfi.cc
index 3b237f4..1ed1f5a 100644
--- a/test/137-cfi/cfi.cc
+++ b/test/137-cfi/cfi.cc
@@ -33,6 +33,7 @@
 #include "gc/heap.h"
 #include "gc/space/image_space.h"
 #include "oat_file.h"
+#include "runtime.h"
 #include "utils.h"
 
 namespace art {
diff --git a/test/ManyMethods/ManyMethods.java b/test/ManyMethods/ManyMethods.java
new file mode 100644
index 0000000..b3a57f6
--- /dev/null
+++ b/test/ManyMethods/ManyMethods.java
@@ -0,0 +1,105 @@
+/*
+ * Copyright (C) 2017 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.
+ */
+
+class ManyMethods {
+  static class Strings {
+    public static String msg0 = "Hello World";
+    public static String msg1 = "Hello World1";
+    public static String msg2 = "Hello World2";
+    public static String msg3 = "Hello World3";
+    public static String msg4 = "Hello World4";
+    public static String msg5 = "Hello World5";
+    public static String msg6 = "Hello World6";
+    public static String msg7 = "Hello World7";
+    public static String msg8 = "Hello World8";
+    public static String msg9 = "Hello World9";
+  }
+
+  static class Printer {
+    static void Print(String s) {
+      System.out.println(s);
+    }
+  }
+
+  static class Printer2 {
+    static void Print(String s) {
+      System.out.println("AAA" + s);
+    }
+  }
+
+  public static void Print0() {
+    Printer.Print(Strings.msg0);
+  }
+
+  public static void Print1() {
+    Printer.Print(Strings.msg1);
+  }
+
+  public static void Print2() {
+    Printer.Print(Strings.msg2);
+  }
+
+  public static void Print3() {
+    Printer.Print(Strings.msg1);
+  }
+
+  public static void Print4() {
+    Printer.Print(Strings.msg2);
+  }
+
+  public static void Print5() {
+    Printer.Print(Strings.msg3);
+  }
+
+  public static void Print6() {
+    Printer2.Print(Strings.msg4);
+  }
+
+  public static void Print7() {
+    Printer.Print(Strings.msg5);
+  }
+
+  public static void Print8() {
+    Printer.Print(Strings.msg6);
+  }
+
+  public static void Print9() {
+    Printer2.Print(Strings.msg7);
+  }
+
+  public static void Print10() {
+    Printer2.Print(Strings.msg8);
+  }
+
+  public static void Print11() {
+    Printer.Print(Strings.msg9);
+  }
+
+  public static void main(String args[]) {
+    Print0();
+    Print1();
+    Print2();
+    Print3();
+    Print4();
+    Print5();
+    Print6();
+    Print7();
+    Print8();
+    Print9();
+    Print10();
+    Print11();
+  }
+}
diff --git a/tools/ahat/README.txt b/tools/ahat/README.txt
index 3049871..38556ab 100644
--- a/tools/ahat/README.txt
+++ b/tools/ahat/README.txt
@@ -75,7 +75,10 @@
  * Instance.isRoot and Instance.getRootTypes.
 
 Release History:
- 1.2 Pending
+ 1.3 Pending
+
+ 1.2 May 26, 2017
+   Show registered native sizes of objects.
    Simplify presentation of sample path from gc root.
 
  1.1 Feb 21, 2017
diff --git a/tools/ahat/src/DocString.java b/tools/ahat/src/DocString.java
index c6303c8..7970bf8 100644
--- a/tools/ahat/src/DocString.java
+++ b/tools/ahat/src/DocString.java
@@ -126,6 +126,23 @@
   }
 
   /**
+   * Standard formatted DocString for describing a size.
+   *
+   * Nothing is printed for a size of zero.
+   * Set isPlaceHolder to true to indicate that the size field corresponds to
+   * for a place holder object that should be annotated specially.
+   */
+  public static DocString size(long size, boolean isPlaceHolder) {
+    DocString string = new DocString();
+    if (isPlaceHolder) {
+      string.append(DocString.removed("del"));
+    } else if (size != 0) {
+      string.appendFormat("%,14d", size);
+    }
+    return string;
+  }
+
+  /**
    * Standard formatted DocString for describing a change in size relative to
    * a baseline.
    * @param noCurrent - whether no current object exists.
diff --git a/tools/ahat/src/DominatedList.java b/tools/ahat/src/DominatedList.java
index f73e3ca..75133b2 100644
--- a/tools/ahat/src/DominatedList.java
+++ b/tools/ahat/src/DominatedList.java
@@ -55,7 +55,7 @@
 
     @Override
     public long getSize(AhatInstance element, AhatHeap heap) {
-      return element.getRetainedSize(heap);
+      return element.getRetainedSize(heap).getSize();
     }
 
     @Override
diff --git a/tools/ahat/src/HeapTable.java b/tools/ahat/src/HeapTable.java
index 9abbe4a..b04f2ae 100644
--- a/tools/ahat/src/HeapTable.java
+++ b/tools/ahat/src/HeapTable.java
@@ -45,16 +45,6 @@
     List<ValueConfig<T>> getValueConfigs();
   }
 
-  private static DocString sizeString(long size, boolean isPlaceHolder) {
-    DocString string = new DocString();
-    if (isPlaceHolder) {
-      string.append(DocString.removed("del"));
-    } else if (size != 0) {
-      string.appendFormat("%,14d", size);
-    }
-    return string;
-  }
-
   /**
    * Render the table to the given document.
    * @param query - The page query.
@@ -100,10 +90,10 @@
         long basesize = config.getSize(base, heap.getBaseline());
         total += size;
         basetotal += basesize;
-        vals.add(sizeString(size, elem.isPlaceHolder()));
+        vals.add(DocString.size(size, elem.isPlaceHolder()));
         vals.add(DocString.delta(elem.isPlaceHolder(), base.isPlaceHolder(), size, basesize));
       }
-      vals.add(sizeString(total, elem.isPlaceHolder()));
+      vals.add(DocString.size(total, elem.isPlaceHolder()));
       vals.add(DocString.delta(elem.isPlaceHolder(), base.isPlaceHolder(), total, basetotal));
 
       for (ValueConfig<T> value : values) {
@@ -140,10 +130,10 @@
         long basesize = basesummary.get(heap);
         total += size;
         basetotal += basesize;
-        vals.add(sizeString(size, false));
+        vals.add(DocString.size(size, false));
         vals.add(DocString.delta(false, false, size, basesize));
       }
-      vals.add(sizeString(total, false));
+      vals.add(DocString.size(total, false));
       vals.add(DocString.delta(false, false, total, basetotal));
 
       for (ValueConfig<T> value : values) {
@@ -159,7 +149,7 @@
   public static <T extends Diffable<T>> boolean hasNonZeroEntry(AhatHeap heap,
       TableConfig<T> config, List<T> elements) {
     AhatHeap baseheap = heap.getBaseline();
-    if (heap.getSize() > 0 || baseheap.getSize() > 0) {
+    if (!heap.getSize().isZero() || !baseheap.getSize().isZero()) {
       for (T element : elements) {
         if (config.getSize(element, heap) > 0 ||
             config.getSize(element.getBaseline(), baseheap) > 0) {
diff --git a/tools/ahat/src/ObjectHandler.java b/tools/ahat/src/ObjectHandler.java
index b1d7904..d6f1faa 100644
--- a/tools/ahat/src/ObjectHandler.java
+++ b/tools/ahat/src/ObjectHandler.java
@@ -70,16 +70,6 @@
     doc.descriptions();
     doc.description(DocString.text("Class"), Summarizer.summarize(cls));
 
-    DocString sizeDescription = DocString.format("%,14d ", inst.getSize());
-    sizeDescription.appendDelta(false, base.isPlaceHolder(),
-        inst.getSize(), base.getSize());
-    doc.description(DocString.text("Size"), sizeDescription);
-
-    DocString rsizeDescription = DocString.format("%,14d ", inst.getTotalRetainedSize());
-    rsizeDescription.appendDelta(false, base.isPlaceHolder(),
-        inst.getTotalRetainedSize(), base.getTotalRetainedSize());
-    doc.description(DocString.text("Retained Size"), rsizeDescription);
-
     doc.description(DocString.text("Heap"), DocString.text(inst.getHeap().getName()));
 
     Collection<String> rootTypes = inst.getRootTypes();
@@ -96,6 +86,13 @@
 
     doc.end();
 
+    doc.section("Object Size");
+    SizeTable.table(doc, new Column(""), inst != base && !base.isPlaceHolder());
+    SizeTable.row(doc, DocString.text("Shallow"), inst.getSize(), base.getSize());
+    SizeTable.row(doc, DocString.text("Retained"),
+        inst.getTotalRetainedSize(), base.getTotalRetainedSize());
+    SizeTable.end(doc);
+
     printBitmap(doc, inst);
     if (inst.isClassInstance()) {
       printClassInstanceFields(doc, query, inst.asClassInstance());
diff --git a/tools/ahat/src/ObjectsHandler.java b/tools/ahat/src/ObjectsHandler.java
index 3062d23..86d48f1 100644
--- a/tools/ahat/src/ObjectsHandler.java
+++ b/tools/ahat/src/ObjectsHandler.java
@@ -54,23 +54,18 @@
 
     doc.title("Objects");
 
-    doc.table(
-        new Column("Size", Column.Align.RIGHT),
-        new Column("Δ", Column.Align.RIGHT, mSnapshot.isDiffed()),
+    SizeTable.table(doc, mSnapshot.isDiffed(),
         new Column("Heap"),
         new Column("Object"));
 
     SubsetSelector<AhatInstance> selector = new SubsetSelector(query, OBJECTS_ID, insts);
     for (AhatInstance inst : selector.selected()) {
       AhatInstance base = inst.getBaseline();
-      doc.row(
-          DocString.format("%,14d", inst.getSize()),
-          DocString.delta(inst.isPlaceHolder(), base.isPlaceHolder(),
-            inst.getSize(), base.getSize()),
+      SizeTable.row(doc, inst.getSize(), base.getSize(),
           DocString.text(inst.getHeap().getName()),
           Summarizer.summarize(inst));
     }
-    doc.end();
+    SizeTable.end(doc);
     selector.render(doc);
   }
 }
diff --git a/tools/ahat/src/OverviewHandler.java b/tools/ahat/src/OverviewHandler.java
index ea305c4..c9f8425 100644
--- a/tools/ahat/src/OverviewHandler.java
+++ b/tools/ahat/src/OverviewHandler.java
@@ -18,16 +18,12 @@
 
 import com.android.ahat.heapdump.AhatHeap;
 import com.android.ahat.heapdump.AhatSnapshot;
-import com.android.ahat.heapdump.Diffable;
+import com.android.ahat.heapdump.Size;
 import java.io.File;
 import java.io.IOException;
-import java.util.Collections;
-import java.util.List;
 
 class OverviewHandler implements AhatHandler {
 
-  private static final String OVERVIEW_ID = "overview";
-
   private AhatSnapshot mSnapshot;
   private File mHprof;
   private File mBaseHprof;
@@ -53,39 +49,27 @@
     }
     doc.end();
 
-    doc.section("Heap Sizes");
-    printHeapSizes(doc, query);
+    doc.section("Bytes Retained by Heap");
+    printHeapSizes(doc);
 
     doc.big(Menu.getMenu());
   }
 
-  private static class TableElem implements Diffable<TableElem> {
-    @Override public TableElem getBaseline() {
-      return this;
+  private void printHeapSizes(Doc doc) {
+    SizeTable.table(doc, new Column("Heap"), mSnapshot.isDiffed());
+    Size totalSize = Size.ZERO;
+    Size totalBase = Size.ZERO;
+    for (AhatHeap heap : mSnapshot.getHeaps()) {
+      Size size = heap.getSize();
+      Size base = heap.getBaseline().getSize();
+      if (!size.isZero() || !base.isZero()) {
+        SizeTable.row(doc, DocString.text(heap.getName()), size, base);
+        totalSize = totalSize.plus(size);
+        totalBase = totalBase.plus(base);
+      }
     }
-
-    @Override public boolean isPlaceHolder() {
-      return false;
-    }
-  }
-
-  private void printHeapSizes(Doc doc, Query query) {
-    List<TableElem> dummy = Collections.singletonList(new TableElem());
-
-    HeapTable.TableConfig<TableElem> table = new HeapTable.TableConfig<TableElem>() {
-      public String getHeapsDescription() {
-        return "Bytes Retained by Heap";
-      }
-
-      public long getSize(TableElem element, AhatHeap heap) {
-        return heap.getSize();
-      }
-
-      public List<HeapTable.ValueConfig<TableElem>> getValueConfigs() {
-        return Collections.emptyList();
-      }
-    };
-    HeapTable.render(doc, query, OVERVIEW_ID, table, mSnapshot, dummy);
+    SizeTable.row(doc, DocString.text("Total"), totalSize, totalBase);
+    SizeTable.end(doc);
   }
 }
 
diff --git a/tools/ahat/src/SiteHandler.java b/tools/ahat/src/SiteHandler.java
index febf171..7a831d3 100644
--- a/tools/ahat/src/SiteHandler.java
+++ b/tools/ahat/src/SiteHandler.java
@@ -60,7 +60,7 @@
         }
 
         public long getSize(Site element, AhatHeap heap) {
-          return element.getSize(heap);
+          return element.getSize(heap).getSize();
         }
 
         public List<HeapTable.ValueConfig<Site>> getValueConfigs() {
@@ -80,10 +80,7 @@
     }
 
     doc.section("Objects Allocated");
-
-    doc.table(
-        new Column("Reachable Bytes Allocated", Column.Align.RIGHT),
-        new Column("Δ", Column.Align.RIGHT, mSnapshot.isDiffed()),
+    SizeTable.table(doc, mSnapshot.isDiffed(),
         new Column("Instances", Column.Align.RIGHT),
         new Column("Δ", Column.Align.RIGHT, mSnapshot.isDiffed()),
         new Column("Heap"),
@@ -100,9 +97,7 @@
     for (Site.ObjectsInfo info : selector.selected()) {
       Site.ObjectsInfo baseinfo = info.getBaseline();
       String className = info.getClassName();
-      doc.row(
-          DocString.format("%,14d", info.numBytes),
-          DocString.delta(false, false, info.numBytes, baseinfo.numBytes),
+      SizeTable.row(doc, info.numBytes, baseinfo.numBytes,
           DocString.link(
             DocString.formattedUri("objects?id=%d&depth=%d&heap=%s&class=%s",
               site.getId(), site.getDepth(), info.heap.getName(), className),
@@ -111,7 +106,7 @@
           DocString.text(info.heap.getName()),
           Summarizer.summarize(info.classObj));
     }
-    doc.end();
+    SizeTable.end(doc);
     selector.render(doc);
   }
 }
diff --git a/tools/ahat/src/SitePrinter.java b/tools/ahat/src/SitePrinter.java
index 21ca2de..32037f4 100644
--- a/tools/ahat/src/SitePrinter.java
+++ b/tools/ahat/src/SitePrinter.java
@@ -38,7 +38,7 @@
       }
 
       public long getSize(Site element, AhatHeap heap) {
-        return element.getSize(heap);
+        return element.getSize(heap).getSize();
       }
 
       public List<HeapTable.ValueConfig<Site>> getValueConfigs() {
diff --git a/tools/ahat/src/SizeTable.java b/tools/ahat/src/SizeTable.java
new file mode 100644
index 0000000..46e3956
--- /dev/null
+++ b/tools/ahat/src/SizeTable.java
@@ -0,0 +1,106 @@
+/*
+ * Copyright (C) 2017 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.
+ */
+
+package com.android.ahat;
+
+import com.android.ahat.heapdump.Size;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.List;
+
+/**
+ * Class for rendering a table that includes all categories of Size.
+ * Two table formats are supported, one where a custom left column can be
+ * added before the size columns:
+ *    |left column|Java Size|Native Size|...|Total Size|custom columns...|
+ *
+ * The other without the custom left column:
+ *    |Java Size|Native Size|...|Total Size|custom columns...|
+ */
+class SizeTable {
+  /**
+   * Start a size table with a custom left column.
+   *
+   * |left column|Java Size|Native Size|...|Total Size|custom columns...|
+   *
+   * This should be followed by calls to the 'row' method to fill in the table
+   * contents and the 'end' method to end the table.
+   *
+   * Set showDiff to true if size diffs should be shown.
+   */
+  static void table(Doc doc, Column left, boolean showDiff, Column... columns) {
+    List<Column> cols = new ArrayList<Column>();
+    cols.add(left);
+    cols.add(new Column("Java Size", Column.Align.RIGHT));
+    cols.add(new Column("Δ", Column.Align.RIGHT, showDiff));
+    cols.add(new Column("Registered Native Size", Column.Align.RIGHT));
+    cols.add(new Column("Δ", Column.Align.RIGHT, showDiff));
+    cols.add(new Column("Total Size", Column.Align.RIGHT));
+    cols.add(new Column("Δ", Column.Align.RIGHT, showDiff));
+    cols.addAll(Arrays.asList(columns));
+    doc.table(cols.toArray(new Column[cols.size()]));
+  }
+
+  /**
+   * Add a row to the currently active size table with custom left column.
+   * The number of values must match the number of columns provided for the
+   * currently active table.
+   */
+  static void row(Doc doc, DocString left, Size size, Size base, DocString... values) {
+    List<DocString> vals = new ArrayList<DocString>();
+    vals.add(left);
+    vals.add(DocString.size(size.getJavaSize(), false));
+    vals.add(DocString.delta(false, false, size.getJavaSize(), base.getJavaSize()));
+    vals.add(DocString.size(size.getRegisteredNativeSize(), false));
+    vals.add(DocString.delta(false, false,
+          size.getRegisteredNativeSize(), base.getRegisteredNativeSize()));
+    vals.add(DocString.size(size.getSize(), false));
+    vals.add(DocString.delta(false, false, size.getSize(), base.getSize()));
+    vals.addAll(Arrays.asList(values));
+    doc.row(vals.toArray(new DocString[vals.size()]));
+  }
+
+  /**
+   * Start a size table without a custom left column.
+   *
+   * |Java Size|Native Size|...|Total Size|custom columns...|
+   * This should be followed by calls to the 'row' method to fill in the table
+   * contents and the 'end' method to end the table.
+   *
+   * Set showDiff to true if size diffs should be shown.
+   */
+  static void table(Doc doc, boolean showDiff, Column... columns) {
+    // Re-use the code for a size table with custom left column by having an
+    // invisible custom left column.
+    table(doc, new Column("", Column.Align.LEFT, false), showDiff, columns);
+  }
+
+  /**
+   * Add a row to the currently active size table without a custom left column.
+   * The number of values must match the number of columns provided for the
+   * currently active table.
+   */
+  static void row(Doc doc, Size size, Size base, DocString... values) {
+    row(doc, new DocString(), size, base, values);
+  }
+
+  /**
+   * End the currently active table.
+   */
+  static void end(Doc doc) {
+    doc.end();
+  }
+}
diff --git a/tools/ahat/src/heapdump/AhatHeap.java b/tools/ahat/src/heapdump/AhatHeap.java
index c39adc4..b8897a1 100644
--- a/tools/ahat/src/heapdump/AhatHeap.java
+++ b/tools/ahat/src/heapdump/AhatHeap.java
@@ -18,7 +18,7 @@
 
 public class AhatHeap implements Diffable<AhatHeap> {
   private String mName;
-  private long mSize = 0;
+  private Size mSize = Size.ZERO;
   private int mIndex;
   private AhatHeap mBaseline;
   private boolean mIsPlaceHolder = false;
@@ -47,8 +47,8 @@
     return new AhatHeap(name, baseline);
   }
 
-  void addToSize(long increment) {
-    mSize += increment;
+  void addToSize(Size size) {
+    mSize = mSize.plus(size);
   }
 
   /**
@@ -69,7 +69,7 @@
   /**
    * Returns the total number of bytes allocated on this heap.
    */
-  public long getSize() {
+  public Size getSize() {
     return mSize;
   }
 
diff --git a/tools/ahat/src/heapdump/AhatInstance.java b/tools/ahat/src/heapdump/AhatInstance.java
index e6b9c00..af369d9 100644
--- a/tools/ahat/src/heapdump/AhatInstance.java
+++ b/tools/ahat/src/heapdump/AhatInstance.java
@@ -20,17 +20,18 @@
 import com.android.tools.perflib.heap.Instance;
 import com.android.tools.perflib.heap.RootObj;
 import java.awt.image.BufferedImage;
+import java.util.ArrayDeque;
 import java.util.ArrayList;
 import java.util.Arrays;
 import java.util.Collection;
 import java.util.Collections;
+import java.util.Deque;
 import java.util.List;
 
 public abstract class AhatInstance implements Diffable<AhatInstance> {
   private long mId;
-  private long mSize;
-  private long mTotalRetainedSize;
-  private long mRetainedSizes[];      // Retained size indexed by heap index
+  private Size mSize;
+  private Size[] mRetainedSizes;      // Retained size indexed by heap index
   private boolean mIsReachable;
   private AhatHeap mHeap;
   private AhatInstance mImmediateDominator;
@@ -63,15 +64,10 @@
    */
   void initialize(AhatSnapshot snapshot, Instance inst) {
     mId = inst.getId();
-    mSize = inst.getSize();
-    mTotalRetainedSize = inst.getTotalRetainedSize();
+    mSize = new Size(inst.getSize(), 0);
     mIsReachable = inst.isReachable();
 
     List<AhatHeap> heaps = snapshot.getHeaps();
-    mRetainedSizes = new long[heaps.size()];
-    for (AhatHeap heap : heaps) {
-      mRetainedSizes[heap.getIndex()] = inst.getRetainedSize(heap.getIndex());
-    }
 
     mHeap = snapshot.getHeap(inst.getHeap().getName());
 
@@ -130,7 +126,7 @@
   /**
    * Returns the shallow number of bytes this object takes up.
    */
-  public long getSize() {
+  public Size getSize() {
     return mSize;
   }
 
@@ -138,16 +134,32 @@
    * Returns the number of bytes belonging to the given heap that this instance
    * retains.
    */
-  public long getRetainedSize(AhatHeap heap) {
+  public Size getRetainedSize(AhatHeap heap) {
     int index = heap.getIndex();
-    return 0 <= index && index < mRetainedSizes.length ? mRetainedSizes[heap.getIndex()] : 0;
+    if (mRetainedSizes != null && 0 <= index && index < mRetainedSizes.length) {
+      return mRetainedSizes[heap.getIndex()];
+    }
+    return Size.ZERO;
   }
 
   /**
    * Returns the total number of bytes this instance retains.
    */
-  public long getTotalRetainedSize() {
-    return mTotalRetainedSize;
+  public Size getTotalRetainedSize() {
+    Size size = Size.ZERO;
+    if (mRetainedSizes != null) {
+      for (int i = 0; i < mRetainedSizes.length; i++) {
+        size = size.plus(mRetainedSizes[i]);
+      }
+    }
+    return size;
+  }
+
+  /**
+   * Increment the number of registered native bytes tied to this object.
+   */
+  void addRegisteredNativeSize(long size) {
+    mSize = mSize.plusRegisteredNativeSize(size);
   }
 
   /**
@@ -452,4 +464,41 @@
   AhatInstance newPlaceHolderInstance() {
     return new AhatPlaceHolderInstance(this);
   }
+
+  /**
+   * Recursively compute the retained size of the given instance and all
+   * other instances it dominates.
+   */
+  static void computeRetainedSize(AhatInstance inst, int numHeaps) {
+    // Note: We can't use a recursive implementation because it can lead to
+    // stack overflow. Use an iterative implementation instead.
+    //
+    // Objects not yet processed will have mRetainedSizes set to null.
+    // Once prepared, an object will have mRetaiedSizes set to an array of 0
+    // sizes.
+    Deque<AhatInstance> deque = new ArrayDeque<AhatInstance>();
+    deque.push(inst);
+
+    while (!deque.isEmpty()) {
+      inst = deque.pop();
+      if (inst.mRetainedSizes == null) {
+        inst.mRetainedSizes = new Size[numHeaps];
+        for (int i = 0; i < numHeaps; i++) {
+          inst.mRetainedSizes[i] = Size.ZERO;
+        }
+        inst.mRetainedSizes[inst.mHeap.getIndex()] = 
+          inst.mRetainedSizes[inst.mHeap.getIndex()].plus(inst.mSize);
+        deque.push(inst);
+        for (AhatInstance dominated : inst.mDominated) {
+          deque.push(dominated);
+        }
+      } else {
+        for (AhatInstance dominated : inst.mDominated) {
+          for (int i = 0; i < numHeaps; i++) {
+            inst.mRetainedSizes[i] = inst.mRetainedSizes[i].plus(dominated.mRetainedSizes[i]);
+          }
+        }
+      }
+    }
+  }
 }
diff --git a/tools/ahat/src/heapdump/AhatPlaceHolderClassObj.java b/tools/ahat/src/heapdump/AhatPlaceHolderClassObj.java
index c6ad87f..2b3e056 100644
--- a/tools/ahat/src/heapdump/AhatPlaceHolderClassObj.java
+++ b/tools/ahat/src/heapdump/AhatPlaceHolderClassObj.java
@@ -29,16 +29,16 @@
     baseline.setBaseline(this);
   }
 
-  @Override public long getSize() {
-    return 0;
+  @Override public Size getSize() {
+    return Size.ZERO;
   }
 
-  @Override public long getRetainedSize(AhatHeap heap) {
-    return 0;
+  @Override public Size getRetainedSize(AhatHeap heap) {
+    return Size.ZERO;
   }
 
-  @Override public long getTotalRetainedSize() {
-    return 0;
+  @Override public Size getTotalRetainedSize() {
+    return Size.ZERO;
   }
 
   @Override public AhatHeap getHeap() {
diff --git a/tools/ahat/src/heapdump/AhatPlaceHolderInstance.java b/tools/ahat/src/heapdump/AhatPlaceHolderInstance.java
index 9412eae..4aac804 100644
--- a/tools/ahat/src/heapdump/AhatPlaceHolderInstance.java
+++ b/tools/ahat/src/heapdump/AhatPlaceHolderInstance.java
@@ -29,16 +29,16 @@
     baseline.setBaseline(this);
   }
 
-  @Override public long getSize() {
-    return 0;
+  @Override public Size getSize() {
+    return Size.ZERO;
   }
 
-  @Override public long getRetainedSize(AhatHeap heap) {
-    return 0;
+  @Override public Size getRetainedSize(AhatHeap heap) {
+    return Size.ZERO;
   }
 
-  @Override public long getTotalRetainedSize() {
-    return 0;
+  @Override public Size getTotalRetainedSize() {
+    return Size.ZERO;
   }
 
   @Override public AhatHeap getHeap() {
diff --git a/tools/ahat/src/heapdump/AhatSnapshot.java b/tools/ahat/src/heapdump/AhatSnapshot.java
index 20b85da..35d6c8a 100644
--- a/tools/ahat/src/heapdump/AhatSnapshot.java
+++ b/tools/ahat/src/heapdump/AhatSnapshot.java
@@ -82,8 +82,7 @@
     Snapshot snapshot = Snapshot.createSnapshot(buffer, map);
     snapshot.computeDominators();
 
-    // Properly label the class of class objects in the perflib snapshot, and
-    // count the total number of instances.
+    // Properly label the class of class objects in the perflib snapshot.
     final ClassObj javaLangClass = snapshot.findClass("java.lang.Class");
     if (javaLangClass != null) {
       for (Heap heap : snapshot.getHeaps()) {
@@ -134,12 +133,19 @@
       }
     });
 
+    Map<Instance, Long> registeredNative = Perflib.getRegisteredNativeAllocations(snapshot);
+
     // Initialize ahat snapshot and instances based on the perflib snapshot
     // and instances.
     for (AhatInstance ahat : mInstances) {
       Instance inst = snapshot.findInstance(ahat.getId());
       ahat.initialize(this, inst);
 
+      Long registeredNativeSize = registeredNative.get(inst);
+      if (registeredNativeSize != null) {
+        ahat.addRegisteredNativeSize(registeredNativeSize);
+      }
+
       if (inst.getImmediateDominator() == Snapshot.SENTINEL_ROOT) {
         mRooted.add(ahat);
       }
@@ -166,6 +172,13 @@
       }
     }
     snapshot.dispose();
+
+    // Compute the retained sizes of objects. We do this explicitly now rather
+    // than relying on the retained sizes computed by perflib so that
+    // registered native sizes are included.
+    for (AhatInstance inst : mRooted) {
+      AhatInstance.computeRetainedSize(inst, mHeaps.size());
+    }
   }
 
   /**
diff --git a/tools/ahat/src/heapdump/Perflib.java b/tools/ahat/src/heapdump/Perflib.java
new file mode 100644
index 0000000..d0264a3
--- /dev/null
+++ b/tools/ahat/src/heapdump/Perflib.java
@@ -0,0 +1,91 @@
+/*
+ * Copyright (C) 2017 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.
+ */
+
+package com.android.ahat.heapdump;
+
+import com.android.tools.perflib.heap.ClassInstance;
+import com.android.tools.perflib.heap.ClassObj;
+import com.android.tools.perflib.heap.Instance;
+import com.android.tools.perflib.heap.Snapshot;
+import java.util.HashMap;
+import java.util.Map;
+
+/**
+ * Collection of utilities that may be suitable to have in perflib instead of
+ * ahat.
+ */
+public class Perflib {
+  /**
+   * Return a collection of instances in the given snapshot that are tied to
+   * registered native allocations and their corresponding registered native
+   * sizes.
+   */
+  public static Map<Instance, Long> getRegisteredNativeAllocations(Snapshot snapshot) {
+    Map<Instance, Long> allocs = new HashMap<Instance, Long>();
+    ClassObj cleanerClass = snapshot.findClass("sun.misc.Cleaner");
+    if (cleanerClass != null) {
+      for (Instance cleanerInst : cleanerClass.getInstancesList()) {
+        ClassInstance cleaner = (ClassInstance)cleanerInst;
+        Object referent = getField(cleaner, "referent");
+        if (referent instanceof Instance) {
+          Instance inst = (Instance)referent;
+          Object thunkValue = getField(cleaner, "thunk");
+          if (thunkValue instanceof ClassInstance) {
+            ClassInstance thunk = (ClassInstance)thunkValue;
+            ClassObj thunkClass = thunk.getClassObj();
+            String cleanerThunkClassName = "libcore.util.NativeAllocationRegistry$CleanerThunk";
+            if (thunkClass != null && cleanerThunkClassName.equals(thunkClass.getClassName())) {
+              for (ClassInstance.FieldValue thunkField : thunk.getValues()) {
+                if (thunkField.getValue() instanceof ClassInstance) {
+                  ClassInstance registry = (ClassInstance)thunkField.getValue();
+                  ClassObj registryClass = registry.getClassObj();
+                  String registryClassName = "libcore.util.NativeAllocationRegistry";
+                  if (registryClass != null
+                      && registryClassName.equals(registryClass.getClassName())) {
+                    Object sizeValue = getField(registry, "size");
+                    if (sizeValue instanceof Long) {
+                      long size = (Long)sizeValue;
+                      if (size > 0) {
+                        Long old = allocs.get(inst);
+                        allocs.put(inst, old == null ? size : old + size);
+                      }
+                    }
+                    break;
+                  }
+                }
+              }
+            }
+          }
+        }
+      }
+    }
+    return allocs;
+  }
+
+  /**
+   * Helper function to read a single field from a perflib class instance.
+   * Returns null if field not found. Note there is no way to distinguish
+   * between field not found an a field value of null.
+   */
+  private static Object getField(ClassInstance cls, String name) {
+    for (ClassInstance.FieldValue field : cls.getValues()) {
+      if (name.equals(field.getField().getName())) {
+        return field.getValue();
+      }
+    }
+    return null;
+  }
+}
diff --git a/tools/ahat/src/heapdump/Site.java b/tools/ahat/src/heapdump/Site.java
index 738eaf0..fdd4eea 100644
--- a/tools/ahat/src/heapdump/Site.java
+++ b/tools/ahat/src/heapdump/Site.java
@@ -44,7 +44,7 @@
   // The total size of objects allocated in this site (including child sites),
   // organized by heap index. Heap indices outside the range of mSizesByHeap
   // implicitly have size 0.
-  private long[] mSizesByHeap;
+  private Size[] mSizesByHeap;
 
   // List of child sites.
   private List<Site> mChildren;
@@ -60,14 +60,18 @@
     public AhatHeap heap;
     public AhatClassObj classObj;   // May be null.
     public long numInstances;
-    public long numBytes;
+    public Size numBytes;
     private ObjectsInfo baseline;
 
-    public ObjectsInfo(AhatHeap heap, AhatClassObj classObj, long numInstances, long numBytes) {
+    /**
+     * Construct a new, empty objects info for the given heap and class
+     * combination.
+     */
+    public ObjectsInfo(AhatHeap heap, AhatClassObj classObj) {
       this.heap = heap;
       this.classObj = classObj;
-      this.numInstances = numInstances;
-      this.numBytes = numBytes;
+      this.numInstances = 0;
+      this.numBytes = Size.ZERO;
       this.baseline = this;
     }
 
@@ -107,7 +111,7 @@
     mLineNumber = line;
     mId = id;
     mDepth = depth;
-    mSizesByHeap = new long[1];
+    mSizesByHeap = new Size[0];
     mChildren = new ArrayList<Site>();
     mObjects = new ArrayList<AhatInstance>();
     mObjectsInfos = new ArrayList<ObjectsInfo>();
@@ -133,16 +137,20 @@
       if (inst.isReachable()) {
         AhatHeap heap = inst.getHeap();
         if (heap.getIndex() >= site.mSizesByHeap.length) {
-          long[] newSizes = new long[heap.getIndex() + 1];
+          Size[] newSizes = new Size[heap.getIndex() + 1];
           for (int i = 0; i < site.mSizesByHeap.length; i++) {
             newSizes[i] = site.mSizesByHeap[i];
           }
+          for (int i = site.mSizesByHeap.length; i < heap.getIndex() + 1; i++) {
+            newSizes[i] = Size.ZERO;
+          }
           site.mSizesByHeap = newSizes;
         }
-        site.mSizesByHeap[heap.getIndex()] += inst.getSize();
+        site.mSizesByHeap[heap.getIndex()]
+          = site.mSizesByHeap[heap.getIndex()].plus(inst.getSize());
 
         info.numInstances++;
-        info.numBytes += inst.getSize();
+        info.numBytes = info.numBytes.plus(inst.getSize());
       }
 
       if (depth > 0) {
@@ -172,9 +180,9 @@
   }
 
   // Get the size of a site for a specific heap.
-  public long getSize(AhatHeap heap) {
+  public Size getSize(AhatHeap heap) {
     int index = heap.getIndex();
-    return index >= 0 && index < mSizesByHeap.length ? mSizesByHeap[index] : 0;
+    return index >= 0 && index < mSizesByHeap.length ? mSizesByHeap[index] : Size.ZERO;
   }
 
   /**
@@ -198,7 +206,7 @@
 
     ObjectsInfo info = classToObjectsInfo.get(classObj);
     if (info == null) {
-      info = new ObjectsInfo(heap, classObj, 0, 0);
+      info = new ObjectsInfo(heap, classObj);
       mObjectsInfos.add(info);
       classToObjectsInfo.put(classObj, info);
     }
@@ -210,10 +218,10 @@
   }
 
   // Get the combined size of the site for all heaps.
-  public long getTotalSize() {
-    long total = 0;
+  public Size getTotalSize() {
+    Size total = Size.ZERO;
     for (int i = 0; i < mSizesByHeap.length; i++) {
-      total += mSizesByHeap[i];
+      total = total.plus(mSizesByHeap[i]);
     }
     return total;
   }
diff --git a/tools/ahat/src/heapdump/Size.java b/tools/ahat/src/heapdump/Size.java
new file mode 100644
index 0000000..7c8db90
--- /dev/null
+++ b/tools/ahat/src/heapdump/Size.java
@@ -0,0 +1,89 @@
+/*
+ * Copyright (C) 2017 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.
+ */
+
+package com.android.ahat.heapdump;
+
+/**
+ * The Size class is used to represent how much space an instance takes up.
+ *
+ * An abstraction is introduced rather than using a long directly in order to
+ * more easily keep track of the different components of the size. For
+ * example, some instances may have associated native, code, or graphics
+ * sizes.
+ *
+ * Size objects are immutable.
+ */
+public class Size {
+  private final long mJavaSize;
+  private final long mRegisteredNativeSize;
+
+  public static Size ZERO = new Size(0, 0);
+
+  public Size(long javaSize, long registeredNativeSize) {
+    mJavaSize = javaSize;
+    mRegisteredNativeSize = registeredNativeSize;
+  }
+
+  public long getSize() {
+    return mJavaSize + mRegisteredNativeSize;
+  }
+
+  public long getJavaSize() {
+    return mJavaSize;
+  }
+
+  public long getRegisteredNativeSize() {
+    return mRegisteredNativeSize;
+  }
+
+  /**
+   * Returns true if all the fields of this size object are zero.
+   */
+  public boolean isZero() {
+    return mJavaSize == 0 && mRegisteredNativeSize == 0;
+  }
+
+  /**
+   * Return a new Size object that is the sum of this size and the other.
+   */
+  public Size plus(Size other) {
+    if (isZero()) {
+      return other;
+    } else if (other.isZero()) {
+      return this;
+    } else {
+      return new Size(mJavaSize + other.mJavaSize,
+          mRegisteredNativeSize + other.mRegisteredNativeSize);
+    }
+  }
+
+  /**
+   * Return a new Size object that has 'size' more registered native size than
+   * this Size object.
+   */
+  public Size plusRegisteredNativeSize(long size) {
+    return new Size(mJavaSize, mRegisteredNativeSize + size);
+  }
+
+  @Override public boolean equals(Object other) {
+    if (other instanceof Size) {
+      Size s = (Size)other;
+      return mJavaSize == s.mJavaSize && mRegisteredNativeSize == s.mRegisteredNativeSize;
+    }
+    return false;
+  }
+}
+
diff --git a/tools/ahat/src/heapdump/Sort.java b/tools/ahat/src/heapdump/Sort.java
index 93d147a..0745803 100644
--- a/tools/ahat/src/heapdump/Sort.java
+++ b/tools/ahat/src/heapdump/Sort.java
@@ -32,6 +32,17 @@
  */
 public class Sort {
   /**
+   * Compare sizes by their total size.
+   * This sorts sizes from smaller total size to larger total size.
+   */
+  public static final Comparator<Size> SIZE_BY_SIZE = new Comparator<Size>() {
+    @Override
+    public int compare(Size a, Size b) {
+      return Long.compare(a.getSize(), b.getSize());
+    }
+  };
+
+  /**
    * Compare instances by their total retained size.
    * Different instances with the same total retained size are considered
    * equal for the purposes of comparison.
@@ -41,7 +52,7 @@
     = new Comparator<AhatInstance>() {
     @Override
     public int compare(AhatInstance a, AhatInstance b) {
-      return Long.compare(b.getTotalRetainedSize(), a.getTotalRetainedSize());
+      return SIZE_BY_SIZE.compare(b.getTotalRetainedSize(), a.getTotalRetainedSize());
     }
   };
 
@@ -60,7 +71,7 @@
 
     @Override
     public int compare(AhatInstance a, AhatInstance b) {
-      return Long.compare(b.getRetainedSize(mHeap), a.getRetainedSize(mHeap));
+      return SIZE_BY_SIZE.compare(b.getRetainedSize(mHeap), a.getRetainedSize(mHeap));
     }
   }
 
@@ -119,7 +130,7 @@
 
     @Override
     public int compare(Site a, Site b) {
-      return Long.compare(b.getSize(mHeap), a.getSize(mHeap));
+      return SIZE_BY_SIZE.compare(b.getSize(mHeap), a.getSize(mHeap));
     }
   }
 
@@ -130,7 +141,7 @@
   public static final Comparator<Site> SITE_BY_TOTAL_SIZE = new Comparator<Site>() {
     @Override
     public int compare(Site a, Site b) {
-      return Long.compare(b.getTotalSize(), a.getTotalSize());
+      return SIZE_BY_SIZE.compare(b.getTotalSize(), a.getTotalSize());
     }
   };
 
@@ -158,7 +169,7 @@
     = new Comparator<Site.ObjectsInfo>() {
     @Override
     public int compare(Site.ObjectsInfo a, Site.ObjectsInfo b) {
-      return Long.compare(b.numBytes, a.numBytes);
+      return SIZE_BY_SIZE.compare(b.numBytes, a.numBytes);
     }
   };
 
diff --git a/tools/ahat/src/manifest.txt b/tools/ahat/src/manifest.txt
index 20245f3..c35ccf1 100644
--- a/tools/ahat/src/manifest.txt
+++ b/tools/ahat/src/manifest.txt
@@ -1,4 +1,4 @@
 Name: ahat/
 Implementation-Title: ahat
-Implementation-Version: 1.1
+Implementation-Version: 1.2
 Main-Class: com.android.ahat.Main
diff --git a/tools/ahat/test-dump/Main.java b/tools/ahat/test-dump/Main.java
index 7a05b1c..3d3de78 100644
--- a/tools/ahat/test-dump/Main.java
+++ b/tools/ahat/test-dump/Main.java
@@ -20,6 +20,7 @@
 import java.lang.ref.ReferenceQueue;
 import java.lang.ref.SoftReference;
 import java.lang.ref.WeakReference;
+import libcore.util.NativeAllocationRegistry;
 import org.apache.harmony.dalvik.ddmc.DdmVmInternal;
 
 /**
@@ -98,6 +99,11 @@
         bigArray[i] = (byte)((i*i) & 0xFF);
       }
 
+      // 0x12345, 50000, and 0xABCDABCD are arbitrary values.
+      NativeAllocationRegistry registry = new NativeAllocationRegistry(
+          Main.class.getClassLoader(), 0x12345, 50000);
+      registry.registerNativeAllocation(anObject, 0xABCDABCD);
+
       addedObject = baseline ? null : new AddedObject();
       removedObject = baseline ? new RemovedObject() : null;
       modifiedObject = new ModifiedObject();
diff --git a/tools/ahat/test/InstanceTest.java b/tools/ahat/test/InstanceTest.java
index 3a50150..71b081c 100644
--- a/tools/ahat/test/InstanceTest.java
+++ b/tools/ahat/test/InstanceTest.java
@@ -21,6 +21,7 @@
 import com.android.ahat.heapdump.AhatInstance;
 import com.android.ahat.heapdump.AhatSnapshot;
 import com.android.ahat.heapdump.PathElement;
+import com.android.ahat.heapdump.Size;
 import com.android.ahat.heapdump.Value;
 import com.android.tools.perflib.heap.hprof.HprofClassDump;
 import com.android.tools.perflib.heap.hprof.HprofConstant;
@@ -292,13 +293,13 @@
     // allocated on, and should be 0 for all other heaps.
     AhatInstance anObject = dump.getDumpedAhatInstance("anObject");
     AhatSnapshot snapshot = dump.getAhatSnapshot();
-    long size = anObject.getSize();
+    Size size = anObject.getSize();
     assertEquals(size, anObject.getTotalRetainedSize());
     assertEquals(size, anObject.getRetainedSize(anObject.getHeap()));
     for (AhatHeap heap : snapshot.getHeaps()) {
       if (!heap.equals(anObject.getHeap())) {
         assertEquals(String.format("For heap '%s'", heap.getName()),
-            0, anObject.getRetainedSize(heap));
+            Size.ZERO, anObject.getRetainedSize(heap));
       }
     }
   }
diff --git a/tools/ahat/test/NativeAllocationTest.java b/tools/ahat/test/NativeAllocationTest.java
new file mode 100644
index 0000000..7436be8
--- /dev/null
+++ b/tools/ahat/test/NativeAllocationTest.java
@@ -0,0 +1,37 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.ahat;
+
+import com.android.ahat.heapdump.AhatInstance;
+import com.android.ahat.heapdump.AhatSnapshot;
+import java.io.IOException;
+import org.junit.Test;
+
+import static org.junit.Assert.assertEquals;
+
+public class NativeAllocationTest {
+
+  @Test
+  public void nativeAllocation() throws IOException {
+    TestDump dump = TestDump.getTestDump();
+
+    AhatSnapshot snapshot = dump.getAhatSnapshot();
+    AhatInstance referent = dump.getDumpedAhatInstance("anObject");
+    assertEquals(50000, referent.getSize().getRegisteredNativeSize());
+  }
+}
+
diff --git a/tools/ahat/test/Tests.java b/tools/ahat/test/Tests.java
index 2fd3286..c7e9b18 100644
--- a/tools/ahat/test/Tests.java
+++ b/tools/ahat/test/Tests.java
@@ -24,6 +24,7 @@
       args = new String[]{
         "com.android.ahat.DiffTest",
         "com.android.ahat.InstanceTest",
+        "com.android.ahat.NativeAllocationTest",
         "com.android.ahat.ObjectHandlerTest",
         "com.android.ahat.OverviewHandlerTest",
         "com.android.ahat.PerformanceTest",