Merge "Add ICU's .dat to the runtime APEX"
diff --git a/Android.mk b/Android.mk
index 237dcd8..54c96ab 100644
--- a/Android.mk
+++ b/Android.mk
@@ -63,7 +63,6 @@
 include $(art_path)/tools/amm/Android.mk
 include $(art_path)/tools/dexfuzz/Android.mk
 include $(art_path)/tools/veridex/Android.mk
-include $(art_path)/libart_fake/Android.mk
 
 ART_HOST_DEPENDENCIES := \
   $(ART_HOST_EXECUTABLES) \
@@ -388,9 +387,6 @@
     profman \
     libadbconnection \
 
-# For nosy apps, we provide a fake library that avoids namespace issues and gives some warnings.
-LOCAL_REQUIRED_MODULES += libart_fake
-
 # Potentially add in debug variants:
 #
 # * We will never add them if PRODUCT_ART_TARGET_INCLUDE_DEBUG_BUILD = false.
@@ -492,6 +488,15 @@
 .PHONY: build-art-target-golem
 # Also include libartbenchmark, we always include it when running golem.
 # libstdc++ is needed when building for ART_TARGET_LINUX.
+#
+# Also include a copy of the ICU .dat prebuilt files in
+# /system/etc/icu on target (see module `icu-data-art-test`), so that
+# it can found even if the Runtime APEX is not available, by setting
+# the environment variable `ART_TEST_ANDROID_RUNTIME_ROOT` to
+# "/system" on device. This is a temporary change needed until both
+# the ART Buildbot and Golem fully support the Runtime APEX.
+# TODO(b/121117762): Remove this when the ART Buildbot and Golem have
+# full support for the Runtime APEX.
 ART_TARGET_SHARED_LIBRARY_BENCHMARK := $(TARGET_OUT_SHARED_LIBRARIES)/libartbenchmark.so
 build-art-target-golem: dex2oat dalvikvm linker libstdc++ \
                         $(TARGET_OUT_EXECUTABLES)/art \
@@ -500,7 +505,8 @@
                         $(ART_TARGET_SHARED_LIBRARY_DEPENDENCIES) \
                         $(ART_TARGET_SHARED_LIBRARY_BENCHMARK) \
                         $(TARGET_CORE_IMG_OUT_BASE).art \
-                        $(TARGET_CORE_IMG_OUT_BASE)-interpreter.art
+                        $(TARGET_CORE_IMG_OUT_BASE)-interpreter.art \
+                        icu-data-art-test
 	# remove debug libraries from public.libraries.txt because golem builds
 	# won't have it.
 	sed -i '/libartd.so/d' $(TARGET_OUT)/etc/public.libraries.txt
diff --git a/build/Android.gtest.mk b/build/Android.gtest.mk
index a926d9a..f00da9c 100644
--- a/build/Android.gtest.mk
+++ b/build/Android.gtest.mk
@@ -371,8 +371,8 @@
 
 ART_TEST_MODULES := \
     art_cmdline_tests \
-    art_compiler_tests \
     art_compiler_host_tests \
+    art_compiler_tests \
     art_dex2oat_tests \
     art_dexanalyze_tests \
     art_dexdiag_tests \
@@ -383,12 +383,14 @@
     art_hiddenapi_tests \
     art_imgdiag_tests \
     art_libartbase_tests \
+    art_libdexfile_external_tests \
+    art_libdexfile_support_tests \
     art_libdexfile_tests \
     art_libprofile_tests \
     art_oatdump_tests \
     art_profman_tests \
-    art_runtime_tests \
     art_runtime_compiler_tests \
+    art_runtime_tests \
     art_sigchain_tests \
 
 ART_TARGET_GTEST_FILES := $(foreach m,$(ART_TEST_MODULES),\
@@ -423,6 +425,9 @@
 endif
 
 ART_GTEST_TARGET_ANDROID_RUNTIME_ROOT := '/apex/com.android.runtime'
+ifneq ($(ART_TEST_ANDROID_RUNTIME_ROOT),)
+  ART_GTEST_TARGET_ANDROID_RUNTIME_ROOT := $(ART_TEST_ANDROID_RUNTIME_ROOT)
+endif
 
 # Define a make rule for a target device gtest.
 # $(1): gtest name - the name of the test we're building such as leb128_test.
diff --git a/build/apex/Android.bp b/build/apex/Android.bp
index fe23b80..47729c1 100644
--- a/build/apex/Android.bp
+++ b/build/apex/Android.bp
@@ -41,7 +41,6 @@
     "libopenjdkjvmd",
     "libopenjdkjvmtid",
     "libadbconnectiond",
-    "libjavacrypto",
 ]
 
 // Data files associated with bionic / managed core library APIs.
diff --git a/build/apex/ld.config.txt b/build/apex/ld.config.txt
index 014b115..9e49d76 100644
--- a/build/apex/ld.config.txt
+++ b/build/apex/ld.config.txt
@@ -24,8 +24,7 @@
 namespace.platform.isolated = true
 namespace.platform.search.paths = /system/${LIB}
 namespace.platform.links = default
-namespace.platform.link.default.shared_libs  = libc.so:libdl.so:libm.so
-namespace.platform.link.default.shared_libs += libart.so:libartd.so
+namespace.platform.link.default.shared_libs  = libart.so:libartd.so
 namespace.platform.link.default.shared_libs += libnativebridge.so
 namespace.platform.link.default.shared_libs += libnativehelper.so
 namespace.platform.link.default.shared_libs += libnativeloader.so
diff --git a/build/apex/runtests.sh b/build/apex/runtests.sh
index b5e8d8b..9db325a 100755
--- a/build/apex/runtests.sh
+++ b/build/apex/runtests.sh
@@ -146,18 +146,19 @@
   # TODO: Check for it when it is also built for host.
   : check_binary oatdump
 
-  # Check that the mounted image contains ART libraries.
+  # Check that the mounted image contains Android Runtime libraries.
   check_library libart-compiler.so
+  check_library libart-dexlayout.so
   check_library libart.so
+  check_library libartbase.so
+  check_library libdexfile.so
   check_library libopenjdkjvm.so
   check_library libopenjdkjvmti.so
-  check_library libadbconnection.so
-  # TODO: Should we check for these libraries too, even if they are not explicitly
-  # listed as dependencies in the Android Runtime APEX module rule?
-  check_library libartbase.so
-  check_library libart-dexlayout.so
-  check_library libdexfile.so
   check_library libprofile.so
+  # Check that the mounted image contains Android Core libraries.
+  check_library libjavacrypto.so
+  # Check that the mounted image contains additional required libraries.
+  check_library libadbconnection.so
 
   # TODO: Should we check for other libraries, such as:
   #
@@ -186,19 +187,18 @@
   check_binary dexoptanalyzerd
   check_binary profmand
 
-  # Check that the mounted image contains ART debug libraries.
+  # Check that the mounted image contains Android Runtime debug libraries.
+  check_library libartbased.so
   check_library libartd-compiler.so
+  check_library libartd-dexlayout.so
   check_library libartd.so
+  check_library libdexfiled.so
   check_library libopenjdkd.so
   check_library libopenjdkjvmd.so
   check_library libopenjdkjvmtid.so
-  check_library libadbconnectiond.so
-  # TODO: Should we check for these libraries too, even if they are not explicitly
-  # listed as dependencies in the Android Runtime APEX module rule?
-  check_library libdexfiled.so
-  check_library libartbased.so
-  check_library libartd-dexlayout.so
   check_library libprofiled.so
+  # Check that the mounted image contains additional required libraries.
+  check_library libadbconnectiond.so
 }
 
 # Testing target (device) APEX packages.
diff --git a/compiler/jni/quick/arm/calling_convention_arm.cc b/compiler/jni/quick/arm/calling_convention_arm.cc
index 8b4bab7..42a4603 100644
--- a/compiler/jni/quick/arm/calling_convention_arm.cc
+++ b/compiler/jni/quick/arm/calling_convention_arm.cc
@@ -18,6 +18,7 @@
 
 #include <android-base/logging.h>
 
+#include "arch/instruction_set.h"
 #include "base/macros.h"
 #include "handle_scope-inl.h"
 #include "utils/arm/managed_register_arm.h"
diff --git a/compiler/jni/quick/arm64/calling_convention_arm64.cc b/compiler/jni/quick/arm64/calling_convention_arm64.cc
index 4e6221e..4a6a754 100644
--- a/compiler/jni/quick/arm64/calling_convention_arm64.cc
+++ b/compiler/jni/quick/arm64/calling_convention_arm64.cc
@@ -18,6 +18,7 @@
 
 #include <android-base/logging.h>
 
+#include "arch/instruction_set.h"
 #include "handle_scope-inl.h"
 #include "utils/arm64/managed_register_arm64.h"
 
diff --git a/compiler/jni/quick/calling_convention.cc b/compiler/jni/quick/calling_convention.cc
index ff814c8..f031b9b 100644
--- a/compiler/jni/quick/calling_convention.cc
+++ b/compiler/jni/quick/calling_convention.cc
@@ -18,6 +18,8 @@
 
 #include <android-base/logging.h>
 
+#include "arch/instruction_set.h"
+
 #ifdef ART_ENABLE_CODEGEN_arm
 #include "jni/quick/arm/calling_convention_arm.h"
 #endif
diff --git a/compiler/jni/quick/calling_convention.h b/compiler/jni/quick/calling_convention.h
index e256ce6..77a5d59 100644
--- a/compiler/jni/quick/calling_convention.h
+++ b/compiler/jni/quick/calling_convention.h
@@ -27,6 +27,8 @@
 
 namespace art {
 
+enum class InstructionSet;
+
 // Top-level abstraction for different calling conventions.
 class CallingConvention : public DeletableArenaObject<kArenaAllocCallingConvention> {
  public:
diff --git a/compiler/jni/quick/mips/calling_convention_mips.cc b/compiler/jni/quick/mips/calling_convention_mips.cc
index d3d489e..c69854d 100644
--- a/compiler/jni/quick/mips/calling_convention_mips.cc
+++ b/compiler/jni/quick/mips/calling_convention_mips.cc
@@ -18,6 +18,7 @@
 
 #include <android-base/logging.h>
 
+#include "arch/instruction_set.h"
 #include "handle_scope-inl.h"
 #include "utils/mips/managed_register_mips.h"
 
diff --git a/compiler/jni/quick/mips64/calling_convention_mips64.cc b/compiler/jni/quick/mips64/calling_convention_mips64.cc
index 3c7cee6..2c297b3 100644
--- a/compiler/jni/quick/mips64/calling_convention_mips64.cc
+++ b/compiler/jni/quick/mips64/calling_convention_mips64.cc
@@ -18,6 +18,7 @@
 
 #include <android-base/logging.h>
 
+#include "arch/instruction_set.h"
 #include "handle_scope-inl.h"
 #include "utils/mips64/managed_register_mips64.h"
 
diff --git a/compiler/jni/quick/x86/calling_convention_x86.cc b/compiler/jni/quick/x86/calling_convention_x86.cc
index 71e6019..1f255e2 100644
--- a/compiler/jni/quick/x86/calling_convention_x86.cc
+++ b/compiler/jni/quick/x86/calling_convention_x86.cc
@@ -18,6 +18,7 @@
 
 #include <android-base/logging.h>
 
+#include "arch/instruction_set.h"
 #include "handle_scope-inl.h"
 #include "utils/x86/managed_register_x86.h"
 
diff --git a/compiler/jni/quick/x86_64/calling_convention_x86_64.cc b/compiler/jni/quick/x86_64/calling_convention_x86_64.cc
index e5e96d0..9e77d6b 100644
--- a/compiler/jni/quick/x86_64/calling_convention_x86_64.cc
+++ b/compiler/jni/quick/x86_64/calling_convention_x86_64.cc
@@ -18,6 +18,7 @@
 
 #include <android-base/logging.h>
 
+#include "arch/instruction_set.h"
 #include "base/bit_utils.h"
 #include "handle_scope-inl.h"
 #include "utils/x86_64/managed_register_x86_64.h"
diff --git a/compiler/optimizing/block_builder.cc b/compiler/optimizing/block_builder.cc
index 3672cce..a5f78ca 100644
--- a/compiler/optimizing/block_builder.cc
+++ b/compiler/optimizing/block_builder.cc
@@ -315,8 +315,16 @@
     CatchHandlerIterator iterator(handlers_ptr);
     for (; iterator.HasNext(); iterator.Next()) {
       uint32_t address = iterator.GetHandlerAddress();
-      if (catch_blocks.find(address) != catch_blocks.end()) {
+      auto existing = catch_blocks.find(address);
+      if (existing != catch_blocks.end()) {
         // Catch block already processed.
+        TryCatchInformation* info = existing->second->GetTryCatchInformation();
+        if (iterator.GetHandlerTypeIndex() != info->GetCatchTypeIndex()) {
+          // The handler is for multiple types. We could record all the types, but
+          // doing class resolution here isn't ideal, and it's unclear whether wasting
+          // the space in TryCatchInformation is worth it.
+          info->SetInvalidTypeIndex();
+        }
         continue;
       }
 
@@ -337,7 +345,7 @@
 
       catch_blocks.Put(address, catch_block);
       catch_block->SetTryCatchInformation(
-        new (allocator_) TryCatchInformation(iterator.GetHandlerTypeIndex(), *dex_file_));
+          new (allocator_) TryCatchInformation(iterator.GetHandlerTypeIndex(), *dex_file_));
     }
     handlers_ptr = iterator.EndDataPointer();
   }
diff --git a/compiler/optimizing/nodes.h b/compiler/optimizing/nodes.h
index 686a2de..48fb611 100644
--- a/compiler/optimizing/nodes.h
+++ b/compiler/optimizing/nodes.h
@@ -895,7 +895,7 @@
   explicit TryCatchInformation(const HTryBoundary& try_entry)
       : try_entry_(&try_entry),
         catch_dex_file_(nullptr),
-        catch_type_index_(DexFile::kDexNoIndex16) {
+        catch_type_index_(dex::TypeIndex::Invalid()) {
     DCHECK(try_entry_ != nullptr);
   }
 
@@ -914,9 +914,9 @@
 
   bool IsCatchBlock() const { return catch_dex_file_ != nullptr; }
 
-  bool IsCatchAllTypeIndex() const {
+  bool IsValidTypeIndex() const {
     DCHECK(IsCatchBlock());
-    return !catch_type_index_.IsValid();
+    return catch_type_index_.IsValid();
   }
 
   dex::TypeIndex GetCatchTypeIndex() const {
@@ -929,6 +929,10 @@
     return *catch_dex_file_;
   }
 
+  void SetInvalidTypeIndex() {
+    catch_type_index_ = dex::TypeIndex::Invalid();
+  }
+
  private:
   // One of possibly several TryBoundary instructions entering the block's try.
   // Only set for try blocks.
@@ -936,7 +940,7 @@
 
   // Exception type information. Only set for catch blocks.
   const DexFile* catch_dex_file_;
-  const dex::TypeIndex catch_type_index_;
+  dex::TypeIndex catch_type_index_;
 };
 
 static constexpr size_t kNoLifetime = -1;
diff --git a/compiler/optimizing/reference_type_propagation.cc b/compiler/optimizing/reference_type_propagation.cc
index 61e7a60..4929e0a 100644
--- a/compiler/optimizing/reference_type_propagation.cc
+++ b/compiler/optimizing/reference_type_propagation.cc
@@ -699,14 +699,14 @@
   DCHECK(instr->GetBlock()->IsCatchBlock());
   TryCatchInformation* catch_info = instr->GetBlock()->GetTryCatchInformation();
 
-  if (catch_info->IsCatchAllTypeIndex()) {
-    instr->SetReferenceTypeInfo(
-        ReferenceTypeInfo::Create(handle_cache_->GetThrowableClassHandle(), /* is_exact= */ false));
-  } else {
+  if (catch_info->IsValidTypeIndex()) {
     UpdateReferenceTypeInfo(instr,
                             catch_info->GetCatchTypeIndex(),
                             catch_info->GetCatchDexFile(),
                             /* is_exact= */ false);
+  } else {
+    instr->SetReferenceTypeInfo(
+        ReferenceTypeInfo::Create(handle_cache_->GetThrowableClassHandle(), /* is_exact= */ false));
   }
 }
 
diff --git a/dex2oat/dex2oat_test.cc b/dex2oat/dex2oat_test.cc
index fd454f0..524bce0 100644
--- a/dex2oat/dex2oat_test.cc
+++ b/dex2oat/dex2oat_test.cc
@@ -1011,6 +1011,10 @@
 }
 
 TEST_F(Dex2oatWatchdogTest, TestWatchdogTrigger) {
+  // This test is frequently interrupted by timeout_dumper on host (x86);
+  // disable it while we investigate (b/121352534).
+  TEST_DISABLED_FOR_X86();
+
   // The watchdog is independent of dex2oat and will not delete intermediates. It is possible
   // that the compilation succeeds and the file is completely written by the time the watchdog
   // kills dex2oat (but the dex2oat threads must have been scheduled pretty badly).
diff --git a/dex2oat/linker/image_writer.cc b/dex2oat/linker/image_writer.cc
index 1331fc3..15ced72 100644
--- a/dex2oat/linker/image_writer.cc
+++ b/dex2oat/linker/image_writer.cc
@@ -49,6 +49,7 @@
 #include "gc/heap-visit-objects-inl.h"
 #include "gc/heap.h"
 #include "gc/space/large_object_space.h"
+#include "gc/space/region_space.h"
 #include "gc/space/space-inl.h"
 #include "gc/verification.h"
 #include "handle_scope-inl.h"
@@ -2423,10 +2424,33 @@
   }
 
   // Calculate bin slot offsets.
-  for (ImageInfo& image_info : image_infos_) {
+  for (size_t oat_index = 0; oat_index < image_infos_.size(); ++oat_index) {
+    ImageInfo& image_info = image_infos_[oat_index];
     size_t bin_offset = image_objects_offset_begin_;
+    // Need to visit the objects in bin order since alignment requirements might change the
+    // section sizes.
+    // Avoid using ObjPtr since VisitObjects invalidates. This is safe since concurrent GC can not
+    // occur during image writing.
+    using BinPair = std::pair<BinSlot, mirror::Object*>;
+    std::vector<BinPair> objects;
+    heap->VisitObjects([&](mirror::Object* obj)
+        REQUIRES_SHARED(Locks::mutator_lock_) {
+      // Only visit the oat index for the current image.
+      if (IsImageObject(obj) && GetOatIndex(obj) == oat_index) {
+        objects.emplace_back(GetImageBinSlot(obj), obj);
+      }
+    });
+    std::sort(objects.begin(), objects.end(), [](const BinPair& a, const BinPair& b) -> bool {
+      if (a.first.GetBin() != b.first.GetBin()) {
+        return a.first.GetBin() < b.first.GetBin();
+      }
+      // Note that the index is really the relative offset in this case.
+      return a.first.GetIndex() < b.first.GetIndex();
+    });
+    auto it = objects.begin();
     for (size_t i = 0; i != kNumberOfBins; ++i) {
-      switch (static_cast<Bin>(i)) {
+      Bin bin = enum_cast<Bin>(i);
+      switch (bin) {
         case Bin::kArtMethodClean:
         case Bin::kArtMethodDirty: {
           bin_offset = RoundUp(bin_offset, method_alignment);
@@ -2445,13 +2469,49 @@
         }
       }
       image_info.bin_slot_offsets_[i] = bin_offset;
-      bin_offset += image_info.bin_slot_sizes_[i];
+
+      // If the bin is for mirror objects, assign the offsets since we may need to change sizes
+      // from alignment requirements.
+      if (i < static_cast<size_t>(Bin::kMirrorCount)) {
+        const size_t start_offset = bin_offset;
+        // Visit and assign offsets for all objects of the bin type.
+        while (it != objects.end() && it->first.GetBin() == bin) {
+          ObjPtr<mirror::Object> obj(it->second);
+          const size_t object_size = RoundUp(obj->SizeOf(), kObjectAlignment);
+          // If the object spans region bondaries, add padding objects between.
+          // TODO: Instead of adding padding, we should consider reordering the bins to reduce
+          // wasted space.
+          if (region_size_ != 0u) {
+            const size_t offset_after_header = bin_offset - sizeof(ImageHeader);
+            const size_t next_region = RoundUp(offset_after_header, region_size_);
+            if (offset_after_header != next_region &&
+                offset_after_header + object_size > next_region) {
+              // Add padding objects until aligned.
+              while (bin_offset - sizeof(ImageHeader) < next_region) {
+                image_info.padding_object_offsets_.push_back(bin_offset);
+                bin_offset += kObjectAlignment;
+                region_alignment_wasted_ += kObjectAlignment;
+                image_info.image_end_ += kObjectAlignment;
+              }
+              CHECK_EQ(bin_offset - sizeof(ImageHeader), next_region);
+            }
+          }
+          SetImageOffset(obj.Ptr(), bin_offset);
+          bin_offset = bin_offset + object_size;
+          ++it;
+        }
+        image_info.bin_slot_sizes_[i] = bin_offset - start_offset;
+      } else {
+        bin_offset += image_info.bin_slot_sizes_[i];
+      }
     }
     // NOTE: There may be additional padding between the bin slots and the intern table.
     DCHECK_EQ(image_info.image_end_,
               image_info.GetBinSizeSum(Bin::kMirrorCount) + image_objects_offset_begin_);
   }
 
+  VLOG(image) << "Space wasted for region alignment " << region_alignment_wasted_;
+
   // Calculate image offsets.
   size_t image_offset = 0;
   for (ImageInfo& image_info : image_infos_) {
@@ -2462,17 +2522,6 @@
     image_offset += image_info.image_size_;
   }
 
-  // Transform each object's bin slot into an offset which will be used to do the final copy.
-  {
-    auto unbin_objects_into_offset = [&](mirror::Object* obj)
-        REQUIRES_SHARED(Locks::mutator_lock_) {
-      if (IsImageObject(obj)) {
-        UnbinObjectsIntoOffset(obj);
-      }
-    };
-    heap->VisitObjects(unbin_objects_into_offset);
-  }
-
   size_t i = 0;
   for (ImageInfo& image_info : image_infos_) {
     image_info.image_roots_address_ = PointerToLowMemUInt32(GetImageAddress(image_roots[i].Get()));
@@ -2887,16 +2936,6 @@
   }
 }
 
-void ImageWriter::CopyAndFixupObjects() {
-  auto visitor = [&](Object* obj) REQUIRES_SHARED(Locks::mutator_lock_) {
-    DCHECK(obj != nullptr);
-    CopyAndFixupObject(obj);
-  };
-  Runtime::Current()->GetHeap()->VisitObjects(visitor);
-  // We no longer need the hashcode map, values have already been copied to target objects.
-  saved_hashcode_map_.clear();
-}
-
 void ImageWriter::FixupPointerArray(mirror::Object* dst,
                                     mirror::PointerArray* arr,
                                     Bin array_type) {
@@ -2944,6 +2983,18 @@
   image_info.image_bitmap_->Set(dst);  // Mark the obj as live.
 
   const size_t n = obj->SizeOf();
+
+  if (kIsDebugBuild && region_size_ != 0u) {
+    const size_t offset_after_header = offset - sizeof(ImageHeader);
+    const size_t next_region = RoundUp(offset_after_header, region_size_);
+    if (offset_after_header != next_region) {
+      // If the object is not on a region bondary, it must not be cross region.
+      CHECK_LT(offset_after_header, next_region)
+          << "offset_after_header=" << offset_after_header << " size=" << n;
+      CHECK_LE(offset_after_header + n, next_region)
+          << "offset_after_header=" << offset_after_header << " size=" << n;
+    }
+  }
   DCHECK_LE(offset + n, image_info.image_.Size());
   memcpy(dst, src, n);
 
@@ -2973,7 +3024,6 @@
       const {}
   void VisitRoot(mirror::CompressedReference<mirror::Object>* root ATTRIBUTE_UNUSED) const {}
 
-
   void operator()(ObjPtr<Object> obj, MemberOffset offset, bool is_static ATTRIBUTE_UNUSED) const
       REQUIRES_SHARED(Locks::mutator_lock_) REQUIRES(Locks::heap_bitmap_lock_) {
     ObjPtr<Object> ref = obj->GetFieldObject<Object, kVerifyNone>(offset);
@@ -2994,6 +3044,25 @@
   mirror::Object* const copy_;
 };
 
+void ImageWriter::CopyAndFixupObjects() {
+  auto visitor = [&](Object* obj) REQUIRES_SHARED(Locks::mutator_lock_) {
+    DCHECK(obj != nullptr);
+    CopyAndFixupObject(obj);
+  };
+  Runtime::Current()->GetHeap()->VisitObjects(visitor);
+  // Copy the padding objects since they are required for in order traversal of the image space.
+  for (const ImageInfo& image_info : image_infos_) {
+    for (const size_t offset : image_info.padding_object_offsets_) {
+      auto* dst = reinterpret_cast<Object*>(image_info.image_.Begin() + offset);
+      dst->SetClass<kVerifyNone>(GetImageAddress(GetClassRoot<mirror::Object>().Ptr()));
+      dst->SetLockWord<kVerifyNone>(LockWord::Default(), /*as_volatile=*/ false);
+      image_info.image_bitmap_->Set(dst);  // Mark the obj as live.
+    }
+  }
+  // We no longer need the hashcode map, values have already been copied to target objects.
+  saved_hashcode_map_.clear();
+}
+
 class ImageWriter::FixupClassVisitor final : public FixupVisitor {
  public:
   FixupClassVisitor(ImageWriter* image_writer, Object* copy)
@@ -3572,6 +3641,10 @@
   CHECK_EQ(compiler_options.IsBootImage(),
            Runtime::Current()->GetHeap()->GetBootImageSpaces().empty())
       << "Compiling a boot image should occur iff there are no boot image spaces loaded";
+  if (compiler_options_.IsAppImage()) {
+    // Make sure objects are not crossing region boundaries for app images.
+    region_size_ = gc::space::RegionSpace::kRegionSize;
+  }
 }
 
 ImageWriter::ImageInfo::ImageInfo()
diff --git a/dex2oat/linker/image_writer.h b/dex2oat/linker/image_writer.h
index b680265..8896e07 100644
--- a/dex2oat/linker/image_writer.h
+++ b/dex2oat/linker/image_writer.h
@@ -279,7 +279,7 @@
 
    private:
     // Must be the same size as LockWord, any larger and we would truncate the data.
-    const uint32_t lockword_;
+    uint32_t lockword_;
   };
 
   struct ImageInfo {
@@ -397,6 +397,9 @@
 
     // Class table associated with this image for serialization.
     std::unique_ptr<ClassTable> class_table_;
+
+    // Padding objects to ensure region alignment (if required).
+    std::vector<size_t> padding_object_offsets_;
   };
 
   // We use the lock word to store the offset of the object in the image.
@@ -798,6 +801,12 @@
   // Set of objects known to be dirty in the image. Can be nullptr if there are none.
   const HashSet<std::string>* dirty_image_objects_;
 
+  // Objects are guaranteed to not cross the region size boundary.
+  size_t region_size_ = 0u;
+
+  // Region alignment bytes wasted.
+  size_t region_alignment_wasted_ = 0u;
+
   class ImageFileGuard;
   class FixupClassVisitor;
   class FixupRootVisitor;
diff --git a/dex2oat/linker/oat_writer.h b/dex2oat/linker/oat_writer.h
index cc0e83a..48215bb 100644
--- a/dex2oat/linker/oat_writer.h
+++ b/dex2oat/linker/oat_writer.h
@@ -19,6 +19,7 @@
 
 #include <stdint.h>
 #include <cstddef>
+#include <list>
 #include <memory>
 #include <vector>
 
diff --git a/dexoptanalyzer/dexoptanalyzer.cc b/dexoptanalyzer/dexoptanalyzer.cc
index acf0f94..92850f7 100644
--- a/dexoptanalyzer/dexoptanalyzer.cc
+++ b/dexoptanalyzer/dexoptanalyzer.cc
@@ -202,11 +202,7 @@
             Usage("Invalid --zip-fd %d", zip_fd_);
           }
       } else if (option.starts_with("--class-loader-context=")) {
-        std::string context_str = option.substr(strlen("--class-loader-context=")).ToString();
-        class_loader_context_ = ClassLoaderContext::Create(context_str);
-        if (class_loader_context_ == nullptr) {
-          Usage("Invalid --class-loader-context '%s'", context_str.c_str());
-        }
+        context_str_ = option.substr(strlen("--class-loader-context=")).ToString();
       } else {
         Usage("Unknown argument '%s'", option.data());
       }
@@ -264,6 +260,17 @@
     }
     std::unique_ptr<Runtime> runtime(Runtime::Current());
 
+    // Only when the runtime is created can we create the class loader context: the
+    // class loader context will open dex file and use the MemMap global lock that the
+    // runtime owns.
+    std::unique_ptr<ClassLoaderContext> class_loader_context;
+    if (!context_str_.empty()) {
+      class_loader_context = ClassLoaderContext::Create(context_str_);
+      if (class_loader_context == nullptr) {
+        Usage("Invalid --class-loader-context '%s'", context_str_.c_str());
+      }
+    }
+
     std::unique_ptr<OatFileAssistant> oat_file_assistant;
     oat_file_assistant = std::make_unique<OatFileAssistant>(dex_file_.c_str(),
                                                             isa_,
@@ -279,7 +286,7 @@
     }
 
     int dexoptNeeded = oat_file_assistant->GetDexOptNeeded(
-        compiler_filter_, assume_profile_changed_, downgrade_, class_loader_context_.get());
+        compiler_filter_, assume_profile_changed_, downgrade_, class_loader_context.get());
 
     // Convert OatFileAssitant codes to dexoptanalyzer codes.
     switch (dexoptNeeded) {
@@ -300,7 +307,7 @@
   std::string dex_file_;
   InstructionSet isa_;
   CompilerFilter::Filter compiler_filter_;
-  std::unique_ptr<ClassLoaderContext> class_loader_context_;
+  std::string context_str_;
   bool assume_profile_changed_;
   bool downgrade_;
   std::string image_;
diff --git a/dexoptanalyzer/dexoptanalyzer_test.cc b/dexoptanalyzer/dexoptanalyzer_test.cc
index f6fd1fb..7b6b36c 100644
--- a/dexoptanalyzer/dexoptanalyzer_test.cc
+++ b/dexoptanalyzer/dexoptanalyzer_test.cc
@@ -36,7 +36,8 @@
 
   int Analyze(const std::string& dex_file,
               CompilerFilter::Filter compiler_filter,
-              bool assume_profile_changed) {
+              bool assume_profile_changed,
+              const std::string& class_loader_context) {
     std::string dexoptanalyzer_cmd = GetDexoptAnalyzerCmd();
     std::vector<std::string> argv_str;
     argv_str.push_back(dexoptanalyzer_cmd);
@@ -52,6 +53,9 @@
     argv_str.push_back(GetClassPathOption("-Xbootclasspath-locations:", GetLibCoreDexLocations()));
     argv_str.push_back("--image=" + GetImageLocation());
     argv_str.push_back("--android-data=" + android_data_);
+    if (!class_loader_context.empty()) {
+      argv_str.push_back("--class-loader-context=" + class_loader_context);
+    }
 
     std::string error;
     return ExecAndReturnCode(argv_str, &error);
@@ -74,8 +78,10 @@
   void Verify(const std::string& dex_file,
               CompilerFilter::Filter compiler_filter,
               bool assume_profile_changed = false,
-              bool downgrade = false) {
-    int dexoptanalyzerResult = Analyze(dex_file, compiler_filter, assume_profile_changed);
+              bool downgrade = false,
+              const std::string& class_loader_context = "") {
+    int dexoptanalyzerResult = Analyze(
+        dex_file, compiler_filter, assume_profile_changed, class_loader_context);
     dexoptanalyzerResult = DexoptanalyzerToOatFileAssistant(dexoptanalyzerResult);
     OatFileAssistant oat_file_assistant(dex_file.c_str(), kRuntimeISA, /*load_executable=*/ false);
     int assistantResult = oat_file_assistant.GetDexOptNeeded(
@@ -305,4 +311,22 @@
   Verify(dex_location, CompilerFilter::kSpeed);
 }
 
+// Case: We have a DEX file and up-to-date OAT file for it, and we check with
+// a class loader context.
+TEST_F(DexoptAnalyzerTest, ClassLoaderContext) {
+  std::string dex_location1 = GetScratchDir() + "/DexToAnalyze.jar";
+  std::string odex_location1 = GetOdexDir() + "/DexToAnalyze.odex";
+  std::string dex_location2 = GetScratchDir() + "/DexInContext.jar";
+  Copy(GetDexSrc1(), dex_location1);
+  Copy(GetDexSrc2(), dex_location2);
+
+  std::string class_loader_context = "PCL[" + dex_location2 + "]";
+  std::string class_loader_context_option = "--class-loader-context=PCL[" + dex_location2 + "]";
+
+  // Generate the odex to get the class loader context also open the dex files.
+  GenerateOdexForTest(dex_location1, odex_location1, CompilerFilter::kSpeed, /* compilation_reason= */ nullptr, /* extra_args= */ { class_loader_context_option });
+
+  Verify(dex_location1, CompilerFilter::kSpeed, false, false, class_loader_context);
+}
+
 }  // namespace art
diff --git a/libart_fake/Android.mk b/libart_fake/Android.mk
deleted file mode 100644
index 96e6a14..0000000
--- a/libart_fake/Android.mk
+++ /dev/null
@@ -1,35 +0,0 @@
-# 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.
-#
-
-LOCAL_PATH := $(my-dir)
-
-include $(CLEAR_VARS)
-
-LOCAL_MODULE := libart_fake
-LOCAL_INSTALLED_MODULE_STEM := libart.so
-LOCAL_SDK_VERSION := 9
-LOCAL_CPP_EXTENSION := .cc
-LOCAL_SRC_FILES := fake.cc
-LOCAL_CFLAGS := -Wall -Werror
-LOCAL_SHARED_LIBRARIES := liblog
-
-ifdef TARGET_2ND_ARCH
-    LOCAL_MODULE_PATH_32 := $(TARGET_OUT)/fake-libs
-    LOCAL_MODULE_PATH_64 := $(TARGET_OUT)/fake-libs64
-else
-    LOCAL_MODULE_PATH := $(TARGET_OUT)/fake-libs
-endif
-
-include $(BUILD_SHARED_LIBRARY)
diff --git a/libart_fake/README.md b/libart_fake/README.md
deleted file mode 100644
index 6e3621e..0000000
--- a/libart_fake/README.md
+++ /dev/null
@@ -1,5 +0,0 @@
-libart_fake
-====
-
-A fake libart made to satisfy some misbehaving apps that will attempt to link
-against libart.so.
diff --git a/libart_fake/fake.cc b/libart_fake/fake.cc
deleted file mode 100644
index 8842421..0000000
--- a/libart_fake/fake.cc
+++ /dev/null
@@ -1,46 +0,0 @@
-/*
- * Copyright 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.
- */
-
-#define LOG_TAG "libart_fake"
-
-#include <android/log.h>
-
-#define LOGIT(...) __android_log_print(ANDROID_LOG_ERROR, LOG_TAG, __VA_ARGS__)
-namespace art {
-class Dbg {
- public:
-  void SuspendVM();
-  void ResumeVM();
-};
-
-class FaultManager {
- public:
-  void EnsureArtActionInFrontOfSignalChain();
-};
-
-void Dbg::SuspendVM() {
-  LOGIT("Linking to and calling into libart.so internal functions is not supported. "
-        "This call to '%s' is being ignored.", __func__);
-}
-void Dbg::ResumeVM() {
-  LOGIT("Linking to and calling into libart.so internal functions is not supported. "
-        "This call to '%s' is being ignored.", __func__);
-}
-void FaultManager::EnsureArtActionInFrontOfSignalChain() {
-  LOGIT("Linking to and calling into libart.so internal functions is not supported. "
-        "This call to '%s' is being ignored.", __func__);
-}
-};  // namespace art
diff --git a/libartbase/Android.bp b/libartbase/Android.bp
index 109853c..509b072 100644
--- a/libartbase/Android.bp
+++ b/libartbase/Android.bp
@@ -24,6 +24,7 @@
         "base/arena_allocator.cc",
         "base/arena_bit_vector.cc",
         "base/bit_vector.cc",
+        "base/enums.cc",
         "base/file_magic.cc",
         "base/file_utils.cc",
         "base/hex_dump.cc",
@@ -153,7 +154,6 @@
     srcs: [
         "arch/instruction_set.h",
         "base/allocator.h",
-        "base/callee_save_type.h",
         "base/unix_file/fd_file.h",
     ],
     output_extension: "operator_out.cc",
diff --git a/libartbase/base/enums.cc b/libartbase/base/enums.cc
new file mode 100644
index 0000000..3f28232
--- /dev/null
+++ b/libartbase/base/enums.cc
@@ -0,0 +1,32 @@
+/*
+ * 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.
+ */
+
+#include "enums.h"
+
+#include <ostream>
+
+namespace art {
+
+std::ostream& operator<<(std::ostream& os, const PointerSize& rhs) {
+  switch (rhs) {
+    case PointerSize::k32: os << "k32"; break;
+    case PointerSize::k64: os << "k64"; break;
+    default: os << "PointerSize[" << static_cast<int>(rhs) << "]"; break;
+  }
+  return os;
+}
+
+}  // namespace art
diff --git a/libartbase/base/enums.h b/libartbase/base/enums.h
index ad5578f..c5fb880 100644
--- a/libartbase/base/enums.h
+++ b/libartbase/base/enums.h
@@ -18,7 +18,7 @@
 #define ART_LIBARTBASE_BASE_ENUMS_H_
 
 #include <cstddef>
-#include <ostream>
+#include <iosfwd>
 
 namespace art {
 
@@ -27,14 +27,7 @@
   k64 = 8
 };
 
-inline std::ostream& operator<<(std::ostream& os, const PointerSize& rhs) {
-  switch (rhs) {
-    case PointerSize::k32: os << "k32"; break;
-    case PointerSize::k64: os << "k64"; break;
-    default: os << "PointerSize[" << static_cast<int>(rhs) << "]"; break;
-  }
-  return os;
-}
+std::ostream& operator<<(std::ostream& os, const PointerSize& rhs);
 
 static constexpr PointerSize kRuntimePointerSize = sizeof(void*) == 8U
                                                        ? PointerSize::k64
diff --git a/libartbase/base/globals.h b/libartbase/base/globals.h
index 2a2a737..97eae63 100644
--- a/libartbase/base/globals.h
+++ b/libartbase/base/globals.h
@@ -38,20 +38,6 @@
 // compile-time constant so the compiler can generate better code.
 static constexpr int kPageSize = 4096;
 
-// Size of Dex virtual registers.
-static constexpr size_t kVRegSize = 4;
-
-// Returns whether the given memory offset can be used for generating
-// an implicit null check.
-static inline bool CanDoImplicitNullCheckOn(uintptr_t offset) {
-  return offset < kPageSize;
-}
-
-// Required object alignment
-static constexpr size_t kObjectAlignmentShift = 3;
-static constexpr size_t kObjectAlignment = 1u << kObjectAlignmentShift;
-static constexpr size_t kLargeObjectAlignment = kPageSize;
-
 // Clion, clang analyzer, etc can falsely believe that "if (kIsDebugBuild)" always
 // returns the same value. By wrapping into a call to another constexpr function, we force it
 // to realize that is not actually always evaluating to the same value.
@@ -117,48 +103,6 @@
 static constexpr bool kHostStaticBuildEnabled = false;
 #endif
 
-// Garbage collector constants.
-static constexpr bool kMovingCollector = true;
-static constexpr bool kMarkCompactSupport = false && kMovingCollector;
-// True if we allow moving classes.
-static constexpr bool kMovingClasses = !kMarkCompactSupport;
-// If true, enable generational collection when using the Concurrent Copying
-// (CC) collector, i.e. use sticky-bit CC for minor collections and (full) CC
-// for major collections.
-//
-// Generational CC collection is currently only compatible with Baker read
-// barriers.
-#if defined(ART_USE_GENERATIONAL_CC) && defined(ART_READ_BARRIER_TYPE_IS_BAKER)
-static constexpr bool kEnableGenerationalConcurrentCopyingCollection = true;
-#else
-static constexpr bool kEnableGenerationalConcurrentCopyingCollection = false;
-#endif
-
-// If true, enable the tlab allocator by default.
-#ifdef ART_USE_TLAB
-static constexpr bool kUseTlab = true;
-#else
-static constexpr bool kUseTlab = false;
-#endif
-
-// Kinds of tracing clocks.
-enum class TraceClockSource {
-  kThreadCpu,
-  kWall,
-  kDual,  // Both wall and thread CPU clocks.
-};
-
-#if defined(__linux__)
-static constexpr TraceClockSource kDefaultTraceClockSource = TraceClockSource::kDual;
-#else
-static constexpr TraceClockSource kDefaultTraceClockSource = TraceClockSource::kWall;
-#endif
-
-static constexpr bool kDefaultMustRelocate = true;
-
-// Size of a heap reference.
-static constexpr size_t kHeapReferenceSize = sizeof(uint32_t);
-
 }  // namespace art
 
 #endif  // ART_LIBARTBASE_BASE_GLOBALS_H_
diff --git a/libartbase/base/logging.h b/libartbase/base/logging.h
index 9ded082..484db87 100644
--- a/libartbase/base/logging.h
+++ b/libartbase/base/logging.h
@@ -17,9 +17,6 @@
 #ifndef ART_LIBARTBASE_BASE_LOGGING_H_
 #define ART_LIBARTBASE_BASE_LOGGING_H_
 
-#include <ostream>
-#include <sstream>
-
 #include "android-base/logging.h"
 #include "macros.h"
 
diff --git a/libdexfile/Android.bp b/libdexfile/Android.bp
index 9c48aa2..2f56a3d 100644
--- a/libdexfile/Android.bp
+++ b/libdexfile/Android.bp
@@ -176,6 +176,36 @@
     },
 }
 
+art_cc_test {
+    name: "art_libdexfile_tests",
+    defaults: [
+        "art_gtest_defaults",
+    ],
+    srcs: [
+        "dex/art_dex_file_loader_test.cc",
+        "dex/class_accessor_test.cc",
+        "dex/code_item_accessors_test.cc",
+        "dex/compact_dex_file_test.cc",
+        "dex/compact_offset_table_test.cc",
+        "dex/descriptors_names_test.cc",
+        "dex/test_dex_file_builder_test.cc",
+        "dex/dex_file_loader_test.cc",
+        "dex/dex_file_verifier_test.cc",
+        "dex/dex_instruction_test.cc",
+        "dex/primitive_test.cc",
+        "dex/string_reference_test.cc",
+        "dex/type_lookup_table_test.cc",
+        "dex/utf_test.cc",
+    ],
+    shared_libs: [
+        "libbacktrace",
+        "libziparchive",
+    ],
+    include_dirs: [
+        "external/zlib",
+    ],
+}
+
 cc_library_headers {
     name: "libdexfile_external_headers",
     host_supported: true,
@@ -227,6 +257,16 @@
     },
 }
 
+art_cc_test {
+    name: "art_libdexfile_external_tests",
+    host_supported: true,
+    test_per_src: true,  // For consistency with other ART gtests.
+    srcs: [
+        "external/dex_file_ext_c_test.c",
+    ],
+    header_libs: ["libdexfile_external_headers"],
+}
+
 // Support library with a C++ API for accessing the libdexfile API for external
 // (non-ART) users. They should link to their own instance of this (either
 // statically or through linker namespaces).
@@ -242,31 +282,16 @@
 }
 
 art_cc_test {
-    name: "art_libdexfile_tests",
-    defaults: [
-        "art_gtest_defaults",
-    ],
+    name: "art_libdexfile_support_tests",
+    host_supported: true,
+    test_per_src: true,  // For consistency with other ART gtests.
     srcs: [
-        "dex/art_dex_file_loader_test.cc",
-        "dex/class_accessor_test.cc",
-        "dex/code_item_accessors_test.cc",
-        "dex/compact_dex_file_test.cc",
-        "dex/compact_offset_table_test.cc",
-        "dex/descriptors_names_test.cc",
-        "dex/test_dex_file_builder_test.cc",
-        "dex/dex_file_loader_test.cc",
-        "dex/dex_file_verifier_test.cc",
-        "dex/dex_instruction_test.cc",
-        "dex/primitive_test.cc",
-        "dex/string_reference_test.cc",
-        "dex/type_lookup_table_test.cc",
-        "dex/utf_test.cc",
+        "external/dex_file_supp_test.cc",
     ],
     shared_libs: [
-        "libbacktrace",
-        "libziparchive",
-    ],
-    include_dirs: [
-        "external/zlib",
+        "libartbase",
+        "libbase",
+        "libdexfile_external",
+        "libdexfile_support",
     ],
 }
diff --git a/libdexfile/dex/dex_file.cc b/libdexfile/dex/dex_file.cc
index 5c100e6..d3cdf13 100644
--- a/libdexfile/dex/dex_file.cc
+++ b/libdexfile/dex/dex_file.cc
@@ -23,6 +23,7 @@
 #include <zlib.h>
 
 #include <memory>
+#include <ostream>
 #include <sstream>
 #include <type_traits>
 
diff --git a/libdexfile/dex/dex_file_types.h b/libdexfile/dex/dex_file_types.h
index d4fb3de..ecc0482 100644
--- a/libdexfile/dex/dex_file_types.h
+++ b/libdexfile/dex/dex_file_types.h
@@ -17,8 +17,9 @@
 #ifndef ART_LIBDEXFILE_DEX_DEX_FILE_TYPES_H_
 #define ART_LIBDEXFILE_DEX_DEX_FILE_TYPES_H_
 
+#include <iosfwd>
 #include <limits>
-#include <ostream>
+#include <utility>
 
 namespace art {
 namespace dex {
diff --git a/libdexfile/external/dex_file_ext.cc b/libdexfile/external/dex_file_ext.cc
index 5c353b5..e1b7874 100644
--- a/libdexfile/external/dex_file_ext.cc
+++ b/libdexfile/external/dex_file_ext.cc
@@ -14,6 +14,8 @@
  * limitations under the License.
  */
 
+#include "art_api/dex_file_external.h"
+
 #include <inttypes.h>
 #include <stdint.h>
 #include <sys/mman.h>
@@ -39,18 +41,9 @@
 #include <dex/dex_file-inl.h>
 #include <dex/dex_file_loader.h>
 
-#include "art_api/ext_dex_file.h"
-
-extern "C" class ExtDexFileString {
- public:
-  const std::string str_;
-};
-
 namespace art {
 namespace {
 
-const ExtDexFileString empty_string{""};
-
 struct MethodCacheEntry {
   int32_t offset;  // Offset relative to the start of the dex file header.
   int32_t len;
@@ -77,11 +70,17 @@
 
 extern "C" {
 
-const ExtDexFileString* ExtDexFileMakeString(const char* str) {
-  if (str[0] == '\0') {
-    return &art::empty_string;
+struct ExtDexFileString {
+  const std::string str_;
+};
+
+static const ExtDexFileString empty_string{""};
+
+const ExtDexFileString* ExtDexFileMakeString(const char* str, size_t size) {
+  if (size == 0) {
+    return &empty_string;
   }
-  return new ExtDexFileString{str};
+  return new ExtDexFileString{std::string(str, size)};
 }
 
 const char* ExtDexFileGetString(const ExtDexFileString* ext_string, /*out*/ size_t* size) {
@@ -92,14 +91,15 @@
 
 void ExtDexFileFreeString(const ExtDexFileString* ext_string) {
   DCHECK(ext_string != nullptr);
-  if (ext_string != &art::empty_string) {
+  if (ext_string != &empty_string) {
     delete (ext_string);
   }
 }
 
 // Wraps DexFile to add the caching needed by the external interface. This is
 // what gets passed over as ExtDexFile*.
-class ExtDexFile {
+struct ExtDexFile {
+ private:
   // Method cache for GetMethodInfoForOffset. This is populated as we iterate
   // sequentially through the class defs. MethodCacheEntry.name is only set for
   // methods returned by GetMethodInfoForOffset.
@@ -226,7 +226,10 @@
 
   if (length < offset + sizeof(art::DexFile::Header)) {
     *ext_error_msg = new ExtDexFileString{android::base::StringPrintf(
-        "Offset %" PRId64 " too large for '%s' of size %zu", int64_t{offset}, location, length)};
+        "Offset %" PRId64 " too large for '%s' of size %zu",
+        int64_t{offset},
+        location,
+        length)};
     return false;
   }
 
@@ -282,6 +285,7 @@
 
 int ExtDexFileGetMethodInfoForOffset(ExtDexFile* ext_dex_file,
                                      int64_t dex_offset,
+                                     int with_signature,
                                      /*out*/ ExtDexFileMethodInfo* method_info) {
   if (!ext_dex_file->dex_file_->IsInDataSection(ext_dex_file->dex_file_->Begin() + dex_offset)) {
     return false;  // The DEX offset is not within the bytecode of this dex file.
@@ -304,7 +308,7 @@
     method_info->offset = entry->offset;
     method_info->len = entry->len;
     method_info->name =
-        new ExtDexFileString{ext_dex_file->dex_file_->PrettyMethod(entry->index, false)};
+        new ExtDexFileString{ext_dex_file->dex_file_->PrettyMethod(entry->index, with_signature)};
     return true;
   }
 
diff --git a/libdexfile/external/dex_file_ext_c_test.c b/libdexfile/external/dex_file_ext_c_test.c
new file mode 100644
index 0000000..85cd46e
--- /dev/null
+++ b/libdexfile/external/dex_file_ext_c_test.c
@@ -0,0 +1,55 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <errno.h>
+#include <stdio.h>
+#include <string.h>
+
+/* The main purpose of this test is to ensure this C header compiles in C, so
+ * that no C++ features inadvertently leak into the C ABI. */
+#include "art_api/dex_file_external.h"
+
+static const char gtest_output_arg[] = "--gtest_output=xml:";
+static const char gtest_output_xml[] = "\
+<?xml version=\"1.0\"?>\n\
+<testsuites tests=\"0\" failures=\"0\" disabled=\"0\" errors=\"0\" name=\"AllTests\">";
+
+/* Writes a dummy gtest xml report to the given path. */
+static int write_gtest_output_xml(char* gtest_output_path) {
+  FILE* output_fd = fopen(gtest_output_path, "w");
+  if (output_fd == NULL) {
+    fprintf(stderr, "Failed to open %s: %s\n", gtest_output_path, strerror(errno));
+    return 1;
+  }
+  if (fprintf(output_fd, gtest_output_xml) != sizeof(gtest_output_xml) - 1) {
+    fprintf(stderr, "Failed to write %s: %s\n", gtest_output_path, strerror(errno));
+    fclose(output_fd);
+    return 1;
+  }
+  if (fclose(output_fd) != 0) {
+    fprintf(stderr, "Failed to close %s: %s\n", gtest_output_path, strerror(errno));
+    return 1;
+  }
+  return 0;
+}
+
+int main(int argc, char** argv) {
+  if (argc >= 1 && strncmp(argv[1], gtest_output_arg, sizeof(gtest_output_arg) - 1) == 0) {
+    /* The ART gtest framework expects all tests to understand --gtest_output. */
+    return write_gtest_output_xml(argv[1] + sizeof(gtest_output_arg) - 1);
+  }
+  return 0;
+}
diff --git a/libdexfile/external/dex_file_supp.cc b/libdexfile/external/dex_file_supp.cc
index 6514c8a..5bd25fc 100644
--- a/libdexfile/external/dex_file_supp.cc
+++ b/libdexfile/external/dex_file_supp.cc
@@ -14,7 +14,7 @@
  * limitations under the License.
  */
 
-#include "art_api/ext_dex_file.h"
+#include "art_api/dex_file_support.h"
 
 namespace art_api {
 namespace dex {
diff --git a/libdexfile/external/dex_file_supp_test.cc b/libdexfile/external/dex_file_supp_test.cc
new file mode 100644
index 0000000..2f7ad50
--- /dev/null
+++ b/libdexfile/external/dex_file_supp_test.cc
@@ -0,0 +1,289 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <sys/types.h>
+
+#include <memory>
+#include <string>
+#include <string_view>
+
+#include <android-base/file.h>
+#include <dex/dex_file.h>
+#include <gtest/gtest.h>
+
+#include "art_api/dex_file_support.h"
+
+namespace art_api {
+namespace dex {
+
+static constexpr uint32_t kDexData[] = {
+    0x0a786564, 0x00383330, 0xc98b3ab8, 0xf3749d94, 0xaecca4d8, 0xffc7b09a, 0xdca9ca7f, 0x5be5deab,
+    0x00000220, 0x00000070, 0x12345678, 0x00000000, 0x00000000, 0x0000018c, 0x00000008, 0x00000070,
+    0x00000004, 0x00000090, 0x00000002, 0x000000a0, 0x00000000, 0x00000000, 0x00000003, 0x000000b8,
+    0x00000001, 0x000000d0, 0x00000130, 0x000000f0, 0x00000122, 0x0000012a, 0x00000132, 0x00000146,
+    0x00000151, 0x00000154, 0x00000158, 0x0000016d, 0x00000001, 0x00000002, 0x00000004, 0x00000006,
+    0x00000004, 0x00000002, 0x00000000, 0x00000005, 0x00000002, 0x0000011c, 0x00000000, 0x00000000,
+    0x00010000, 0x00000007, 0x00000001, 0x00000000, 0x00000000, 0x00000001, 0x00000001, 0x00000000,
+    0x00000003, 0x00000000, 0x0000017e, 0x00000000, 0x00010001, 0x00000001, 0x00000173, 0x00000004,
+    0x00021070, 0x000e0000, 0x00010001, 0x00000000, 0x00000178, 0x00000001, 0x0000000e, 0x00000001,
+    0x3c060003, 0x74696e69, 0x4c06003e, 0x6e69614d, 0x4c12003b, 0x6176616a, 0x6e616c2f, 0x624f2f67,
+    0x7463656a, 0x4d09003b, 0x2e6e6961, 0x6176616a, 0x00560100, 0x004c5602, 0x6a4c5b13, 0x2f617661,
+    0x676e616c, 0x7274532f, 0x3b676e69, 0x616d0400, 0x01006e69, 0x000e0700, 0x07000103, 0x0000000e,
+    0x81000002, 0x01f00480, 0x02880901, 0x0000000c, 0x00000000, 0x00000001, 0x00000000, 0x00000001,
+    0x00000008, 0x00000070, 0x00000002, 0x00000004, 0x00000090, 0x00000003, 0x00000002, 0x000000a0,
+    0x00000005, 0x00000003, 0x000000b8, 0x00000006, 0x00000001, 0x000000d0, 0x00002001, 0x00000002,
+    0x000000f0, 0x00001001, 0x00000001, 0x0000011c, 0x00002002, 0x00000008, 0x00000122, 0x00002003,
+    0x00000002, 0x00000173, 0x00002000, 0x00000001, 0x0000017e, 0x00001000, 0x00000001, 0x0000018c,
+};
+
+TEST(DexStringTest, alloc_string) {
+  auto s = DexString("123");
+  EXPECT_EQ(std::string_view(s), "123");
+}
+
+TEST(DexStringTest, alloc_empty_string) {
+  auto s = DexString("");
+  EXPECT_TRUE(std::string_view(s).empty());
+}
+
+TEST(DexStringTest, move_construct) {
+  auto s1 = DexString("foo");
+  auto s2 = DexString(std::move(s1));
+  EXPECT_TRUE(std::string_view(s1).empty());
+  EXPECT_EQ(std::string_view(s2), "foo");
+}
+
+TEST(DexStringTest, move_assign) {
+  auto s1 = DexString("foo");
+  DexString s2;
+  EXPECT_TRUE(std::string_view(s2).empty());
+  s2 = std::move(s1);
+  EXPECT_TRUE(std::string_view(s1).empty());
+  EXPECT_EQ(std::string_view(s2), "foo");
+}
+
+TEST(DexStringTest, reassign) {
+  auto s = DexString("foo");
+  s = DexString("bar");
+  EXPECT_EQ(std::string_view(s), "bar");
+}
+
+TEST(DexStringTest, data_access) {
+  auto s = DexString("foo");
+  EXPECT_STREQ(s.data(), "foo");
+  EXPECT_STREQ(s.c_str(), "foo");
+}
+
+TEST(DexStringTest, size_access) {
+  auto s = DexString("foo");
+  EXPECT_EQ(s.size(), size_t{3});
+  EXPECT_EQ(s.length(), size_t{3});
+}
+
+TEST(DexStringTest, equality) {
+  auto s = DexString("foo");
+  EXPECT_EQ(s, DexString("foo"));
+  EXPECT_FALSE(s == DexString("bar"));
+}
+
+TEST(DexStringTest, equality_with_nul) {
+  auto s = DexString(std::string("foo\0bar", 7));
+  EXPECT_EQ(s.size(), size_t{7});
+  EXPECT_EQ(s, DexString(std::string("foo\0bar", 7)));
+  EXPECT_FALSE(s == DexString(std::string("foo\0baz", 7)));
+}
+
+TEST(DexFileTest, from_memory_header_too_small) {
+  size_t size = sizeof(art::DexFile::Header) - 1;
+  std::string error_msg;
+  EXPECT_EQ(DexFile::OpenFromMemory(kDexData, &size, "", &error_msg), nullptr);
+  EXPECT_EQ(size, sizeof(art::DexFile::Header));
+  EXPECT_TRUE(error_msg.empty());
+}
+
+TEST(DexFileTest, from_memory_file_too_small) {
+  size_t size = sizeof(art::DexFile::Header);
+  std::string error_msg;
+  EXPECT_EQ(DexFile::OpenFromMemory(kDexData, &size, "", &error_msg), nullptr);
+  EXPECT_EQ(size, sizeof(kDexData));
+  EXPECT_TRUE(error_msg.empty());
+}
+
+static std::unique_ptr<DexFile> GetTestDexData() {
+  size_t size = sizeof(kDexData);
+  std::string error_msg;
+  std::unique_ptr<DexFile> dex_file = DexFile::OpenFromMemory(kDexData, &size, "", &error_msg);
+  EXPECT_TRUE(error_msg.empty());
+  return dex_file;
+}
+
+TEST(DexFileTest, from_memory) {
+  EXPECT_NE(GetTestDexData(), nullptr);
+}
+
+TEST(DexFileTest, from_fd_header_too_small) {
+  TemporaryFile tf;
+  ASSERT_NE(tf.fd, -1);
+  ASSERT_EQ(sizeof(art::DexFile::Header) - 1,
+            static_cast<size_t>(
+                TEMP_FAILURE_RETRY(write(tf.fd, kDexData, sizeof(art::DexFile::Header) - 1))));
+
+  std::string error_msg;
+  EXPECT_EQ(DexFile::OpenFromFd(tf.fd, 0, tf.path, &error_msg), nullptr);
+  EXPECT_FALSE(error_msg.empty());
+}
+
+TEST(DexFileTest, from_fd_file_too_small) {
+  TemporaryFile tf;
+  ASSERT_NE(tf.fd, -1);
+  ASSERT_EQ(sizeof(art::DexFile::Header),
+            static_cast<size_t>(
+                TEMP_FAILURE_RETRY(write(tf.fd, kDexData, sizeof(art::DexFile::Header)))));
+
+  std::string error_msg;
+  EXPECT_EQ(DexFile::OpenFromFd(tf.fd, 0, tf.path, &error_msg), nullptr);
+  EXPECT_FALSE(error_msg.empty());
+}
+
+TEST(DexFileTest, from_fd) {
+  TemporaryFile tf;
+  ASSERT_NE(tf.fd, -1);
+  ASSERT_EQ(sizeof(kDexData),
+            static_cast<size_t>(TEMP_FAILURE_RETRY(write(tf.fd, kDexData, sizeof(kDexData)))));
+
+  std::string error_msg;
+  EXPECT_NE(DexFile::OpenFromFd(tf.fd, 0, tf.path, &error_msg), nullptr);
+  EXPECT_TRUE(error_msg.empty());
+}
+
+TEST(DexFileTest, from_fd_non_zero_offset) {
+  TemporaryFile tf;
+  ASSERT_NE(tf.fd, -1);
+  ASSERT_EQ(0x100, lseek(tf.fd, 0x100, SEEK_SET));
+  ASSERT_EQ(sizeof(kDexData),
+            static_cast<size_t>(TEMP_FAILURE_RETRY(write(tf.fd, kDexData, sizeof(kDexData)))));
+
+  std::string error_msg;
+  EXPECT_NE(DexFile::OpenFromFd(tf.fd, 0x100, tf.path, &error_msg), nullptr);
+  EXPECT_TRUE(error_msg.empty());
+}
+
+TEST(DexFileTest, get_method_info_for_offset_without_signature) {
+  std::unique_ptr<DexFile> dex_file = GetTestDexData();
+  ASSERT_NE(dex_file, nullptr);
+
+  MethodInfo info = dex_file->GetMethodInfoForOffset(0x102, false);
+  EXPECT_EQ(info.offset, int32_t{0x100});
+  EXPECT_EQ(info.len, int32_t{8});
+  EXPECT_STREQ(info.name.data(), "Main.<init>");
+
+  info = dex_file->GetMethodInfoForOffset(0x118, false);
+  EXPECT_EQ(info.offset, int32_t{0x118});
+  EXPECT_EQ(info.len, int32_t{2});
+  EXPECT_STREQ(info.name.data(), "Main.main");
+
+  // Retrieve a cached result.
+  info = dex_file->GetMethodInfoForOffset(0x104, false);
+  EXPECT_EQ(info.offset, int32_t{0x100});
+  EXPECT_EQ(info.len, int32_t{8});
+  EXPECT_STREQ(info.name.data(), "Main.<init>");
+}
+
+TEST(DexFileTest, get_method_info_for_offset_with_signature) {
+  std::unique_ptr<DexFile> dex_file = GetTestDexData();
+  ASSERT_NE(dex_file, nullptr);
+
+  MethodInfo info = dex_file->GetMethodInfoForOffset(0x102, true);
+  EXPECT_EQ(info.offset, int32_t{0x100});
+  EXPECT_EQ(info.len, int32_t{8});
+  EXPECT_STREQ(info.name.data(), "void Main.<init>()");
+
+  info = dex_file->GetMethodInfoForOffset(0x118, true);
+  EXPECT_EQ(info.offset, int32_t{0x118});
+  EXPECT_EQ(info.len, int32_t{2});
+  EXPECT_STREQ(info.name.data(), "void Main.main(java.lang.String[])");
+
+  // Retrieve a cached result.
+  info = dex_file->GetMethodInfoForOffset(0x104, true);
+  EXPECT_EQ(info.offset, int32_t{0x100});
+  EXPECT_EQ(info.len, int32_t{8});
+  EXPECT_STREQ(info.name.data(), "void Main.<init>()");
+
+  // with_signature doesn't affect the cache.
+  info = dex_file->GetMethodInfoForOffset(0x104, false);
+  EXPECT_EQ(info.offset, int32_t{0x100});
+  EXPECT_EQ(info.len, int32_t{8});
+  EXPECT_STREQ(info.name.data(), "Main.<init>");
+}
+
+TEST(DexFileTest, get_method_info_for_offset_boundaries) {
+  std::unique_ptr<DexFile> dex_file = GetTestDexData();
+  ASSERT_NE(dex_file, nullptr);
+
+  MethodInfo info = dex_file->GetMethodInfoForOffset(0x100000, false);
+  EXPECT_EQ(info.offset, int32_t{0});
+
+  info = dex_file->GetMethodInfoForOffset(0x99, false);
+  EXPECT_EQ(info.offset, int32_t{0});
+  info = dex_file->GetMethodInfoForOffset(0x100, false);
+  EXPECT_EQ(info.offset, int32_t{0x100});
+  info = dex_file->GetMethodInfoForOffset(0x107, false);
+  EXPECT_EQ(info.offset, int32_t{0x100});
+  info = dex_file->GetMethodInfoForOffset(0x108, false);
+  EXPECT_EQ(info.offset, int32_t{0});
+
+  // Make sure that once the whole dex file has been cached, no problems occur.
+  info = dex_file->GetMethodInfoForOffset(0x98, false);
+  EXPECT_EQ(info.offset, int32_t{0});
+
+  // Choose a value that is in the cached map, but not in a valid method.
+  info = dex_file->GetMethodInfoForOffset(0x110, false);
+  EXPECT_EQ(info.offset, int32_t{0});
+}
+
+TEST(DexFileTest, get_all_method_infos_without_signature) {
+  std::unique_ptr<DexFile> dex_file = GetTestDexData();
+  ASSERT_NE(dex_file, nullptr);
+
+  std::vector<MethodInfo> infos;
+  infos.emplace_back(MethodInfo{0x100, 8, DexString("Main.<init>")});
+  infos.emplace_back(MethodInfo{0x118, 2, DexString("Main.main")});
+  ASSERT_EQ(dex_file->GetAllMethodInfos(false), infos);
+}
+
+TEST(DexFileTest, get_all_method_infos_with_signature) {
+  std::unique_ptr<DexFile> dex_file = GetTestDexData();
+  ASSERT_NE(dex_file, nullptr);
+
+  std::vector<MethodInfo> infos;
+  infos.emplace_back(MethodInfo{0x100, 8, DexString("void Main.<init>()")});
+  infos.emplace_back(MethodInfo{0x118, 2, DexString("void Main.main(java.lang.String[])")});
+  ASSERT_EQ(dex_file->GetAllMethodInfos(true), infos);
+}
+
+TEST(DexFileTest, move_construct) {
+  std::unique_ptr<DexFile> dex_file = GetTestDexData();
+  ASSERT_NE(dex_file, nullptr);
+
+  auto df1 = DexFile(std::move(*dex_file));
+  auto df2 = DexFile(std::move(df1));
+
+  MethodInfo info = df2.GetMethodInfoForOffset(0x100, false);
+  EXPECT_EQ(info.offset, int32_t{0x100});
+}
+
+}  // namespace dex
+}  // namespace art_api
diff --git a/libdexfile/external/include/art_api/dex_file_external.h b/libdexfile/external/include/art_api/dex_file_external.h
new file mode 100644
index 0000000..b29e759
--- /dev/null
+++ b/libdexfile/external/include/art_api/dex_file_external.h
@@ -0,0 +1,89 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef ART_LIBDEXFILE_EXTERNAL_INCLUDE_ART_API_DEX_FILE_EXTERNAL_H_
+#define ART_LIBDEXFILE_EXTERNAL_INCLUDE_ART_API_DEX_FILE_EXTERNAL_H_
+
+// Dex file external API
+
+#include <sys/types.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+// This is the stable C ABI that backs art_api::dex below. Structs and functions
+// may only be added here. C++ users should use dex_file_support.h instead.
+
+// Opaque wrapper for an std::string allocated in libdexfile which must be freed
+// using ExtDexFileFreeString.
+struct ExtDexFileString;
+
+// Returns an ExtDexFileString initialized to the given string.
+const struct ExtDexFileString* ExtDexFileMakeString(const char* str, size_t size);
+
+// Returns a pointer to the underlying null-terminated character array and its
+// size for the given ExtDexFileString.
+const char* ExtDexFileGetString(const struct ExtDexFileString* ext_string, /*out*/ size_t* size);
+
+// Frees an ExtDexFileString.
+void ExtDexFileFreeString(const struct ExtDexFileString* ext_string);
+
+struct ExtDexFileMethodInfo {
+  int32_t offset;
+  int32_t len;
+  const struct ExtDexFileString* name;
+};
+
+struct ExtDexFile;
+
+// See art_api::dex::DexFile::OpenFromMemory. Returns true on success.
+int ExtDexFileOpenFromMemory(const void* addr,
+                             /*inout*/ size_t* size,
+                             const char* location,
+                             /*out*/ const struct ExtDexFileString** error_msg,
+                             /*out*/ struct ExtDexFile** ext_dex_file);
+
+// See art_api::dex::DexFile::OpenFromFd. Returns true on success.
+int ExtDexFileOpenFromFd(int fd,
+                         off_t offset,
+                         const char* location,
+                         /*out*/ const struct ExtDexFileString** error_msg,
+                         /*out*/ struct ExtDexFile** ext_dex_file);
+
+// See art_api::dex::DexFile::GetMethodInfoForOffset. Returns true on success.
+int ExtDexFileGetMethodInfoForOffset(struct ExtDexFile* ext_dex_file,
+                                     int64_t dex_offset,
+                                     int with_signature,
+                                     /*out*/ struct ExtDexFileMethodInfo* method_info);
+
+typedef void ExtDexFileMethodInfoCallback(const struct ExtDexFileMethodInfo* ext_method_info,
+                                          void* user_data);
+
+// See art_api::dex::DexFile::GetAllMethodInfos.
+void ExtDexFileGetAllMethodInfos(struct ExtDexFile* ext_dex_file,
+                                 int with_signature,
+                                 ExtDexFileMethodInfoCallback* method_info_cb,
+                                 void* user_data);
+
+// Frees an ExtDexFile.
+void ExtDexFileFree(struct ExtDexFile* ext_dex_file);
+
+#ifdef __cplusplus
+}  // extern "C"
+#endif
+
+#endif  // ART_LIBDEXFILE_EXTERNAL_INCLUDE_ART_API_DEX_FILE_EXTERNAL_H_
diff --git a/libdexfile/external/include/art_api/ext_dex_file.h b/libdexfile/external/include/art_api/dex_file_support.h
similarity index 62%
rename from libdexfile/external/include/art_api/ext_dex_file.h
rename to libdexfile/external/include/art_api/dex_file_support.h
index 4a52a2b..24222af 100644
--- a/libdexfile/external/include/art_api/ext_dex_file.h
+++ b/libdexfile/external/include/art_api/dex_file_support.h
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2018 The Android Open Source Project
+ * Copyright (C) 2019 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.
@@ -14,83 +14,21 @@
  * limitations under the License.
  */
 
-#ifndef ART_LIBDEXFILE_EXTERNAL_INCLUDE_ART_API_EXT_DEX_FILE_H_
-#define ART_LIBDEXFILE_EXTERNAL_INCLUDE_ART_API_EXT_DEX_FILE_H_
+#ifndef ART_LIBDEXFILE_EXTERNAL_INCLUDE_ART_API_DEX_FILE_SUPPORT_H_
+#define ART_LIBDEXFILE_EXTERNAL_INCLUDE_ART_API_DEX_FILE_SUPPORT_H_
 
-// Dex file external API
-
-#include <sys/types.h>
+// C++ wrapper for the dex file external API.
 
 #include <cstring>
 #include <memory>
 #include <string>
 #include <string_view>
+#include <utility>
 #include <vector>
 
 #include <android-base/macros.h>
 
-extern "C" {
-
-// This is the stable C ABI that backs art_api::dex below. Structs and functions
-// may only be added here.
-// TODO(b/120978655): Move this to a separate pure C header.
-//
-// Clients should use the C++ wrappers in art_api::dex instead.
-
-// Opaque wrapper for an std::string allocated in libdexfile which must be freed
-// using ExtDexFileFreeString.
-class ExtDexFileString;
-
-// Returns an ExtDexFileString initialized to the given string.
-const ExtDexFileString* ExtDexFileMakeString(const char* str);
-
-// Returns a pointer to the underlying null-terminated character array and its
-// size for the given ExtDexFileString.
-const char* ExtDexFileGetString(const ExtDexFileString* ext_string, /*out*/ size_t* size);
-
-// Frees an ExtDexFileString.
-void ExtDexFileFreeString(const ExtDexFileString* ext_string);
-
-struct ExtDexFileMethodInfo {
-  int32_t offset;
-  int32_t len;
-  const ExtDexFileString* name;
-};
-
-class ExtDexFile;
-
-// See art_api::dex::DexFile::OpenFromMemory. Returns true on success.
-int ExtDexFileOpenFromMemory(const void* addr,
-                             /*inout*/ size_t* size,
-                             const char* location,
-                             /*out*/ const ExtDexFileString** error_msg,
-                             /*out*/ ExtDexFile** ext_dex_file);
-
-// See art_api::dex::DexFile::OpenFromFd. Returns true on success.
-int ExtDexFileOpenFromFd(int fd,
-                         off_t offset,
-                         const char* location,
-                         /*out*/ const ExtDexFileString** error_msg,
-                         /*out*/ ExtDexFile** ext_dex_file);
-
-// See art_api::dex::DexFile::GetMethodInfoForOffset. Returns true on success.
-int ExtDexFileGetMethodInfoForOffset(ExtDexFile* ext_dex_file,
-                                     int64_t dex_offset,
-                                     /*out*/ ExtDexFileMethodInfo* method_info);
-
-typedef void ExtDexFileMethodInfoCallback(const ExtDexFileMethodInfo* ext_method_info,
-                                          void* user_data);
-
-// See art_api::dex::DexFile::GetAllMethodInfos.
-void ExtDexFileGetAllMethodInfos(ExtDexFile* ext_dex_file,
-                                 int with_signature,
-                                 ExtDexFileMethodInfoCallback* method_info_cb,
-                                 void* user_data);
-
-// Frees an ExtDexFile.
-void ExtDexFileFree(ExtDexFile* ext_dex_file);
-
-}  // extern "C"
+#include "art_api/dex_file_external.h"
 
 namespace art_api {
 namespace dex {
@@ -98,12 +36,17 @@
 // Minimal std::string look-alike for a string returned from libdexfile.
 class DexString final {
  public:
-  DexString(DexString&& dex_str) noexcept { ReplaceExtString(std::move(dex_str)); }
-  explicit DexString(const char* str = "") : ext_string_(ExtDexFileMakeString(str)) {}
+  DexString(DexString&& dex_str) noexcept : ext_string_(dex_str.ext_string_) {
+    dex_str.ext_string_ = ExtDexFileMakeString("", 0);
+  }
+  explicit DexString(const char* str = "")
+      : ext_string_(ExtDexFileMakeString(str, std::strlen(str))) {}
+  explicit DexString(std::string_view str)
+      : ext_string_(ExtDexFileMakeString(str.data(), str.size())) {}
   ~DexString() { ExtDexFileFreeString(ext_string_); }
 
   DexString& operator=(DexString&& dex_str) noexcept {
-    ReplaceExtString(std::move(dex_str));
+    std::swap(ext_string_, dex_str.ext_string_);
     return *this;
   }
 
@@ -132,11 +75,6 @@
   explicit DexString(const ExtDexFileString* ext_string) : ext_string_(ext_string) {}
   const ExtDexFileString* ext_string_;  // Owned instance. Never nullptr.
 
-  void ReplaceExtString(DexString&& dex_str) {
-    ext_string_ = dex_str.ext_string_;
-    dex_str.ext_string_ = ExtDexFileMakeString("");
-  }
-
   DISALLOW_COPY_AND_ASSIGN(DexString);
 };
 
@@ -211,10 +149,15 @@
 
   // Given an offset relative to the start of the dex file header, if there is a
   // method whose instruction range includes that offset then returns info about
-  // it, otherwise returns a struct with offset == 0.
-  MethodInfo GetMethodInfoForOffset(int64_t dex_offset) {
+  // it, otherwise returns a struct with offset == 0. MethodInfo.name receives
+  // the full function signature if with_signature is set, otherwise it gets the
+  // class and method name only.
+  MethodInfo GetMethodInfoForOffset(int64_t dex_offset, bool with_signature) {
     ExtDexFileMethodInfo ext_method_info;
-    if (ExtDexFileGetMethodInfoForOffset(ext_dex_file_, dex_offset, &ext_method_info)) {
+    if (ExtDexFileGetMethodInfoForOffset(ext_dex_file_,
+                                         dex_offset,
+                                         with_signature,
+                                         &ext_method_info)) {
       return AbsorbMethodInfo(ext_method_info);
     }
     return {/*offset=*/0, /*len=*/0, /*name=*/DexString()};
@@ -223,10 +166,12 @@
   // Returns info structs about all methods in the dex file. MethodInfo.name
   // receives the full function signature if with_signature is set, otherwise it
   // gets the class and method name only.
-  std::vector<MethodInfo> GetAllMethodInfos(bool with_signature = true) {
+  std::vector<MethodInfo> GetAllMethodInfos(bool with_signature) {
     MethodInfoVector res;
-    ExtDexFileGetAllMethodInfos(
-        ext_dex_file_, with_signature, AddMethodInfoCallback, static_cast<void*>(&res));
+    ExtDexFileGetAllMethodInfos(ext_dex_file_,
+                                with_signature,
+                                AddMethodInfoCallback,
+                                static_cast<void*>(&res));
     return res;
   }
 
@@ -245,4 +190,4 @@
 }  // namespace dex
 }  // namespace art_api
 
-#endif  // ART_LIBDEXFILE_EXTERNAL_INCLUDE_ART_API_EXT_DEX_FILE_H_
+#endif  // ART_LIBDEXFILE_EXTERNAL_INCLUDE_ART_API_DEX_FILE_SUPPORT_H_
diff --git a/oatdump/oatdump.cc b/oatdump/oatdump.cc
index 4e1276e..89826c6 100644
--- a/oatdump/oatdump.cc
+++ b/oatdump/oatdump.cc
@@ -114,7 +114,7 @@
   "kOomeWhenThrowingOome",
   "kOomeWhenHandlingStackOverflow",
   "kNoClassDefFoundError",
-  "kClassLoader",
+  "kSpecialRoots",
 };
 
 // Map is so that we don't allocate multiple dex files for the same OatDexFile.
diff --git a/openjdkjvmti/OpenjdkJvmTi.cc b/openjdkjvmti/OpenjdkJvmTi.cc
index bd5b598..7a2b638 100644
--- a/openjdkjvmti/OpenjdkJvmTi.cc
+++ b/openjdkjvmti/OpenjdkJvmTi.cc
@@ -1552,7 +1552,7 @@
 
   {
     // Make sure we can deopt anything we need to.
-    art::ScopedObjectAccess soa(art::Thread::Current());
+    art::ScopedSuspendAll ssa(__FUNCTION__);
     gDeoptManager->FinishSetup();
   }
 
diff --git a/openjdkjvmti/deopt_manager.h b/openjdkjvmti/deopt_manager.h
index d9f34a5..065baa7 100644
--- a/openjdkjvmti/deopt_manager.h
+++ b/openjdkjvmti/deopt_manager.h
@@ -107,7 +107,7 @@
 
   void FinishSetup()
       REQUIRES(!deoptimization_status_lock_, !art::Roles::uninterruptible_)
-      REQUIRES_SHARED(art::Locks::mutator_lock_);
+      REQUIRES(art::Locks::mutator_lock_);
 
   static DeoptManager* Get();
 
diff --git a/openjdkjvmti/events.cc b/openjdkjvmti/events.cc
index 7fb6a15..22c622a 100644
--- a/openjdkjvmti/events.cc
+++ b/openjdkjvmti/events.cc
@@ -34,6 +34,7 @@
 #include <array>
 #include <sys/time.h>
 
+#include "arch/context.h"
 #include "art_field-inl.h"
 #include "art_jvmti.h"
 #include "art_method-inl.h"
diff --git a/openjdkjvmti/ti_method.cc b/openjdkjvmti/ti_method.cc
index 7d69c89..e88539f 100644
--- a/openjdkjvmti/ti_method.cc
+++ b/openjdkjvmti/ti_method.cc
@@ -33,6 +33,7 @@
 
 #include <type_traits>
 
+#include "arch/context.h"
 #include "art_jvmti.h"
 #include "art_method-inl.h"
 #include "base/enums.h"
diff --git a/openjdkjvmti/ti_redefine.cc b/openjdkjvmti/ti_redefine.cc
index 4bcb7b2..3d175a8 100644
--- a/openjdkjvmti/ti_redefine.cc
+++ b/openjdkjvmti/ti_redefine.cc
@@ -188,7 +188,9 @@
     if (obsoleted_methods_.find(old_method) != obsoleted_methods_.end()) {
       // We cannot ensure that the right dex file is used in inlined frames so we don't support
       // redefining them.
-      DCHECK(!IsInInlinedFrame()) << "Inlined frames are not supported when using redefinition";
+      DCHECK(!IsInInlinedFrame()) << "Inlined frames are not supported when using redefinition: "
+                                  << old_method->PrettyMethod() << " is inlined into "
+                                  << GetOuterMethod()->PrettyMethod();
       art::ArtMethod* new_obsolete_method = obsolete_maps_->FindObsoleteVersion(old_method);
       if (new_obsolete_method == nullptr) {
         // Create a new Obsolete Method and put it in the list.
diff --git a/openjdkjvmti/ti_stack.cc b/openjdkjvmti/ti_stack.cc
index 4a3eac8..385ac45 100644
--- a/openjdkjvmti/ti_stack.cc
+++ b/openjdkjvmti/ti_stack.cc
@@ -36,6 +36,7 @@
 #include <unordered_map>
 #include <vector>
 
+#include "arch/context.h"
 #include "art_field-inl.h"
 #include "art_method-inl.h"
 #include "art_jvmti.h"
diff --git a/runtime/Android.bp b/runtime/Android.bp
index 71c5b74..b89eb02 100644
--- a/runtime/Android.bp
+++ b/runtime/Android.bp
@@ -462,6 +462,7 @@
     cmd: "$(location generate_operator_out) art/runtime $(in) > $(out)",
     tools: ["generate_operator_out"],
     srcs: [
+        "base/callee_save_type.h",
         "base/locks.h",
         "class_loader_context.h",
         "class_status.h",
diff --git a/runtime/arch/arm/callee_save_frame_arm.h b/runtime/arch/arm/callee_save_frame_arm.h
index 11eefb9..72ba3b7 100644
--- a/runtime/arch/arm/callee_save_frame_arm.h
+++ b/runtime/arch/arm/callee_save_frame_arm.h
@@ -21,9 +21,9 @@
 #include "base/bit_utils.h"
 #include "base/callee_save_type.h"
 #include "base/enums.h"
-#include "base/globals.h"
 #include "quick/quick_method_frame_info.h"
 #include "registers_arm.h"
+#include "runtime_globals.h"
 
 namespace art {
 namespace arm {
diff --git a/runtime/arch/arm/fault_handler_arm.cc b/runtime/arch/arm/fault_handler_arm.cc
index bb33a27..e186cd3 100644
--- a/runtime/arch/arm/fault_handler_arm.cc
+++ b/runtime/arch/arm/fault_handler_arm.cc
@@ -18,12 +18,13 @@
 
 #include <sys/ucontext.h>
 
+#include "arch/instruction_set.h"
 #include "art_method.h"
 #include "base/enums.h"
-#include "base/globals.h"
 #include "base/hex_dump.h"
 #include "base/logging.h"  // For VLOG.
 #include "base/macros.h"
+#include "runtime_globals.h"
 #include "thread-current-inl.h"
 
 //
diff --git a/runtime/arch/arm64/callee_save_frame_arm64.h b/runtime/arch/arm64/callee_save_frame_arm64.h
index a5aea2a..d3609f1 100644
--- a/runtime/arch/arm64/callee_save_frame_arm64.h
+++ b/runtime/arch/arm64/callee_save_frame_arm64.h
@@ -21,9 +21,9 @@
 #include "base/bit_utils.h"
 #include "base/callee_save_type.h"
 #include "base/enums.h"
-#include "base/globals.h"
 #include "quick/quick_method_frame_info.h"
 #include "registers_arm64.h"
+#include "runtime_globals.h"
 
 namespace art {
 namespace arm64 {
diff --git a/runtime/arch/arm64/fault_handler_arm64.cc b/runtime/arch/arm64/fault_handler_arm64.cc
index e8b4627..751c05b 100644
--- a/runtime/arch/arm64/fault_handler_arm64.cc
+++ b/runtime/arch/arm64/fault_handler_arm64.cc
@@ -18,13 +18,14 @@
 
 #include <sys/ucontext.h>
 
+#include "arch/instruction_set.h"
 #include "art_method.h"
 #include "base/enums.h"
-#include "base/globals.h"
 #include "base/hex_dump.h"
 #include "base/logging.h"  // For VLOG.
 #include "base/macros.h"
 #include "registers_arm64.h"
+#include "runtime_globals.h"
 #include "thread-current-inl.h"
 
 extern "C" void art_quick_throw_stack_overflow();
diff --git a/runtime/arch/instruction_set_features.cc b/runtime/arch/instruction_set_features.cc
index 0c45bc9..886b40a 100644
--- a/runtime/arch/instruction_set_features.cc
+++ b/runtime/arch/instruction_set_features.cc
@@ -16,6 +16,9 @@
 
 #include "instruction_set_features.h"
 
+#include <algorithm>
+#include <ostream>
+
 #include "android-base/strings.h"
 
 #include "base/casts.h"
diff --git a/runtime/arch/instruction_set_features.h b/runtime/arch/instruction_set_features.h
index c31c927..f910a41 100644
--- a/runtime/arch/instruction_set_features.h
+++ b/runtime/arch/instruction_set_features.h
@@ -17,8 +17,8 @@
 #ifndef ART_RUNTIME_ARCH_INSTRUCTION_SET_FEATURES_H_
 #define ART_RUNTIME_ARCH_INSTRUCTION_SET_FEATURES_H_
 
+#include <iosfwd>
 #include <memory>
-#include <ostream>
 #include <vector>
 
 #include "arch/instruction_set.h"
diff --git a/runtime/arch/mips/callee_save_frame_mips.h b/runtime/arch/mips/callee_save_frame_mips.h
index 6e88d08..84ce209 100644
--- a/runtime/arch/mips/callee_save_frame_mips.h
+++ b/runtime/arch/mips/callee_save_frame_mips.h
@@ -21,9 +21,9 @@
 #include "base/bit_utils.h"
 #include "base/callee_save_type.h"
 #include "base/enums.h"
-#include "base/globals.h"
 #include "quick/quick_method_frame_info.h"
 #include "registers_mips.h"
+#include "runtime_globals.h"
 
 namespace art {
 namespace mips {
diff --git a/runtime/arch/mips/fault_handler_mips.cc b/runtime/arch/mips/fault_handler_mips.cc
index 7c8ac28..0354f0c 100644
--- a/runtime/arch/mips/fault_handler_mips.cc
+++ b/runtime/arch/mips/fault_handler_mips.cc
@@ -17,14 +17,15 @@
 #include <sys/ucontext.h>
 #include "fault_handler.h"
 
+#include "arch/instruction_set.h"
 #include "arch/mips/callee_save_frame_mips.h"
 #include "art_method.h"
 #include "base/callee_save_type.h"
-#include "base/globals.h"
 #include "base/hex_dump.h"
 #include "base/logging.h"  // For VLOG.
 #include "base/macros.h"
 #include "registers_mips.h"
+#include "runtime_globals.h"
 #include "thread-current-inl.h"
 
 extern "C" void art_quick_throw_stack_overflow();
diff --git a/runtime/arch/mips/registers_mips.h b/runtime/arch/mips/registers_mips.h
index 34f2f96..4900e41 100644
--- a/runtime/arch/mips/registers_mips.h
+++ b/runtime/arch/mips/registers_mips.h
@@ -19,9 +19,6 @@
 
 #include <iosfwd>
 
-#include <android-base/logging.h>
-
-#include "base/globals.h"
 #include "base/macros.h"
 
 namespace art {
diff --git a/runtime/arch/mips64/callee_save_frame_mips64.h b/runtime/arch/mips64/callee_save_frame_mips64.h
index 59529a0..64d6bec 100644
--- a/runtime/arch/mips64/callee_save_frame_mips64.h
+++ b/runtime/arch/mips64/callee_save_frame_mips64.h
@@ -21,9 +21,9 @@
 #include "base/bit_utils.h"
 #include "base/callee_save_type.h"
 #include "base/enums.h"
-#include "base/globals.h"
 #include "quick/quick_method_frame_info.h"
 #include "registers_mips64.h"
+#include "runtime_globals.h"
 
 namespace art {
 namespace mips64 {
diff --git a/runtime/arch/mips64/fault_handler_mips64.cc b/runtime/arch/mips64/fault_handler_mips64.cc
index 85f3528..6255235 100644
--- a/runtime/arch/mips64/fault_handler_mips64.cc
+++ b/runtime/arch/mips64/fault_handler_mips64.cc
@@ -18,14 +18,15 @@
 
 #include <sys/ucontext.h>
 
+#include "arch/instruction_set.h"
 #include "arch/mips64/callee_save_frame_mips64.h"
 #include "art_method.h"
 #include "base/callee_save_type.h"
-#include "base/globals.h"
 #include "base/hex_dump.h"
 #include "base/logging.h"  // For VLOG.
 #include "base/macros.h"
 #include "registers_mips64.h"
+#include "runtime_globals.h"
 #include "thread-current-inl.h"
 
 extern "C" void art_quick_throw_stack_overflow();
diff --git a/runtime/arch/mips64/registers_mips64.h b/runtime/arch/mips64/registers_mips64.h
index a3fa2ac4..1c22c07 100644
--- a/runtime/arch/mips64/registers_mips64.h
+++ b/runtime/arch/mips64/registers_mips64.h
@@ -19,9 +19,6 @@
 
 #include <iosfwd>
 
-#include <android-base/logging.h>
-
-#include "base/globals.h"
 #include "base/macros.h"
 
 namespace art {
diff --git a/runtime/arch/x86/callee_save_frame_x86.h b/runtime/arch/x86/callee_save_frame_x86.h
index f336f43..2edcade 100644
--- a/runtime/arch/x86/callee_save_frame_x86.h
+++ b/runtime/arch/x86/callee_save_frame_x86.h
@@ -21,9 +21,9 @@
 #include "base/bit_utils.h"
 #include "base/callee_save_type.h"
 #include "base/enums.h"
-#include "base/globals.h"
 #include "quick/quick_method_frame_info.h"
 #include "registers_x86.h"
+#include "runtime_globals.h"
 
 namespace art {
 namespace x86 {
diff --git a/runtime/arch/x86/fault_handler_x86.cc b/runtime/arch/x86/fault_handler_x86.cc
index 8b24334..26312fb 100644
--- a/runtime/arch/x86/fault_handler_x86.cc
+++ b/runtime/arch/x86/fault_handler_x86.cc
@@ -18,13 +18,14 @@
 
 #include <sys/ucontext.h>
 
+#include "arch/instruction_set.h"
 #include "art_method.h"
 #include "base/enums.h"
-#include "base/globals.h"
 #include "base/hex_dump.h"
 #include "base/logging.h"  // For VLOG.
 #include "base/macros.h"
 #include "base/safe_copy.h"
+#include "runtime_globals.h"
 #include "thread-current-inl.h"
 
 #if defined(__APPLE__)
diff --git a/runtime/arch/x86/registers_x86.h b/runtime/arch/x86/registers_x86.h
index d3b959f..ff6c18f 100644
--- a/runtime/arch/x86/registers_x86.h
+++ b/runtime/arch/x86/registers_x86.h
@@ -19,9 +19,6 @@
 
 #include <iosfwd>
 
-#include <android-base/logging.h>
-
-#include "base/globals.h"
 #include "base/macros.h"
 
 namespace art {
diff --git a/runtime/arch/x86_64/callee_save_frame_x86_64.h b/runtime/arch/x86_64/callee_save_frame_x86_64.h
index 228a902..d4f2da7 100644
--- a/runtime/arch/x86_64/callee_save_frame_x86_64.h
+++ b/runtime/arch/x86_64/callee_save_frame_x86_64.h
@@ -21,9 +21,9 @@
 #include "base/bit_utils.h"
 #include "base/callee_save_type.h"
 #include "base/enums.h"
-#include "base/globals.h"
 #include "quick/quick_method_frame_info.h"
 #include "registers_x86_64.h"
+#include "runtime_globals.h"
 
 namespace art {
 namespace x86_64 {
diff --git a/runtime/arch/x86_64/registers_x86_64.h b/runtime/arch/x86_64/registers_x86_64.h
index 66aea70..248c82b 100644
--- a/runtime/arch/x86_64/registers_x86_64.h
+++ b/runtime/arch/x86_64/registers_x86_64.h
@@ -19,9 +19,6 @@
 
 #include <iosfwd>
 
-#include <android-base/logging.h>
-
-#include "base/globals.h"
 #include "base/macros.h"
 
 namespace art {
diff --git a/runtime/art_method.h b/runtime/art_method.h
index aed9f62..aabd093 100644
--- a/runtime/art_method.h
+++ b/runtime/art_method.h
@@ -476,7 +476,7 @@
   }
 
   ProfilingInfo* GetProfilingInfo(PointerSize pointer_size) REQUIRES_SHARED(Locks::mutator_lock_) {
-    if (UNLIKELY(IsNative()) || UNLIKELY(IsProxyMethod())) {
+    if (UNLIKELY(IsNative() || IsProxyMethod() || !IsInvokable())) {
       return nullptr;
     }
     return reinterpret_cast<ProfilingInfo*>(GetDataPtrSize(pointer_size));
diff --git a/libartbase/base/callee_save_type.h b/runtime/base/callee_save_type.h
similarity index 89%
rename from libartbase/base/callee_save_type.h
rename to runtime/base/callee_save_type.h
index 3e44a3a..e7cc7e6 100644
--- a/libartbase/base/callee_save_type.h
+++ b/runtime/base/callee_save_type.h
@@ -14,11 +14,11 @@
  * limitations under the License.
  */
 
-#ifndef ART_LIBARTBASE_BASE_CALLEE_SAVE_TYPE_H_
-#define ART_LIBARTBASE_BASE_CALLEE_SAVE_TYPE_H_
+#ifndef ART_RUNTIME_BASE_CALLEE_SAVE_TYPE_H_
+#define ART_RUNTIME_BASE_CALLEE_SAVE_TYPE_H_
 
-#include <cstddef>
-#include <ostream>
+#include <cstdint>
+#include <iosfwd>
 
 namespace art {
 
@@ -44,4 +44,4 @@
 
 }  // namespace art
 
-#endif  // ART_LIBARTBASE_BASE_CALLEE_SAVE_TYPE_H_
+#endif  // ART_RUNTIME_BASE_CALLEE_SAVE_TYPE_H_
diff --git a/runtime/base/mutex.h b/runtime/base/mutex.h
index 41a47af..aaa1ee6 100644
--- a/runtime/base/mutex.h
+++ b/runtime/base/mutex.h
@@ -28,7 +28,7 @@
 
 #include "base/aborting.h"
 #include "base/atomic.h"
-#include "base/globals.h"
+#include "runtime_globals.h"
 #include "base/macros.h"
 #include "locks.h"
 
diff --git a/runtime/class_linker.cc b/runtime/class_linker.cc
index 5d1f20c..d29a6b7 100644
--- a/runtime/class_linker.cc
+++ b/runtime/class_linker.cc
@@ -229,7 +229,9 @@
   }
 }
 
-void ClassLinker::ThrowEarlierClassFailure(ObjPtr<mirror::Class> c, bool wrap_in_no_class_def) {
+void ClassLinker::ThrowEarlierClassFailure(ObjPtr<mirror::Class> c,
+                                           bool wrap_in_no_class_def,
+                                           bool log) {
   // The class failed to initialize on a previous attempt, so we want to throw
   // a NoClassDefFoundError (v2 2.17.5).  The exception to this rule is if we
   // failed in verification, in which case v2 5.4.1 says we need to re-throw
@@ -245,8 +247,10 @@
         extra = verify_error->AsThrowable()->Dump();
       }
     }
-    LOG(INFO) << "Rejecting re-init on previously-failed class " << c->PrettyClass()
-              << ": " << extra;
+    if (log) {
+      LOG(INFO) << "Rejecting re-init on previously-failed class " << c->PrettyClass()
+                << ": " << extra;
+    }
   }
 
   CHECK(c->IsErroneous()) << c->PrettyClass() << " " << c->GetStatus();
@@ -5044,7 +5048,7 @@
 
     // Was the class already found to be erroneous? Done under the lock to match the JLS.
     if (klass->IsErroneous()) {
-      ThrowEarlierClassFailure(klass.Get(), true);
+      ThrowEarlierClassFailure(klass.Get(), true, /* log= */ true);
       VlogClassInitializationFailure(klass);
       return false;
     }
diff --git a/runtime/class_linker.h b/runtime/class_linker.h
index b9ac9ca..4f4cb4b 100644
--- a/runtime/class_linker.h
+++ b/runtime/class_linker.h
@@ -17,6 +17,7 @@
 #ifndef ART_RUNTIME_CLASS_LINKER_H_
 #define ART_RUNTIME_CLASS_LINKER_H_
 
+#include <list>
 #include <set>
 #include <string>
 #include <unordered_map>
@@ -89,6 +90,7 @@
 class Runtime;
 class ScopedObjectAccessAlreadyRunnable;
 template<size_t kNumReferences> class PACKED(4) StackHandleScope;
+class Thread;
 
 enum VisitRootFlags : uint8_t;
 
@@ -685,7 +687,9 @@
 
   // Throw the class initialization failure recorded when first trying to initialize the given
   // class.
-  void ThrowEarlierClassFailure(ObjPtr<mirror::Class> c, bool wrap_in_no_class_def = false)
+  void ThrowEarlierClassFailure(ObjPtr<mirror::Class> c,
+                                bool wrap_in_no_class_def = false,
+                                bool log = false)
       REQUIRES_SHARED(Locks::mutator_lock_)
       REQUIRES(!Locks::dex_lock_);
 
diff --git a/runtime/common_runtime_test.h b/runtime/common_runtime_test.h
index 29b7813..d7f6127 100644
--- a/runtime/common_runtime_test.h
+++ b/runtime/common_runtime_test.h
@@ -26,7 +26,6 @@
 
 #include "arch/instruction_set.h"
 #include "base/common_art_test.h"
-#include "base/globals.h"
 #include "base/locks.h"
 #include "base/os.h"
 #include "base/unix_file/fd_file.h"
@@ -34,6 +33,7 @@
 #include "dex/compact_dex_level.h"
 // TODO: Add inl file and avoid including inl.
 #include "obj_ptr-inl.h"
+#include "runtime_globals.h"
 #include "scoped_thread_state_change-inl.h"
 
 namespace art {
diff --git a/runtime/compiler_filter.cc b/runtime/compiler_filter.cc
index bda64eb..c086490 100644
--- a/runtime/compiler_filter.cc
+++ b/runtime/compiler_filter.cc
@@ -16,6 +16,8 @@
 
 #include "compiler_filter.h"
 
+#include <ostream>
+
 #include "base/utils.h"
 
 namespace art {
diff --git a/runtime/compiler_filter.h b/runtime/compiler_filter.h
index 012ebcb..c36e40f 100644
--- a/runtime/compiler_filter.h
+++ b/runtime/compiler_filter.h
@@ -17,7 +17,7 @@
 #ifndef ART_RUNTIME_COMPILER_FILTER_H_
 #define ART_RUNTIME_COMPILER_FILTER_H_
 
-#include <ostream>
+#include <iosfwd>
 #include <string>
 #include <vector>
 
diff --git a/runtime/debugger.cc b/runtime/debugger.cc
index adf01c3..663af81 100644
--- a/runtime/debugger.cc
+++ b/runtime/debugger.cc
@@ -681,13 +681,13 @@
   //
   // The performance cost of this is non-negligible during native-debugging due to the
   // forced JIT, so we keep the AOT code in that case in exchange for limited native debugging.
+  ScopedSuspendAll ssa(__FUNCTION__);
   if (!runtime->IsJavaDebuggable() &&
       !runtime->GetInstrumentation()->IsForcedInterpretOnly() &&
       !runtime->IsNativeDebuggable()) {
     runtime->DeoptimizeBootImage();
   }
 
-  ScopedSuspendAll ssa(__FUNCTION__);
   if (RequiresDeoptimization()) {
     runtime->GetInstrumentation()->EnableDeoptimization();
   }
diff --git a/runtime/dexopt_test.cc b/runtime/dexopt_test.cc
index 7f697d1..9c0ac8f 100644
--- a/runtime/dexopt_test.cc
+++ b/runtime/dexopt_test.cc
@@ -72,7 +72,8 @@
                                     const std::string& oat_location,
                                     CompilerFilter::Filter filter,
                                     bool with_alternate_image,
-                                    const char* compilation_reason) {
+                                    const char* compilation_reason,
+                                    const std::vector<std::string>& extra_args) {
   std::string dalvik_cache = GetDalvikCache(GetInstructionSetString(kRuntimeISA));
   std::string dalvik_cache_tmp = dalvik_cache + ".redirected";
 
@@ -101,6 +102,8 @@
     args.push_back("--compilation-reason=" + std::string(compilation_reason));
   }
 
+  args.insert(args.end(), extra_args.begin(), extra_args.end());
+
   std::string error_msg;
   ASSERT_TRUE(Dex2Oat(args, &error_msg)) << error_msg;
 
@@ -136,12 +139,14 @@
 void DexoptTest::GenerateOdexForTest(const std::string& dex_location,
                                      const std::string& odex_location,
                                      CompilerFilter::Filter filter,
-                                     const char* compilation_reason) {
+                                     const char* compilation_reason,
+                                     const std::vector<std::string>& extra_args) {
   GenerateOatForTest(dex_location,
                      odex_location,
                      filter,
                      /*with_alternate_image=*/ false,
-                     compilation_reason);
+                     compilation_reason,
+                     extra_args);
 }
 
 void DexoptTest::GenerateOatForTest(const char* dex_location,
diff --git a/runtime/dexopt_test.h b/runtime/dexopt_test.h
index efbdcba..026fe55 100644
--- a/runtime/dexopt_test.h
+++ b/runtime/dexopt_test.h
@@ -42,13 +42,15 @@
                           const std::string& oat_location,
                           CompilerFilter::Filter filter,
                           bool with_alternate_image,
-                          const char* compilation_reason = nullptr);
+                          const char* compilation_reason = nullptr,
+                          const std::vector<std::string>& extra_args = {});
 
   // Generate an odex file for the purposes of test.
   void GenerateOdexForTest(const std::string& dex_location,
                            const std::string& odex_location,
                            CompilerFilter::Filter filter,
-                           const char* compilation_reason = nullptr);
+                           const char* compilation_reason = nullptr,
+                          const std::vector<std::string>& extra_args = {});
 
   // Generate an oat file for the given dex location in its oat location (under
   // the dalvik cache).
diff --git a/runtime/fault_handler.h b/runtime/fault_handler.h
index d3be51f..f6cf2d7 100644
--- a/runtime/fault_handler.h
+++ b/runtime/fault_handler.h
@@ -23,8 +23,8 @@
 
 #include <vector>
 
-#include "base/globals.h"  // For CanDoImplicitNullCheckOn.
 #include "base/locks.h"  // For annotalysis.
+#include "runtime_globals.h"  // For CanDoImplicitNullCheckOn.
 
 namespace art {
 
diff --git a/runtime/gc/accounting/bitmap.h b/runtime/gc/accounting/bitmap.h
index bdc686e..68f2d04 100644
--- a/runtime/gc/accounting/bitmap.h
+++ b/runtime/gc/accounting/bitmap.h
@@ -23,9 +23,9 @@
 #include <set>
 #include <vector>
 
-#include "base/globals.h"
 #include "base/locks.h"
 #include "base/mem_map.h"
+#include "runtime_globals.h"
 
 namespace art {
 
diff --git a/runtime/gc/accounting/card_table.h b/runtime/gc/accounting/card_table.h
index c99ed4b..30c4386 100644
--- a/runtime/gc/accounting/card_table.h
+++ b/runtime/gc/accounting/card_table.h
@@ -19,9 +19,9 @@
 
 #include <memory>
 
-#include "base/globals.h"
 #include "base/locks.h"
 #include "base/mem_map.h"
+#include "runtime_globals.h"
 
 namespace art {
 
diff --git a/runtime/gc/accounting/mod_union_table.h b/runtime/gc/accounting/mod_union_table.h
index 8c471bc..011e95c 100644
--- a/runtime/gc/accounting/mod_union_table.h
+++ b/runtime/gc/accounting/mod_union_table.h
@@ -18,12 +18,12 @@
 #define ART_RUNTIME_GC_ACCOUNTING_MOD_UNION_TABLE_H_
 
 #include "base/allocator.h"
-#include "base/globals.h"
 #include "base/safe_map.h"
 #include "base/tracking_safe_map.h"
 #include "bitmap.h"
 #include "card_table.h"
 #include "mirror/object_reference.h"
+#include "runtime_globals.h"
 
 #include <set>
 #include <vector>
diff --git a/runtime/gc/accounting/read_barrier_table.h b/runtime/gc/accounting/read_barrier_table.h
index 2e42f8d..44cdb5e 100644
--- a/runtime/gc/accounting/read_barrier_table.h
+++ b/runtime/gc/accounting/read_barrier_table.h
@@ -20,10 +20,10 @@
 #include <sys/mman.h>  // For the PROT_* and MAP_* constants.
 
 #include "base/bit_utils.h"
-#include "base/globals.h"
 #include "base/locks.h"
 #include "base/mem_map.h"
 #include "gc/space/space.h"
+#include "runtime_globals.h"
 
 namespace art {
 namespace gc {
diff --git a/runtime/gc/accounting/remembered_set.h b/runtime/gc/accounting/remembered_set.h
index 469074f..3525667 100644
--- a/runtime/gc/accounting/remembered_set.h
+++ b/runtime/gc/accounting/remembered_set.h
@@ -18,9 +18,9 @@
 #define ART_RUNTIME_GC_ACCOUNTING_REMEMBERED_SET_H_
 
 #include "base/allocator.h"
-#include "base/globals.h"
 #include "base/locks.h"
 #include "base/safe_map.h"
+#include "runtime_globals.h"
 
 #include <set>
 #include <vector>
diff --git a/runtime/gc/accounting/space_bitmap.h b/runtime/gc/accounting/space_bitmap.h
index 8561f06..6ca254a 100644
--- a/runtime/gc/accounting/space_bitmap.h
+++ b/runtime/gc/accounting/space_bitmap.h
@@ -23,9 +23,9 @@
 #include <set>
 #include <vector>
 
-#include "base/globals.h"
 #include "base/locks.h"
 #include "base/mem_map.h"
+#include "runtime_globals.h"
 
 namespace art {
 
diff --git a/runtime/gc/accounting/space_bitmap_test.cc b/runtime/gc/accounting/space_bitmap_test.cc
index 22529b8..9f355e3 100644
--- a/runtime/gc/accounting/space_bitmap_test.cc
+++ b/runtime/gc/accounting/space_bitmap_test.cc
@@ -19,9 +19,9 @@
 #include <stdint.h>
 #include <memory>
 
-#include "base/globals.h"
 #include "base/mutex.h"
 #include "common_runtime_test.h"
+#include "runtime_globals.h"
 #include "space_bitmap-inl.h"
 
 namespace art {
diff --git a/runtime/gc/allocator/dlmalloc.cc b/runtime/gc/allocator/dlmalloc.cc
index 11ad8a8..79d4fbf 100644
--- a/runtime/gc/allocator/dlmalloc.cc
+++ b/runtime/gc/allocator/dlmalloc.cc
@@ -60,8 +60,8 @@
 
 #include <sys/mman.h>
 
-#include "base/globals.h"
 #include "base/utils.h"
+#include "runtime_globals.h"
 
 extern "C" void DlmallocMadviseCallback(void* start, void* end, size_t used_bytes, void* arg) {
   // Is this chunk in use?
diff --git a/runtime/gc/allocator/rosalloc.h b/runtime/gc/allocator/rosalloc.h
index bf26aea..0906295 100644
--- a/runtime/gc/allocator/rosalloc.h
+++ b/runtime/gc/allocator/rosalloc.h
@@ -30,9 +30,9 @@
 
 #include "base/allocator.h"
 #include "base/bit_utils.h"
-#include "base/globals.h"
 #include "base/mem_map.h"
 #include "base/mutex.h"
+#include "runtime_globals.h"
 #include "thread.h"
 
 namespace art {
diff --git a/runtime/gc/gc_cause.cc b/runtime/gc/gc_cause.cc
index ee7ac7d..8b4bac2 100644
--- a/runtime/gc/gc_cause.cc
+++ b/runtime/gc/gc_cause.cc
@@ -18,8 +18,8 @@
 
 #include <android-base/logging.h>
 
-#include "base/globals.h"
 #include "base/macros.h"
+#include "runtime_globals.h"
 
 #include <ostream>
 
diff --git a/runtime/gc/heap.h b/runtime/gc/heap.h
index 9949bf4..341f16a 100644
--- a/runtime/gc/heap.h
+++ b/runtime/gc/heap.h
@@ -25,9 +25,7 @@
 #include <android-base/logging.h>
 
 #include "allocator_type.h"
-#include "arch/instruction_set.h"
 #include "base/atomic.h"
-#include "base/globals.h"
 #include "base/macros.h"
 #include "base/mutex.h"
 #include "base/runtime_debug.h"
@@ -43,11 +41,13 @@
 #include "offsets.h"
 #include "process_state.h"
 #include "read_barrier_config.h"
+#include "runtime_globals.h"
 #include "verify_object.h"
 
 namespace art {
 
 class ConditionVariable;
+enum class InstructionSet;
 class IsMarkedVisitor;
 class Mutex;
 class RootVisitor;
diff --git a/runtime/gc/reference_processor.h b/runtime/gc/reference_processor.h
index 17b546a..c1c9a3c 100644
--- a/runtime/gc/reference_processor.h
+++ b/runtime/gc/reference_processor.h
@@ -17,10 +17,10 @@
 #ifndef ART_RUNTIME_GC_REFERENCE_PROCESSOR_H_
 #define ART_RUNTIME_GC_REFERENCE_PROCESSOR_H_
 
-#include "base/globals.h"
 #include "base/locks.h"
 #include "jni.h"
 #include "reference_queue.h"
+#include "runtime_globals.h"
 
 namespace art {
 
diff --git a/runtime/gc/reference_queue.h b/runtime/gc/reference_queue.h
index 53518cc..90f0be7 100644
--- a/runtime/gc/reference_queue.h
+++ b/runtime/gc/reference_queue.h
@@ -22,12 +22,12 @@
 #include <vector>
 
 #include "base/atomic.h"
-#include "base/globals.h"
 #include "base/locks.h"
 #include "base/timing_logger.h"
 #include "jni.h"
 #include "obj_ptr.h"
 #include "offsets.h"
+#include "runtime_globals.h"
 #include "thread_pool.h"
 
 namespace art {
diff --git a/runtime/gc/space/image_space.cc b/runtime/gc/space/image_space.cc
index 64fd3cd..5ad5f52 100644
--- a/runtime/gc/space/image_space.cc
+++ b/runtime/gc/space/image_space.cc
@@ -25,6 +25,7 @@
 #include "android-base/stringprintf.h"
 #include "android-base/strings.h"
 
+#include "arch/instruction_set.h"
 #include "art_field-inl.h"
 #include "art_method-inl.h"
 #include "base/array_ref.h"
diff --git a/runtime/gc/space/image_space.h b/runtime/gc/space/image_space.h
index 14e364a..42ac3e2 100644
--- a/runtime/gc/space/image_space.h
+++ b/runtime/gc/space/image_space.h
@@ -17,7 +17,6 @@
 #ifndef ART_RUNTIME_GC_SPACE_IMAGE_SPACE_H_
 #define ART_RUNTIME_GC_SPACE_IMAGE_SPACE_H_
 
-#include "arch/instruction_set.h"
 #include "gc/accounting/space_bitmap.h"
 #include "image.h"
 #include "space.h"
@@ -26,6 +25,7 @@
 
 template <typename T> class ArrayRef;
 class DexFile;
+enum class InstructionSet;
 class OatFile;
 
 namespace gc {
diff --git a/runtime/gc/space/image_space_fs.h b/runtime/gc/space/image_space_fs.h
index 14deb6f..262c6e0 100644
--- a/runtime/gc/space/image_space_fs.h
+++ b/runtime/gc/space/image_space_fs.h
@@ -23,13 +23,13 @@
 #include "android-base/stringprintf.h"
 
 #include "base/file_utils.h"
-#include "base/globals.h"
 #include "base/logging.h"  // For VLOG.
 #include "base/macros.h"
 #include "base/os.h"
 #include "base/unix_file/fd_file.h"
 #include "base/utils.h"
 #include "runtime.h"
+#include "runtime_globals.h"
 
 namespace art {
 namespace gc {
diff --git a/runtime/gc/space/malloc_space.cc b/runtime/gc/space/malloc_space.cc
index b5e6b62..474231b 100644
--- a/runtime/gc/space/malloc_space.cc
+++ b/runtime/gc/space/malloc_space.cc
@@ -16,6 +16,8 @@
 
 #include "malloc_space.h"
 
+#include <ostream>
+
 #include "android-base/stringprintf.h"
 
 #include "base/logging.h"  // For VLOG
diff --git a/runtime/gc/space/malloc_space.h b/runtime/gc/space/malloc_space.h
index 7d28516..9a90dfd 100644
--- a/runtime/gc/space/malloc_space.h
+++ b/runtime/gc/space/malloc_space.h
@@ -19,7 +19,8 @@
 
 #include "space.h"
 
-#include <ostream>
+#include <iosfwd>
+
 #include "base/memory_tool.h"
 #include "base/mutex.h"
 
diff --git a/runtime/gc/space/space.h b/runtime/gc/space/space.h
index dd5451b..903263f 100644
--- a/runtime/gc/space/space.h
+++ b/runtime/gc/space/space.h
@@ -21,12 +21,12 @@
 #include <string>
 
 #include "base/atomic.h"
-#include "base/globals.h"
 #include "base/locks.h"
 #include "base/macros.h"
 #include "base/mem_map.h"
 #include "gc/accounting/space_bitmap.h"
 #include "gc/collector/object_byte_pair.h"
+#include "runtime_globals.h"
 
 namespace art {
 namespace mirror {
diff --git a/runtime/gc/space/space_test.h b/runtime/gc/space/space_test.h
index 1b111e3..7fbd0b5 100644
--- a/runtime/gc/space/space_test.h
+++ b/runtime/gc/space/space_test.h
@@ -20,13 +20,13 @@
 #include <stdint.h>
 #include <memory>
 
-#include "base/globals.h"
 #include "common_runtime_test.h"
 #include "handle_scope-inl.h"
 #include "mirror/array-inl.h"
 #include "mirror/class-inl.h"
 #include "mirror/class_loader.h"
 #include "mirror/object-inl.h"
+#include "runtime_globals.h"
 #include "scoped_thread_state_change-inl.h"
 #include "thread_list.h"
 #include "zygote_space.h"
diff --git a/runtime/gc/task_processor.h b/runtime/gc/task_processor.h
index 6db3c37..86e36ab 100644
--- a/runtime/gc/task_processor.h
+++ b/runtime/gc/task_processor.h
@@ -20,8 +20,8 @@
 #include <memory>
 #include <set>
 
-#include "base/globals.h"
 #include "base/mutex.h"
+#include "runtime_globals.h"
 #include "thread_pool.h"
 
 namespace art {
diff --git a/runtime/handle_scope-inl.h b/runtime/handle_scope-inl.h
index f61c700..765ed7d 100644
--- a/runtime/handle_scope-inl.h
+++ b/runtime/handle_scope-inl.h
@@ -21,6 +21,7 @@
 
 #include "base/mutex.h"
 #include "handle.h"
+#include "handle_wrapper.h"
 #include "obj_ptr-inl.h"
 #include "thread-current-inl.h"
 #include "verify_object.h"
@@ -106,6 +107,15 @@
       handle_scope_entry <= &GetReferences()[number_of_references_ - 1];
 }
 
+template <typename Visitor>
+inline void HandleScope::VisitRoots(Visitor& visitor) {
+  for (size_t i = 0, count = NumberOfReferences(); i < count; ++i) {
+    // GetReference returns a pointer to the stack reference within the handle scope. If this
+    // needs to be updated, it will be done by the root visitor.
+    visitor.VisitRootIfNonNull(GetHandle(i).GetReference());
+  }
+}
+
 template<size_t kNumReferences> template<class T>
 inline MutableHandle<T> FixedSizeHandleScope<kNumReferences>::NewHandle(T* object) {
   SetReference(pos_, object);
diff --git a/runtime/handle_scope.h b/runtime/handle_scope.h
index 1a1c92f..dae8e29 100644
--- a/runtime/handle_scope.h
+++ b/runtime/handle_scope.h
@@ -24,13 +24,16 @@
 #include "base/enums.h"
 #include "base/locks.h"
 #include "base/macros.h"
-#include "handle.h"
 #include "stack_reference.h"
 #include "verify_object.h"
 
 namespace art {
 
+template<class T> class Handle;
 class HandleScope;
+template<class T> class HandleWrapper;
+template<class T> class HandleWrapperObjPtr;
+template<class T> class MutableHandle;
 template<class MirrorType> class ObjPtr;
 class Thread;
 class VariableSizedHandleScope;
@@ -144,13 +147,7 @@
   }
 
   template <typename Visitor>
-  void VisitRoots(Visitor& visitor) REQUIRES_SHARED(Locks::mutator_lock_) {
-    for (size_t i = 0, count = NumberOfReferences(); i < count; ++i) {
-      // GetReference returns a pointer to the stack reference within the handle scope. If this
-      // needs to be updated, it will be done by the root visitor.
-      visitor.VisitRootIfNonNull(GetHandle(i).GetReference());
-    }
-  }
+  ALWAYS_INLINE void VisitRoots(Visitor& visitor) REQUIRES_SHARED(Locks::mutator_lock_);
 
  protected:
   // Return backing storage used for references.
@@ -172,44 +169,6 @@
   DISALLOW_COPY_AND_ASSIGN(HandleScope);
 };
 
-// A wrapper which wraps around Object** and restores the pointer in the destructor.
-// TODO: Delete
-template<class T>
-class HandleWrapper : public MutableHandle<T> {
- public:
-  HandleWrapper(T** obj, const MutableHandle<T>& handle)
-     : MutableHandle<T>(handle), obj_(obj) {
-  }
-
-  HandleWrapper(const HandleWrapper&) = default;
-
-  ~HandleWrapper() {
-    *obj_ = MutableHandle<T>::Get();
-  }
-
- private:
-  T** const obj_;
-};
-
-
-// A wrapper which wraps around ObjPtr<Object>* and restores the pointer in the destructor.
-// TODO: Add more functionality.
-template<class T>
-class HandleWrapperObjPtr : public MutableHandle<T> {
- public:
-  HandleWrapperObjPtr(ObjPtr<T>* obj, const MutableHandle<T>& handle)
-      : MutableHandle<T>(handle), obj_(obj) {}
-
-  HandleWrapperObjPtr(const HandleWrapperObjPtr&) = default;
-
-  ~HandleWrapperObjPtr() {
-    *obj_ = ObjPtr<T>(MutableHandle<T>::Get());
-  }
-
- private:
-  ObjPtr<T>* const obj_;
-};
-
 // Fixed size handle scope that is not necessarily linked in the thread.
 template<size_t kNumReferences>
 class PACKED(4) FixedSizeHandleScope : public HandleScope {
diff --git a/runtime/handle_wrapper.h b/runtime/handle_wrapper.h
new file mode 100644
index 0000000..01252c7
--- /dev/null
+++ b/runtime/handle_wrapper.h
@@ -0,0 +1,65 @@
+/*
+ * Copyright (C) 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef ART_RUNTIME_HANDLE_WRAPPER_H_
+#define ART_RUNTIME_HANDLE_WRAPPER_H_
+
+#include "handle.h"
+#include "obj_ptr.h"
+
+namespace art {
+
+// A wrapper which wraps around Object** and restores the pointer in the destructor.
+// TODO: Delete
+template<class T>
+class HandleWrapper : public MutableHandle<T> {
+ public:
+  HandleWrapper(T** obj, const MutableHandle<T>& handle)
+     : MutableHandle<T>(handle), obj_(obj) {
+  }
+
+  HandleWrapper(const HandleWrapper&) = default;
+
+  ~HandleWrapper() {
+    *obj_ = MutableHandle<T>::Get();
+  }
+
+ private:
+  T** const obj_;
+};
+
+
+// A wrapper which wraps around ObjPtr<Object>* and restores the pointer in the destructor.
+// TODO: Add more functionality.
+template<class T>
+class HandleWrapperObjPtr : public MutableHandle<T> {
+ public:
+  HandleWrapperObjPtr(ObjPtr<T>* obj, const MutableHandle<T>& handle)
+      : MutableHandle<T>(handle), obj_(obj) {}
+
+  HandleWrapperObjPtr(const HandleWrapperObjPtr&) = default;
+
+  ~HandleWrapperObjPtr() {
+    *obj_ = ObjPtr<T>(MutableHandle<T>::Get());
+  }
+
+ private:
+  ObjPtr<T>* const obj_;
+};
+
+}  // namespace art
+
+#endif  // ART_RUNTIME_HANDLE_WRAPPER_H_
diff --git a/runtime/hprof/hprof.cc b/runtime/hprof/hprof.cc
index 3abe4c5..34f645b 100644
--- a/runtime/hprof/hprof.cc
+++ b/runtime/hprof/hprof.cc
@@ -42,7 +42,6 @@
 #include "art_method-inl.h"
 #include "base/array_ref.h"
 #include "base/file_utils.h"
-#include "base/globals.h"
 #include "base/macros.h"
 #include "base/mutex.h"
 #include "base/os.h"
@@ -66,6 +65,7 @@
 #include "mirror/class-inl.h"
 #include "mirror/class.h"
 #include "mirror/object-refvisitor-inl.h"
+#include "runtime_globals.h"
 #include "scoped_thread_state_change-inl.h"
 #include "thread_list.h"
 
diff --git a/runtime/image.h b/runtime/image.h
index 140f504..6578287 100644
--- a/runtime/image.h
+++ b/runtime/image.h
@@ -20,9 +20,9 @@
 #include <string.h>
 
 #include "base/enums.h"
-#include "base/globals.h"
 #include "base/iteration_range.h"
 #include "mirror/object.h"
+#include "runtime_globals.h"
 
 namespace art {
 
diff --git a/runtime/instrumentation.cc b/runtime/instrumentation.cc
index 27c47bc..36f7b3d 100644
--- a/runtime/instrumentation.cc
+++ b/runtime/instrumentation.cc
@@ -848,7 +848,7 @@
         new_quick_code = GetQuickInstrumentationEntryPoint();
         if (!method->IsNative() && Runtime::Current()->GetJit() != nullptr) {
           // Native methods use trampoline entrypoints during interpreter tracing.
-          DCHECK(!Runtime::Current()->GetJit()->GetCodeCache()->GetGarbageCollectCode());
+          DCHECK(!Runtime::Current()->GetJit()->GetCodeCache()->GetGarbageCollectCodeUnsafe());
           ProfilingInfo* profiling_info = method->GetProfilingInfo(kRuntimePointerSize);
           // Tracing will look at the saved entry point in the profiling info to know the actual
           // entrypoint, so we store it here.
@@ -1050,14 +1050,6 @@
     level = InstrumentationLevel::kInstrumentWithInterpreter;
   } else {
     level = InstrumentationLevel::kInstrumentWithInstrumentationStubs;
-    if (Runtime::Current()->GetJit() != nullptr) {
-      // TODO b/110263880 It would be better if we didn't need to do this.
-      // Since we need to hold the method entrypoint across a suspend to ensure instrumentation
-      // hooks are called correctly we have to disable jit-gc to ensure that the entrypoint doesn't
-      // go away. Furthermore we need to leave this off permanently since one could get the same
-      // effect by causing this to be toggled on and off.
-      Runtime::Current()->GetJit()->GetCodeCache()->SetGarbageCollectCode(false);
-    }
   }
   ConfigureStubs(key, level);
 }
diff --git a/runtime/jdwp_provider.h b/runtime/jdwp_provider.h
index 9579513..29fbc3f 100644
--- a/runtime/jdwp_provider.h
+++ b/runtime/jdwp_provider.h
@@ -19,7 +19,7 @@
 
 #include <ios>
 
-#include "base/globals.h"
+#include "runtime_globals.h"
 
 namespace art {
 
diff --git a/runtime/jit/jit_code_cache.cc b/runtime/jit/jit_code_cache.cc
index d976fec..c1b9a1a 100644
--- a/runtime/jit/jit_code_cache.cc
+++ b/runtime/jit/jit_code_cache.cc
@@ -390,7 +390,7 @@
 
   // Zygote should never collect code to share the memory with the children.
   if (is_zygote) {
-    jit_code_cache->SetGarbageCollectCode(false);
+    jit_code_cache->garbage_collect_code_ = false;
   }
 
   if (!jit_code_cache->InitializeMappings(rwx_memory_allowed, is_zygote, error_msg)) {
@@ -1247,6 +1247,24 @@
   }
 }
 
+void JitCodeCache::ClearEntryPointsInZygoteExecSpace() {
+  MutexLock mu(Thread::Current(), lock_);
+  // Iterate over profiling infos to know which methods may have been JITted. Note that
+  // to be JITted, a method must have a profiling info.
+  for (ProfilingInfo* info : profiling_infos_) {
+    ArtMethod* method = info->GetMethod();
+    if (IsInZygoteExecSpace(method->GetEntryPointFromQuickCompiledCode())) {
+      method->SetEntryPointFromQuickCompiledCode(GetQuickToInterpreterBridge());
+    }
+    // If zygote does method tracing, or in some configuration where
+    // the JIT zygote does GC, we also need to clear the saved entry point
+    // in the profiling info.
+    if (IsInZygoteExecSpace(info->GetSavedEntryPoint())) {
+      info->SetSavedEntryPoint(nullptr);
+    }
+  }
+}
+
 size_t JitCodeCache::CodeCacheSizeLocked() {
   return used_memory_for_code_;
 }
@@ -1437,17 +1455,14 @@
 
 void JitCodeCache::GarbageCollectCache(Thread* self) {
   ScopedTrace trace(__FUNCTION__);
-  if (!garbage_collect_code_) {
-    MutexLock mu(self, lock_);
-    IncreaseCodeCacheCapacity();
-    return;
-  }
-
   // Wait for an existing collection, or let everyone know we are starting one.
   {
     ScopedThreadSuspension sts(self, kSuspended);
     MutexLock mu(self, lock_);
-    if (WaitForPotentialCollectionToComplete(self)) {
+    if (!garbage_collect_code_) {
+      IncreaseCodeCacheCapacity();
+      return;
+    } else if (WaitForPotentialCollectionToComplete(self)) {
       return;
     } else {
       number_of_collections_++;
@@ -1573,6 +1588,29 @@
   FreeAllMethodHeaders(method_headers);
 }
 
+bool JitCodeCache::GetGarbageCollectCode() {
+  MutexLock mu(Thread::Current(), lock_);
+  return garbage_collect_code_;
+}
+
+void JitCodeCache::SetGarbageCollectCode(bool value) {
+  Thread* self = Thread::Current();
+  MutexLock mu(self, lock_);
+  if (garbage_collect_code_ != value) {
+    if (garbage_collect_code_) {
+      // When dynamically disabling the garbage collection, we neee
+      // to make sure that a potential current collection is finished, and also
+      // clear the saved entry point in profiling infos to avoid dangling pointers.
+      WaitForPotentialCollectionToComplete(self);
+      for (ProfilingInfo* info : profiling_infos_) {
+        info->SetSavedEntryPoint(nullptr);
+      }
+    }
+    // Update the flag while holding the lock to ensure no thread will try to GC.
+    garbage_collect_code_ = value;
+  }
+}
+
 void JitCodeCache::DoCollection(Thread* self, bool collect_profiling_info) {
   ScopedTrace trace(__FUNCTION__);
   {
diff --git a/runtime/jit/jit_code_cache.h b/runtime/jit/jit_code_cache.h
index e2f3357..8a6cebe 100644
--- a/runtime/jit/jit_code_cache.h
+++ b/runtime/jit/jit_code_cache.h
@@ -246,13 +246,13 @@
   void MoveObsoleteMethod(ArtMethod* old_method, ArtMethod* new_method)
       REQUIRES(!lock_) REQUIRES(Locks::mutator_lock_);
 
-  // Dynamically change whether we want to garbage collect code. Should only be used during JIT
-  // initialization or by tests.
-  void SetGarbageCollectCode(bool value) {
-    garbage_collect_code_ = value;
-  }
+  // Dynamically change whether we want to garbage collect code.
+  void SetGarbageCollectCode(bool value) REQUIRES(!lock_);
 
-  bool GetGarbageCollectCode() const {
+  bool GetGarbageCollectCode() REQUIRES(!lock_);
+
+  // Unsafe variant for debug checks.
+  bool GetGarbageCollectCodeUnsafe() const NO_THREAD_SAFETY_ANALYSIS {
     return garbage_collect_code_;
   }
 
@@ -264,6 +264,11 @@
 
   void PostForkChildAction(bool is_system_server, bool is_zygote);
 
+  // Clear the entrypoints of JIT compiled methods that belong in the zygote space.
+  // This is used for removing non-debuggable JIT code at the point we realize the runtime
+  // is debuggable.
+  void ClearEntryPointsInZygoteExecSpace() REQUIRES(!lock_) REQUIRES(Locks::mutator_lock_);
+
  private:
   JitCodeCache();
 
@@ -451,7 +456,7 @@
   bool last_collection_increased_code_cache_ GUARDED_BY(lock_);
 
   // Whether we can do garbage collection. Not 'const' as tests may override this.
-  bool garbage_collect_code_;
+  bool garbage_collect_code_ GUARDED_BY(lock_);
 
   // The size in bytes of used memory for the data portion of the code cache.
   size_t used_memory_for_data_ GUARDED_BY(lock_);
diff --git a/runtime/mirror/class-inl.h b/runtime/mirror/class-inl.h
index 40c7d30..fe49813 100644
--- a/runtime/mirror/class-inl.h
+++ b/runtime/mirror/class-inl.h
@@ -39,6 +39,7 @@
 #include "runtime.h"
 #include "string.h"
 #include "subtype_check.h"
+#include "thread-current-inl.h"
 
 namespace art {
 namespace mirror {
@@ -1117,6 +1118,18 @@
   }
 }
 
+inline void Class::SetRecursivelyInitialized() {
+  DCHECK_EQ(GetLockOwnerThreadId(), Thread::Current()->GetThreadId());
+  uint32_t flags = GetField32(OFFSET_OF_OBJECT_MEMBER(Class, access_flags_));
+  SetAccessFlags(flags | kAccRecursivelyInitialized);
+}
+
+inline void Class::SetHasDefaultMethods() {
+  DCHECK_EQ(GetLockOwnerThreadId(), Thread::Current()->GetThreadId());
+  uint32_t flags = GetField32(OFFSET_OF_OBJECT_MEMBER(Class, access_flags_));
+  SetAccessFlags(flags | kAccHasDefaultMethod);
+}
+
 }  // namespace mirror
 }  // namespace art
 
diff --git a/runtime/mirror/class.h b/runtime/mirror/class.h
index f7a41f7..d35d526 100644
--- a/runtime/mirror/class.h
+++ b/runtime/mirror/class.h
@@ -30,7 +30,6 @@
 #include "object.h"
 #include "object_array.h"
 #include "read_barrier_option.h"
-#include "thread-current-inl.h"
 
 namespace art {
 
@@ -52,6 +51,7 @@
 class Signature;
 class StringPiece;
 template<size_t kNumReferences> class PACKED(4) StackHandleScope;
+class Thread;
 
 namespace mirror {
 
@@ -223,17 +223,9 @@
     SetAccessFlags(flags | kAccSkipHiddenapiChecks);
   }
 
-  ALWAYS_INLINE void SetRecursivelyInitialized() REQUIRES_SHARED(Locks::mutator_lock_) {
-    DCHECK_EQ(GetLockOwnerThreadId(), Thread::Current()->GetThreadId());
-    uint32_t flags = GetField32(OFFSET_OF_OBJECT_MEMBER(Class, access_flags_));
-    SetAccessFlags(flags | kAccRecursivelyInitialized);
-  }
+  ALWAYS_INLINE void SetRecursivelyInitialized() REQUIRES_SHARED(Locks::mutator_lock_);
 
-  ALWAYS_INLINE void SetHasDefaultMethods() REQUIRES_SHARED(Locks::mutator_lock_) {
-    DCHECK_EQ(GetLockOwnerThreadId(), Thread::Current()->GetThreadId());
-    uint32_t flags = GetField32(OFFSET_OF_OBJECT_MEMBER(Class, access_flags_));
-    SetAccessFlags(flags | kAccHasDefaultMethod);
-  }
+  ALWAYS_INLINE void SetHasDefaultMethods() REQUIRES_SHARED(Locks::mutator_lock_);
 
   ALWAYS_INLINE void SetFinalizable() REQUIRES_SHARED(Locks::mutator_lock_) {
     uint32_t flags = GetField32(OFFSET_OF_OBJECT_MEMBER(Class, access_flags_));
diff --git a/runtime/mirror/dex_cache.cc b/runtime/mirror/dex_cache.cc
index 8d2b838..7e79ebe 100644
--- a/runtime/mirror/dex_cache.cc
+++ b/runtime/mirror/dex_cache.cc
@@ -17,7 +17,6 @@
 #include "dex_cache-inl.h"
 
 #include "art_method-inl.h"
-#include "base/globals.h"
 #include "class_linker.h"
 #include "gc/accounting/card_table-inl.h"
 #include "gc/heap.h"
@@ -27,6 +26,7 @@
 #include "object.h"
 #include "object_array-inl.h"
 #include "runtime.h"
+#include "runtime_globals.h"
 #include "string.h"
 #include "thread.h"
 #include "utils/dex_cache_arrays_layout-inl.h"
diff --git a/runtime/mirror/object.h b/runtime/mirror/object.h
index bca7511..ba222f6 100644
--- a/runtime/mirror/object.h
+++ b/runtime/mirror/object.h
@@ -20,13 +20,13 @@
 #include "base/atomic.h"
 #include "base/casts.h"
 #include "base/enums.h"
-#include "base/globals.h"
 #include "dex/primitive.h"
 #include "obj_ptr.h"
 #include "object_reference.h"
 #include "offsets.h"
 #include "read_barrier_config.h"
 #include "read_barrier_option.h"
+#include "runtime_globals.h"
 #include "verify_object.h"
 
 namespace art {
diff --git a/runtime/mirror/object_reference.h b/runtime/mirror/object_reference.h
index 8636928..e19e165 100644
--- a/runtime/mirror/object_reference.h
+++ b/runtime/mirror/object_reference.h
@@ -18,10 +18,10 @@
 #define ART_RUNTIME_MIRROR_OBJECT_REFERENCE_H_
 
 #include "base/atomic.h"
-#include "base/globals.h"
 #include "base/locks.h"  // For Locks::mutator_lock_.
 #include "heap_poisoning.h"
 #include "obj_ptr.h"
+#include "runtime_globals.h"
 
 namespace art {
 namespace mirror {
diff --git a/runtime/mirror/string-alloc-inl.h b/runtime/mirror/string-alloc-inl.h
index c31eccf..4c4e2af 100644
--- a/runtime/mirror/string-alloc-inl.h
+++ b/runtime/mirror/string-alloc-inl.h
@@ -22,11 +22,11 @@
 
 #include "array.h"
 #include "base/bit_utils.h"
-#include "base/globals.h"
 #include "class.h"
 #include "class_root.h"
 #include "gc/heap-inl.h"
 #include "runtime.h"
+#include "runtime_globals.h"
 #include "thread.h"
 
 namespace art {
diff --git a/runtime/mirror/string-inl.h b/runtime/mirror/string-inl.h
index e11906a..f04a8aa 100644
--- a/runtime/mirror/string-inl.h
+++ b/runtime/mirror/string-inl.h
@@ -20,10 +20,10 @@
 
 #include "android-base/stringprintf.h"
 
-#include "base/globals.h"
 #include "class-inl.h"
 #include "common_throws.h"
 #include "dex/utf.h"
+#include "runtime_globals.h"
 
 namespace art {
 namespace mirror {
diff --git a/runtime/mirror/string.h b/runtime/mirror/string.h
index b32db08..c367957 100644
--- a/runtime/mirror/string.h
+++ b/runtime/mirror/string.h
@@ -18,10 +18,10 @@
 #define ART_RUNTIME_MIRROR_STRING_H_
 
 #include "base/bit_utils.h"
-#include "base/globals.h"
 #include "gc/allocator_type.h"
 #include "class.h"
 #include "object.h"
+#include "runtime_globals.h"
 
 namespace art {
 
diff --git a/runtime/native/dalvik_system_ZygoteHooks.cc b/runtime/native/dalvik_system_ZygoteHooks.cc
index 9ce4749..26fc5e9 100644
--- a/runtime/native/dalvik_system_ZygoteHooks.cc
+++ b/runtime/native/dalvik_system_ZygoteHooks.cc
@@ -203,8 +203,11 @@
     runtime->AddCompilerOption("--debuggable");
     runtime_flags |= DEBUG_GENERATE_MINI_DEBUG_INFO;
     runtime->SetJavaDebuggable(true);
-    // Deoptimize the boot image as it may be non-debuggable.
-    runtime->DeoptimizeBootImage();
+    {
+      // Deoptimize the boot image as it may be non-debuggable.
+      ScopedSuspendAll ssa(__FUNCTION__);
+      runtime->DeoptimizeBootImage();
+    }
     runtime_flags &= ~DEBUG_JAVA_DEBUGGABLE;
     needs_non_debuggable_classes = true;
   }
diff --git a/runtime/oat.cc b/runtime/oat.cc
index d7c968f..c6a963a 100644
--- a/runtime/oat.cc
+++ b/runtime/oat.cc
@@ -20,6 +20,7 @@
 
 #include "android-base/stringprintf.h"
 
+#include "arch/instruction_set.h"
 #include "arch/instruction_set_features.h"
 #include "base/bit_utils.h"
 #include "base/strlcpy.h"
diff --git a/runtime/oat.h b/runtime/oat.h
index ded1489..88238d9 100644
--- a/runtime/oat.h
+++ b/runtime/oat.h
@@ -19,13 +19,13 @@
 
 #include <vector>
 
-#include "arch/instruction_set.h"
 #include "base/macros.h"
 #include "base/safe_map.h"
 #include "compiler_filter.h"
 
 namespace art {
 
+enum class InstructionSet;
 class InstructionSetFeatures;
 
 class PACKED(4) OatHeader {
diff --git a/runtime/obj_ptr-inl.h b/runtime/obj_ptr-inl.h
index b949c96..f096445 100644
--- a/runtime/obj_ptr-inl.h
+++ b/runtime/obj_ptr-inl.h
@@ -17,6 +17,8 @@
 #ifndef ART_RUNTIME_OBJ_PTR_INL_H_
 #define ART_RUNTIME_OBJ_PTR_INL_H_
 
+#include <ostream>
+
 #include "base/bit_utils.h"
 #include "obj_ptr.h"
 #include "thread-current-inl.h"
diff --git a/runtime/obj_ptr.h b/runtime/obj_ptr.h
index 9e2ee29..b0f24da 100644
--- a/runtime/obj_ptr.h
+++ b/runtime/obj_ptr.h
@@ -17,12 +17,12 @@
 #ifndef ART_RUNTIME_OBJ_PTR_H_
 #define ART_RUNTIME_OBJ_PTR_H_
 
-#include <ostream>
+#include <iosfwd>
 #include <type_traits>
 
-#include "base/globals.h"
 #include "base/locks.h"  // For Locks::mutator_lock_.
 #include "base/macros.h"
+#include "runtime_globals.h"
 
 // Always inline ObjPtr methods even in debug builds.
 #define OBJPTR_INLINE __attribute__ ((always_inline))
diff --git a/runtime/offsets.h b/runtime/offsets.h
index 372b821..6d1a8e0 100644
--- a/runtime/offsets.h
+++ b/runtime/offsets.h
@@ -17,10 +17,10 @@
 #ifndef ART_RUNTIME_OFFSETS_H_
 #define ART_RUNTIME_OFFSETS_H_
 
-#include <ostream>
+#include <iosfwd>
 
 #include "base/enums.h"
-#include "base/globals.h"
+#include "runtime_globals.h"
 
 namespace art {
 
diff --git a/runtime/parsed_options.h b/runtime/parsed_options.h
index 8c77d39..095d66e 100644
--- a/runtime/parsed_options.h
+++ b/runtime/parsed_options.h
@@ -23,10 +23,10 @@
 #include <jni.h>
 
 #include "arch/instruction_set.h"
-#include "base/globals.h"
 #include "gc/collector_type.h"
 #include "gc/space/large_object_space.h"
 // #include "jit/profile_saver_options.h"
+#include "runtime_globals.h"
 #include "runtime_options.h"
 
 namespace art {
diff --git a/runtime/reflection.cc b/runtime/reflection.cc
index dfd7e64..dbf40f6 100644
--- a/runtime/reflection.cc
+++ b/runtime/reflection.cc
@@ -33,6 +33,7 @@
 #include "nth_caller_visitor.h"
 #include "scoped_thread_state_change-inl.h"
 #include "stack_reference.h"
+#include "thread-inl.h"
 #include "well_known_classes.h"
 
 namespace art {
diff --git a/runtime/runtime.cc b/runtime/runtime.cc
index f30ba0c..eea7c67 100644
--- a/runtime/runtime.cc
+++ b/runtime/runtime.cc
@@ -42,6 +42,7 @@
 #include "aot_class_linker.h"
 #include "arch/arm/registers_arm.h"
 #include "arch/arm64/registers_arm64.h"
+#include "arch/context.h"
 #include "arch/instruction_set_features.h"
 #include "arch/mips/registers_mips.h"
 #include "arch/mips64/registers_mips64.h"
@@ -1472,6 +1473,8 @@
     if (IsJavaDebuggable()) {
       // Now that we have loaded the boot image, deoptimize its methods if we are running
       // debuggable, as the code may have been compiled non-debuggable.
+      ScopedThreadSuspension sts(self, ThreadState::kNative);
+      ScopedSuspendAll ssa(__FUNCTION__);
       DeoptimizeBootImage();
     }
   } else {
@@ -1571,10 +1574,14 @@
   // Runtime initialization is largely done now.
   // We load plugins first since that can modify the runtime state slightly.
   // Load all plugins
-  for (auto& plugin : plugins_) {
-    std::string err;
-    if (!plugin.Load(&err)) {
-      LOG(FATAL) << plugin << " failed to load: " << err;
+  {
+    // The init method of plugins expect the state of the thread to be non runnable.
+    ScopedThreadSuspension sts(self, ThreadState::kNative);
+    for (auto& plugin : plugins_) {
+      std::string err;
+      if (!plugin.Load(&err)) {
+        LOG(FATAL) << plugin << " failed to load: " << err;
+      }
     }
   }
 
@@ -2647,6 +2654,7 @@
       : instrumentation_(instrumentation) {}
 
   bool operator()(ObjPtr<mirror::Class> klass) override REQUIRES(Locks::mutator_lock_) {
+    DCHECK(Locks::mutator_lock_->IsExclusiveHeld(Thread::Current()));
     auto pointer_size = Runtime::Current()->GetClassLinker()->GetImagePointerSize();
     for (auto& m : klass->GetMethods(pointer_size)) {
       const void* code = m.GetEntryPointFromQuickCompiledCode();
@@ -2673,9 +2681,13 @@
   // we patch entry points of methods in boot image to interpreter bridge, as
   // boot image code may be AOT compiled as not debuggable.
   if (!GetInstrumentation()->IsForcedInterpretOnly()) {
-    ScopedObjectAccess soa(Thread::Current());
     UpdateEntryPointsClassVisitor visitor(GetInstrumentation());
     GetClassLinker()->VisitClasses(&visitor);
+    jit::Jit* jit = GetJit();
+    if (jit != nullptr) {
+      // Code JITted by the zygote is not compiled debuggable.
+      jit->GetCodeCache()->ClearEntryPointsInZygoteExecSpace();
+    }
   }
 }
 
diff --git a/runtime/runtime.h b/runtime/runtime.h
index a2d519d..1acb75b 100644
--- a/runtime/runtime.h
+++ b/runtime/runtime.h
@@ -27,7 +27,6 @@
 #include <memory>
 #include <vector>
 
-#include "arch/instruction_set.h"
 #include "base/locks.h"
 #include "base/macros.h"
 #include "base/mem_map.h"
@@ -84,6 +83,7 @@
 class ClassLinker;
 class CompilerCallbacks;
 class DexFile;
+enum class InstructionSet;
 class InternTable;
 class IsMarkedVisitor;
 class JavaVMExt;
@@ -634,7 +634,7 @@
   void SetJavaDebuggable(bool value);
 
   // Deoptimize the boot image, called for Java debuggable apps.
-  void DeoptimizeBootImage();
+  void DeoptimizeBootImage() REQUIRES(Locks::mutator_lock_);
 
   bool IsNativeDebuggable() const {
     return is_native_debuggable_;
diff --git a/runtime/runtime_globals.h b/runtime/runtime_globals.h
new file mode 100644
index 0000000..793291a
--- /dev/null
+++ b/runtime/runtime_globals.h
@@ -0,0 +1,82 @@
+/*
+ * Copyright (C) 2011 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef ART_RUNTIME_RUNTIME_GLOBALS_H_
+#define ART_RUNTIME_RUNTIME_GLOBALS_H_
+
+#include "base/globals.h"
+
+namespace art {
+
+// Size of Dex virtual registers.
+static constexpr size_t kVRegSize = 4;
+
+// Returns whether the given memory offset can be used for generating
+// an implicit null check.
+static inline bool CanDoImplicitNullCheckOn(uintptr_t offset) {
+  return offset < kPageSize;
+}
+
+// Required object alignment
+static constexpr size_t kObjectAlignmentShift = 3;
+static constexpr size_t kObjectAlignment = 1u << kObjectAlignmentShift;
+static constexpr size_t kLargeObjectAlignment = kPageSize;
+
+// Garbage collector constants.
+static constexpr bool kMovingCollector = true;
+static constexpr bool kMarkCompactSupport = false && kMovingCollector;
+// True if we allow moving classes.
+static constexpr bool kMovingClasses = !kMarkCompactSupport;
+// If true, enable generational collection when using the Concurrent Copying
+// (CC) collector, i.e. use sticky-bit CC for minor collections and (full) CC
+// for major collections.
+//
+// Generational CC collection is currently only compatible with Baker read
+// barriers.
+#if defined(ART_USE_GENERATIONAL_CC) && defined(ART_READ_BARRIER_TYPE_IS_BAKER)
+static constexpr bool kEnableGenerationalConcurrentCopyingCollection = true;
+#else
+static constexpr bool kEnableGenerationalConcurrentCopyingCollection = false;
+#endif
+
+// If true, enable the tlab allocator by default.
+#ifdef ART_USE_TLAB
+static constexpr bool kUseTlab = true;
+#else
+static constexpr bool kUseTlab = false;
+#endif
+
+// Kinds of tracing clocks.
+enum class TraceClockSource {
+  kThreadCpu,
+  kWall,
+  kDual,  // Both wall and thread CPU clocks.
+};
+
+#if defined(__linux__)
+static constexpr TraceClockSource kDefaultTraceClockSource = TraceClockSource::kDual;
+#else
+static constexpr TraceClockSource kDefaultTraceClockSource = TraceClockSource::kWall;
+#endif
+
+static constexpr bool kDefaultMustRelocate = true;
+
+// Size of a heap reference.
+static constexpr size_t kHeapReferenceSize = sizeof(uint32_t);
+
+}  // namespace art
+
+#endif  // ART_RUNTIME_RUNTIME_GLOBALS_H_
diff --git a/runtime/stack.cc b/runtime/stack.cc
index 25939d2..9a677de 100644
--- a/runtime/stack.cc
+++ b/runtime/stack.cc
@@ -568,7 +568,9 @@
     cur_shadow_frame_->SetMethod(method);
   } else {
     DCHECK(cur_quick_frame_ != nullptr);
-    CHECK(!IsInInlinedFrame()) << "We do not support setting inlined method's ArtMethod!";
+    CHECK(!IsInInlinedFrame()) << "We do not support setting inlined method's ArtMethod: "
+                               << GetMethod()->PrettyMethod() << " is inlined into "
+                               << GetOuterMethod()->PrettyMethod();
     *cur_quick_frame_ = method;
   }
 }
diff --git a/runtime/suspend_reason.h b/runtime/suspend_reason.h
index 289a1a4..af2be10 100644
--- a/runtime/suspend_reason.h
+++ b/runtime/suspend_reason.h
@@ -17,7 +17,7 @@
 #ifndef ART_RUNTIME_SUSPEND_REASON_H_
 #define ART_RUNTIME_SUSPEND_REASON_H_
 
-#include <ostream>
+#include <iosfwd>
 
 namespace art {
 
diff --git a/runtime/thread-inl.h b/runtime/thread-inl.h
index 0c00fb9..00f882e 100644
--- a/runtime/thread-inl.h
+++ b/runtime/thread-inl.h
@@ -19,6 +19,7 @@
 
 #include "thread.h"
 
+#include "arch/instruction_set.h"
 #include "base/aborting.h"
 #include "base/casts.h"
 #include "base/mutex-inl.h"
@@ -393,6 +394,26 @@
   return tlsPtr_.managed_stack.PopShadowFrame();
 }
 
+inline uint8_t* Thread::GetStackEndForInterpreter(bool implicit_overflow_check) const {
+  uint8_t* end = tlsPtr_.stack_end + (implicit_overflow_check
+      ? GetStackOverflowReservedBytes(kRuntimeISA)
+          : 0);
+  if (kIsDebugBuild) {
+    // In a debuggable build, but especially under ASAN, the access-checks interpreter has a
+    // potentially humongous stack size. We don't want to take too much of the stack regularly,
+    // so do not increase the regular reserved size (for compiled code etc) and only report the
+    // virtually smaller stack to the interpreter here.
+    end += GetStackOverflowReservedBytes(kRuntimeISA);
+  }
+  return end;
+}
+
+inline void Thread::ResetDefaultStackEnd() {
+  // Our stacks grow down, so we want stack_end_ to be near there, but reserving enough room
+  // to throw a StackOverflowError.
+  tlsPtr_.stack_end = tlsPtr_.stack_begin + GetStackOverflowReservedBytes(kRuntimeISA);
+}
+
 }  // namespace art
 
 #endif  // ART_RUNTIME_THREAD_INL_H_
diff --git a/runtime/thread.cc b/runtime/thread.cc
index 7c050a4..309c04e 100644
--- a/runtime/thread.cc
+++ b/runtime/thread.cc
@@ -48,6 +48,7 @@
 #include "base/atomic.h"
 #include "base/bit_utils.h"
 #include "base/casts.h"
+#include "arch/context.h"
 #include "base/file_utils.h"
 #include "base/memory_tool.h"
 #include "base/mutex.h"
@@ -4232,4 +4233,17 @@
   Runtime::Current()->GetThreadList()->RunCheckpoint(&closure);
 }
 
+void Thread::ReleaseLongJumpContextInternal() {
+  // Each QuickExceptionHandler gets a long jump context and uses
+  // it for doing the long jump, after finding catch blocks/doing deoptimization.
+  // Both finding catch blocks and deoptimization can trigger another
+  // exception such as a result of class loading. So there can be nested
+  // cases of exception handling and multiple contexts being used.
+  // ReleaseLongJumpContext tries to save the context in tlsPtr_.long_jump_context
+  // for reuse so there is no need to always allocate a new one each time when
+  // getting a context. Since we only keep one context for reuse, delete the
+  // existing one since the passed in context is yet to be used for longjump.
+  delete tlsPtr_.long_jump_context;
+}
+
 }  // namespace art
diff --git a/runtime/thread.h b/runtime/thread.h
index ad69ecf..7a14fd7 100644
--- a/runtime/thread.h
+++ b/runtime/thread.h
@@ -25,14 +25,12 @@
 #include <memory>
 #include <string>
 
-#include "arch/context.h"
-#include "arch/instruction_set.h"
 #include "base/atomic.h"
 #include "base/enums.h"
-#include "base/globals.h"
 #include "base/locks.h"
 #include "base/macros.h"
 #include "base/safe_map.h"
+#include "base/value_object.h"
 #include "entrypoints/jni/jni_entrypoints.h"
 #include "entrypoints/quick/quick_entrypoints.h"
 #include "handle_scope.h"
@@ -41,6 +39,7 @@
 #include "managed_stack.h"
 #include "offsets.h"
 #include "read_barrier_config.h"
+#include "runtime_globals.h"
 #include "runtime_stats.h"
 #include "suspend_reason.h"
 #include "thread_state.h"
@@ -471,16 +470,7 @@
   Context* GetLongJumpContext();
   void ReleaseLongJumpContext(Context* context) {
     if (tlsPtr_.long_jump_context != nullptr) {
-      // Each QuickExceptionHandler gets a long jump context and uses
-      // it for doing the long jump, after finding catch blocks/doing deoptimization.
-      // Both finding catch blocks and deoptimization can trigger another
-      // exception such as a result of class loading. So there can be nested
-      // cases of exception handling and multiple contexts being used.
-      // ReleaseLongJumpContext tries to save the context in tlsPtr_.long_jump_context
-      // for reuse so there is no need to always allocate a new one each time when
-      // getting a context. Since we only keep one context for reuse, delete the
-      // existing one since the passed in context is yet to be used for longjump.
-      delete tlsPtr_.long_jump_context;
+      ReleaseLongJumpContextInternal();
     }
     tlsPtr_.long_jump_context = context;
   }
@@ -819,19 +809,7 @@
     return tlsPtr_.stack_size - (tlsPtr_.stack_end - tlsPtr_.stack_begin);
   }
 
-  uint8_t* GetStackEndForInterpreter(bool implicit_overflow_check) const {
-    uint8_t* end = tlsPtr_.stack_end + (implicit_overflow_check
-                                            ? GetStackOverflowReservedBytes(kRuntimeISA)
-                                            : 0);
-    if (kIsDebugBuild) {
-      // In a debuggable build, but especially under ASAN, the access-checks interpreter has a
-      // potentially humongous stack size. We don't want to take too much of the stack regularly,
-      // so do not increase the regular reserved size (for compiled code etc) and only report the
-      // virtually smaller stack to the interpreter here.
-      end += GetStackOverflowReservedBytes(kRuntimeISA);
-    }
-    return end;
-  }
+  ALWAYS_INLINE uint8_t* GetStackEndForInterpreter(bool implicit_overflow_check) const;
 
   uint8_t* GetStackEnd() const {
     return tlsPtr_.stack_end;
@@ -841,11 +819,7 @@
   void SetStackEndForStackOverflow() REQUIRES_SHARED(Locks::mutator_lock_);
 
   // Set the stack end to that to be used during regular execution
-  void ResetDefaultStackEnd() {
-    // Our stacks grow down, so we want stack_end_ to be near there, but reserving enough room
-    // to throw a StackOverflowError.
-    tlsPtr_.stack_end = tlsPtr_.stack_begin + GetStackOverflowReservedBytes(kRuntimeISA);
-  }
+  ALWAYS_INLINE void ResetDefaultStackEnd();
 
   bool IsHandlingStackOverflow() const {
     return tlsPtr_.stack_end == tlsPtr_.stack_begin;
@@ -1425,6 +1399,8 @@
 
   static bool IsAotCompiler();
 
+  void ReleaseLongJumpContextInternal();
+
   // 32 bits of atomically changed state and flags. Keeping as 32 bits allows and atomic CAS to
   // change from being Suspended to Runnable without a suspend request occurring.
   union PACKED(4) StateAndFlags {
diff --git a/runtime/thread_state.h b/runtime/thread_state.h
index 8edfeec..e57a040 100644
--- a/runtime/thread_state.h
+++ b/runtime/thread_state.h
@@ -17,7 +17,7 @@
 #ifndef ART_RUNTIME_THREAD_STATE_H_
 #define ART_RUNTIME_THREAD_STATE_H_
 
-#include <ostream>
+#include <iosfwd>
 
 namespace art {
 
diff --git a/runtime/trace.cc b/runtime/trace.cc
index ce955d8..074e846 100644
--- a/runtime/trace.cc
+++ b/runtime/trace.cc
@@ -38,6 +38,8 @@
 #include "entrypoints/quick/quick_entrypoints.h"
 #include "gc/scoped_gc_critical_section.h"
 #include "instrumentation.h"
+#include "jit/jit.h"
+#include "jit/jit_code_cache.h"
 #include "mirror/class-inl.h"
 #include "mirror/dex_cache-inl.h"
 #include "mirror/object-inl.h"
@@ -390,6 +392,15 @@
   // Enable count of allocs if specified in the flags.
   bool enable_stats = false;
 
+  if (runtime->GetJit() != nullptr) {
+    // TODO b/110263880 It would be better if we didn't need to do this.
+    // Since we need to hold the method entrypoint across a suspend to ensure instrumentation
+    // hooks are called correctly we have to disable jit-gc to ensure that the entrypoint doesn't
+    // go away. Furthermore we need to leave this off permanently since one could get the same
+    // effect by causing this to be toggled on and off.
+    runtime->GetJit()->GetCodeCache()->SetGarbageCollectCode(false);
+  }
+
   // Create Trace object.
   {
     // Required since EnableMethodTracing calls ConfigureStubs which visits class linker classes.
diff --git a/runtime/trace.h b/runtime/trace.h
index 582f756..567f6ed 100644
--- a/runtime/trace.h
+++ b/runtime/trace.h
@@ -27,12 +27,12 @@
 #include <vector>
 
 #include "base/atomic.h"
-#include "base/globals.h"
 #include "base/locks.h"
 #include "base/macros.h"
 #include "base/os.h"
 #include "base/safe_map.h"
 #include "instrumentation.h"
+#include "runtime_globals.h"
 
 namespace unix_file {
 class FdFile;
diff --git a/runtime/utils/dex_cache_arrays_layout-inl.h b/runtime/utils/dex_cache_arrays_layout-inl.h
index c0ea6be..3512efe 100644
--- a/runtime/utils/dex_cache_arrays_layout-inl.h
+++ b/runtime/utils/dex_cache_arrays_layout-inl.h
@@ -22,10 +22,10 @@
 #include <android-base/logging.h>
 
 #include "base/bit_utils.h"
-#include "base/globals.h"
 #include "dex/primitive.h"
 #include "gc_root.h"
 #include "mirror/dex_cache.h"
+#include "runtime_globals.h"
 
 namespace art {
 
diff --git a/runtime/verifier/method_verifier.cc b/runtime/verifier/method_verifier.cc
index 1679821..91eba21 100644
--- a/runtime/verifier/method_verifier.cc
+++ b/runtime/verifier/method_verifier.cc
@@ -2654,6 +2654,7 @@
             // See if instance-of was preceded by a move-object operation, common due to the small
             // register encoding space of instance-of, and propagate type information to the source
             // of the move-object.
+            // Note: this is only valid if the move source was not clobbered.
             uint32_t move_idx = instance_of_idx - 1;
             while (0 != move_idx && !GetInstructionFlags(move_idx).IsOpcode()) {
               move_idx--;
@@ -2663,28 +2664,25 @@
                             work_insn_idx_)) {
               break;
             }
+            auto maybe_update_fn = [&instance_of_inst, update_line, this, &cast_type](
+                uint16_t move_src,
+                uint16_t move_trg)
+                REQUIRES_SHARED(Locks::mutator_lock_) {
+              if (move_trg == instance_of_inst.VRegB_22c() &&
+                  move_src != instance_of_inst.VRegA_22c()) {
+                update_line->SetRegisterType<LockOp::kKeep>(this, move_src, cast_type);
+              }
+            };
             const Instruction& move_inst = code_item_accessor_.InstructionAt(move_idx);
             switch (move_inst.Opcode()) {
               case Instruction::MOVE_OBJECT:
-                if (move_inst.VRegA_12x() == instance_of_inst.VRegB_22c()) {
-                  update_line->SetRegisterType<LockOp::kKeep>(this,
-                                                              move_inst.VRegB_12x(),
-                                                              cast_type);
-                }
+                maybe_update_fn(move_inst.VRegB_12x(), move_inst.VRegA_12x());
                 break;
               case Instruction::MOVE_OBJECT_FROM16:
-                if (move_inst.VRegA_22x() == instance_of_inst.VRegB_22c()) {
-                  update_line->SetRegisterType<LockOp::kKeep>(this,
-                                                              move_inst.VRegB_22x(),
-                                                              cast_type);
-                }
+                maybe_update_fn(move_inst.VRegB_22x(), move_inst.VRegA_22x());
                 break;
               case Instruction::MOVE_OBJECT_16:
-                if (move_inst.VRegA_32x() == instance_of_inst.VRegB_22c()) {
-                  update_line->SetRegisterType<LockOp::kKeep>(this,
-                                                              move_inst.VRegB_32x(),
-                                                              cast_type);
-                }
+                maybe_update_fn(move_inst.VRegB_32x(), move_inst.VRegA_32x());
                 break;
               default:
                 break;
diff --git a/runtime/verify_object.cc b/runtime/verify_object.cc
index 70ca13f..2b8c7da 100644
--- a/runtime/verify_object.cc
+++ b/runtime/verify_object.cc
@@ -17,11 +17,11 @@
 #include "verify_object-inl.h"
 
 #include "base/bit_utils.h"
-#include "base/globals.h"
 #include "gc/heap.h"
 #include "mirror/object-inl.h"
 #include "obj_ptr-inl.h"
 #include "runtime.h"
+#include "runtime_globals.h"
 
 namespace art {
 
diff --git a/test/1001-app-image-regions/app_image_regions.cc b/test/1001-app-image-regions/app_image_regions.cc
new file mode 100644
index 0000000..dc16a84
--- /dev/null
+++ b/test/1001-app-image-regions/app_image_regions.cc
@@ -0,0 +1,53 @@
+/*
+ * Copyright 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "jni.h"
+
+#include "gc/heap.h"
+#include "gc/space/image_space.h"
+#include "gc/space/space-inl.h"
+#include "gc/space/region_space.h"
+#include "image.h"
+#include "mirror/class.h"
+#include "runtime.h"
+#include "scoped_thread_state_change-inl.h"
+
+namespace art {
+
+namespace {
+
+extern "C" JNIEXPORT jint JNICALL Java_Main_getRegionSize(JNIEnv*, jclass) {
+  return gc::space::RegionSpace::kRegionSize;
+}
+
+extern "C" JNIEXPORT jint JNICALL Java_Main_checkAppImageSectionSize(JNIEnv*, jclass, jclass c) {
+  ScopedObjectAccess soa(Thread::Current());
+  ObjPtr<mirror::Class> klass_ptr = soa.Decode<mirror::Class>(c);
+  for (auto* space : Runtime::Current()->GetHeap()->GetContinuousSpaces()) {
+    if (space->IsImageSpace()) {
+      auto* image_space = space->AsImageSpace();
+      const auto& image_header = image_space->GetImageHeader();
+      if (image_header.IsAppImage() && image_space->HasAddress(klass_ptr.Ptr())) {
+        return image_header.GetObjectsSection().Size();
+      }
+    }
+  }
+  return 0;
+}
+
+}  // namespace
+
+}  // namespace art
diff --git a/test/1001-app-image-regions/build b/test/1001-app-image-regions/build
new file mode 100755
index 0000000..16c3a5b
--- /dev/null
+++ b/test/1001-app-image-regions/build
@@ -0,0 +1,34 @@
+#!/bin/bash
+#
+# Copyright 2019 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.
+
+# make us exit on a failure
+set -e
+
+count=10000
+echo "LMain;" >> profile
+for i in $(seq 1 "$count"); do
+  echo "LOther\$Inner${i};" >> "profile"
+done
+
+# Generate the other class.
+other_file="src/Other.java"
+echo "class Other {" >> "${other_file}"
+for i in $(seq 1 "$count"); do
+  echo "  static class Inner${i} { void test(){} }" >> "${other_file}"
+done
+echo "}" >> "${other_file}"
+
+./default-build "$@"
diff --git a/test/1001-app-image-regions/expected.txt b/test/1001-app-image-regions/expected.txt
new file mode 100644
index 0000000..9fd87ca
--- /dev/null
+++ b/test/1001-app-image-regions/expected.txt
@@ -0,0 +1,4 @@
+JNI_OnLoad called
+App image loaded true
+Region size 262144
+App image section size large enough true
diff --git a/test/1001-app-image-regions/info.txt b/test/1001-app-image-regions/info.txt
new file mode 100644
index 0000000..b13f276
--- /dev/null
+++ b/test/1001-app-image-regions/info.txt
@@ -0,0 +1 @@
+Tests that an app image with many classes is generated and loaded correctly.
diff --git a/test/1001-app-image-regions/run b/test/1001-app-image-regions/run
new file mode 100644
index 0000000..128aa2e
--- /dev/null
+++ b/test/1001-app-image-regions/run
@@ -0,0 +1,17 @@
+#!/bin/bash
+#
+# Copyright (C) 2019 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.
+
+exec ${RUN} $@ --profile -Xcompiler-option --compiler-filter=speed-profile
diff --git a/test/1001-app-image-regions/src/Main.java b/test/1001-app-image-regions/src/Main.java
new file mode 100644
index 0000000..c41a606
--- /dev/null
+++ b/test/1001-app-image-regions/src/Main.java
@@ -0,0 +1,37 @@
+/*
+ * Copyright 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+import java.lang.reflect.Field;
+import java.lang.reflect.Constructor;
+import java.lang.reflect.Method;
+
+class Main {
+  public static void main(String[] args) {
+    System.loadLibrary(args[0]);
+    System.out.println("App image loaded " + checkAppImageLoaded());
+    int regionSize = getRegionSize();
+    int objectsSectionSize = checkAppImageSectionSize(Main.class);
+    System.out.println("Region size " + regionSize);
+    System.out.println("App image section size large enough " + (objectsSectionSize > regionSize));
+    if (objectsSectionSize <= regionSize) {
+      System.out.println("Section size " + objectsSectionSize);
+    }
+  }
+
+  public static native boolean checkAppImageLoaded();
+  public static native int getRegionSize();
+  public static native int checkAppImageSectionSize(Class c);
+}
diff --git a/test/689-multi-catch/expected.txt b/test/689-multi-catch/expected.txt
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/test/689-multi-catch/expected.txt
diff --git a/test/689-multi-catch/info.txt b/test/689-multi-catch/info.txt
new file mode 100644
index 0000000..0778ea8
--- /dev/null
+++ b/test/689-multi-catch/info.txt
@@ -0,0 +1,2 @@
+Regression test for the optimizing compiler which used
+to wrongly type an exception in a multi-catch handler.
diff --git a/test/689-multi-catch/src/Main.java b/test/689-multi-catch/src/Main.java
new file mode 100644
index 0000000..18a17f9
--- /dev/null
+++ b/test/689-multi-catch/src/Main.java
@@ -0,0 +1,32 @@
+/*
+ * Copyright (C) 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+public class Main {
+  public static void main(String[] args) {
+    try {
+      willThrow();
+    } catch (IllegalStateException | NullPointerException e) {
+      if (e instanceof NullPointerException) {
+        return;
+      }
+      throw new Error("Expected NullPointerException");
+    }
+  }
+
+  public static void willThrow() {
+    throw new NullPointerException();
+  }
+}
diff --git a/test/689-zygote-jit-deopt/expected.txt b/test/689-zygote-jit-deopt/expected.txt
new file mode 100644
index 0000000..6a5618e
--- /dev/null
+++ b/test/689-zygote-jit-deopt/expected.txt
@@ -0,0 +1 @@
+JNI_OnLoad called
diff --git a/test/689-zygote-jit-deopt/info.txt b/test/689-zygote-jit-deopt/info.txt
new file mode 100644
index 0000000..100032e
--- /dev/null
+++ b/test/689-zygote-jit-deopt/info.txt
@@ -0,0 +1,2 @@
+Regression test for debuggable apps that need to deoptimize
+methods JIT-compiled by the zygote.
diff --git a/test/689-zygote-jit-deopt/src/Main.java b/test/689-zygote-jit-deopt/src/Main.java
new file mode 100644
index 0000000..330663e
--- /dev/null
+++ b/test/689-zygote-jit-deopt/src/Main.java
@@ -0,0 +1,36 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+public class Main {
+  public static void main(String[] args) {
+    System.loadLibrary(args[0]);
+    if (!hasJit()) {
+      return;
+    }
+    ensureJitCompiled(Object.class, "toString");
+    transitionJitFromZygote();
+    deoptimizeBootImage();
+    if (hasJitCompiledEntrypoint(Object.class, "toString")) {
+      throw new Error("Expected Object.toString to be deoptimized");
+    }
+  }
+
+  private static native boolean hasJit();
+  private static native void ensureJitCompiled(Class<?> cls, String name);
+  private static native boolean hasJitCompiledEntrypoint(Class<?> cls, String name);
+  private static native void deoptimizeBootImage();
+  private static native void transitionJitFromZygote();
+}
diff --git a/test/800-smali/expected.txt b/test/800-smali/expected.txt
index f3c3f03..291de72 100644
--- a/test/800-smali/expected.txt
+++ b/test/800-smali/expected.txt
@@ -73,4 +73,5 @@
 b/30458218
 b/31313170
 ConstClassAliasing
+b/121191566
 Done!
diff --git a/test/800-smali/smali/b_121191566.smali b/test/800-smali/smali/b_121191566.smali
new file mode 100644
index 0000000..bcf9ef5
--- /dev/null
+++ b/test/800-smali/smali/b_121191566.smali
@@ -0,0 +1,26 @@
+.class public LB121191566;
+.super Ljava/lang/Object;
+
+
+.method public constructor <init>()V
+.registers 1
+       invoke-direct {p0}, Ljava/lang/Object;-><init>()V
+       return-void
+.end method
+
+.method public static run(Ljava/lang/Object;)Z
+.registers 5
+       move-object v3, v4
+       instance-of v4, v3, Ljava/lang/String;
+       if-eqz v4, :Branch
+       # The peephole must not overwrite v4 (from the move-object). Use an integral move
+       # to check.
+       move v0, v4
+       goto :End
+:Branch
+       # See above.
+       move v0, v4
+:End
+       # Triple-check: the merge should be consistent.
+       return v0
+.end method
diff --git a/test/800-smali/src/Main.java b/test/800-smali/src/Main.java
index 9b06e9e..d7979e1 100644
--- a/test/800-smali/src/Main.java
+++ b/test/800-smali/src/Main.java
@@ -193,6 +193,8 @@
         testCases.add(new TestCase("b/31313170", "B31313170", "run", null, null, 0));
         testCases.add(new TestCase("ConstClassAliasing", "ConstClassAliasing", "run", null, null,
                 null, true));
+        testCases.add(new TestCase("b/121191566", "B121191566", "run", new Object[] { "a" }, null,
+                true, false));
     }
 
     public void runTests() {
diff --git a/test/Android.bp b/test/Android.bp
index 57fcd86..467a717 100644
--- a/test/Android.bp
+++ b/test/Android.bp
@@ -495,6 +495,7 @@
         "708-jit-cache-churn/jit.cc",
         "800-smali/jni.cc",
         "909-attach-agent/disallow_debugging.cc",
+        "1001-app-image-regions/app_image_regions.cc",
         "1947-breakpoint-redefine-deopt/check_deopt.cc",
         "common/runtime_state.cc",
         "common/stack_inspect.cc",
diff --git a/test/common/runtime_state.cc b/test/common/runtime_state.cc
index 55631a9..bbc3039 100644
--- a/test/common/runtime_state.cc
+++ b/test/common/runtime_state.cc
@@ -161,6 +161,19 @@
   return !interpreter;
 }
 
+static ArtMethod* GetMethod(ScopedObjectAccess& soa, jclass cls, const ScopedUtfChars& chars)
+    REQUIRES_SHARED(Locks::mutator_lock_) {
+  CHECK(chars.c_str() != nullptr);
+  ArtMethod* method = soa.Decode<mirror::Class>(cls)->FindDeclaredDirectMethodByName(
+        chars.c_str(), kRuntimePointerSize);
+  if (method == nullptr) {
+    method = soa.Decode<mirror::Class>(cls)->FindDeclaredVirtualMethodByName(
+        chars.c_str(), kRuntimePointerSize);
+  }
+  DCHECK(method != nullptr) << "Unable to find method called " << chars.c_str();
+  return method;
+}
+
 extern "C" JNIEXPORT jboolean JNICALL Java_Main_hasJitCompiledEntrypoint(JNIEnv* env,
                                                                          jclass,
                                                                          jclass cls,
@@ -172,9 +185,7 @@
   Thread* self = Thread::Current();
   ScopedObjectAccess soa(self);
   ScopedUtfChars chars(env, method_name);
-  CHECK(chars.c_str() != nullptr);
-  ArtMethod* method = soa.Decode<mirror::Class>(cls)->FindDeclaredDirectMethodByName(
-        chars.c_str(), kRuntimePointerSize);
+  ArtMethod* method = GetMethod(soa, cls, chars);
   ScopedAssertNoThreadSuspension sants(__FUNCTION__);
   return jit->GetCodeCache()->ContainsPc(
       Runtime::Current()->GetInstrumentation()->GetCodeForInvoke(method));
@@ -191,9 +202,7 @@
   Thread* self = Thread::Current();
   ScopedObjectAccess soa(self);
   ScopedUtfChars chars(env, method_name);
-  CHECK(chars.c_str() != nullptr);
-  ArtMethod* method = soa.Decode<mirror::Class>(cls)->FindDeclaredDirectMethodByName(
-        chars.c_str(), kRuntimePointerSize);
+  ArtMethod* method = GetMethod(soa, cls, chars);
   return jit->GetCodeCache()->ContainsMethod(method);
 }
 
@@ -262,14 +271,7 @@
     ScopedObjectAccess soa(self);
 
     ScopedUtfChars chars(env, method_name);
-    CHECK(chars.c_str() != nullptr);
-    method = soa.Decode<mirror::Class>(cls)->FindDeclaredDirectMethodByName(
-        chars.c_str(), kRuntimePointerSize);
-    if (method == nullptr) {
-      method = soa.Decode<mirror::Class>(cls)->FindDeclaredVirtualMethodByName(
-          chars.c_str(), kRuntimePointerSize);
-    }
-    DCHECK(method != nullptr) << "Unable to find method called " << chars.c_str();
+    method = GetMethod(soa, cls, chars);
   }
   ForceJitCompiled(self, method);
 }
@@ -353,4 +355,20 @@
   return (jit != nullptr) ? jit->HotMethodThreshold() : 0;
 }
 
+extern "C" JNIEXPORT void JNICALL Java_Main_transitionJitFromZygote(JNIEnv*, jclass) {
+  jit::Jit* jit = Runtime::Current()->GetJit();
+  if (jit == nullptr) {
+    return;
+  }
+  // Mimic the transition behavior a zygote fork would have.
+  jit->PreZygoteFork();
+  jit->GetCodeCache()->PostForkChildAction(/*is_system_server=*/ false, /*is_zygote=*/ false);
+  jit->PostForkChildAction(/*is_zygote=*/ false);
+}
+
+extern "C" JNIEXPORT void JNICALL Java_Main_deoptimizeBootImage(JNIEnv*, jclass) {
+  ScopedSuspendAll ssa(__FUNCTION__);
+  Runtime::Current()->DeoptimizeBootImage();
+}
+
 }  // namespace art
diff --git a/test/common/stack_inspect.cc b/test/common/stack_inspect.cc
index 393e773..cb011a8 100644
--- a/test/common/stack_inspect.cc
+++ b/test/common/stack_inspect.cc
@@ -18,6 +18,7 @@
 
 #include <android-base/logging.h>
 
+#include "arch/context.h"
 #include "base/mutex.h"
 #include "dex/dex_file-inl.h"
 #include "jni/jni_internal.h"
diff --git a/test/etc/run-test-jar b/test/etc/run-test-jar
index 25b8b4b..3074763 100755
--- a/test/etc/run-test-jar
+++ b/test/etc/run-test-jar
@@ -319,6 +319,10 @@
         shift
         ANDROID_ROOT="$1"
         shift
+    elif [ "x$1" = "x--android-runtime-root" ]; then
+        shift
+        ANDROID_RUNTIME_ROOT="$1"
+        shift
     elif [ "x$1" = "x--instruction-set-features" ]; then
         shift
         INSTRUCTION_SET_FEATURES="$1"
diff --git a/test/knownfailures.json b/test/knownfailures.json
index 983c16a..9c01ba9 100644
--- a/test/knownfailures.json
+++ b/test/knownfailures.json
@@ -81,11 +81,13 @@
         "variant": "no-prebuild"
     },
     {
-        "tests": ["118-noimage-dex2oat"],
+        "tests": ["118-noimage-dex2oat",
+                  "1001-app-image-regions"],
         "variant": "no-relocate",
         "description": ["118-noimage-dex2oat is not broken per-se it just ",
                         "doesn't work (and isn't meant to) without --prebuild ",
-                        "--relocate"]
+                        "--relocate. 1001-app-image-regions is disabled since it",
+                        "doesn't have the app image loaded for no-relocate"]
     },
     {
         "tests" : "629-vdex-speed",
@@ -1085,6 +1087,7 @@
                   "688-shared-library",
                   "999-redefine-hiddenapi",
                   "1000-non-moving-space-stress",
+                  "1001-app-image-regions",
                   "1951-monitor-enter-no-suspend",
                   "1957-error-ext"],
         "variant": "jvm",
diff --git a/test/run-test b/test/run-test
index 83c726e..67bcce7 100755
--- a/test/run-test
+++ b/test/run-test
@@ -386,6 +386,15 @@
         android_root="$1"
         run_args="${run_args} --android-root $1"
         shift
+    elif [ "x$1" = "x--android-runtime-root" ]; then
+        shift
+        if [ "x$1" = "x" ]; then
+            echo "$0 missing argument to --android-runtime-root" 1>&2
+            usage="yes"
+            break
+        fi
+        run_args="${run_args} --android-runtime-root $1"
+        shift
     elif [ "x$1" = "x--update" ]; then
         update_mode="yes"
         shift
@@ -758,6 +767,9 @@
         echo "    --never-clean         Keep the test files even if the test succeeds."
         echo "    --chroot [newroot]    Run with root directory set to newroot."
         echo "    --android-root [path] The path on target for the android root. (/system by default)."
+        echo "    --android-runtime-root [path]"
+        echo "                          The path on target for the Android Runtime root."
+        echo "                          (/apex/com.android.runtime by default)."
         echo "    --dex2oat-swap        Use a dex2oat swap file."
         echo "    --instruction-set-features [string]"
         echo "                          Set instruction-set-features for compilation."
diff --git a/test/testrunner/env.py b/test/testrunner/env.py
index 1f4b829..c2d5e7d 100644
--- a/test/testrunner/env.py
+++ b/test/testrunner/env.py
@@ -89,8 +89,8 @@
   HOST_2ND_ARCH_PREFIX + 'DEX2OAT_HOST_INSTRUCTION_SET_FEATURES')
 
 ART_TEST_CHROOT = _env.get('ART_TEST_CHROOT')
-
 ART_TEST_ANDROID_ROOT = _env.get('ART_TEST_ANDROID_ROOT')
+ART_TEST_ANDROID_RUNTIME_ROOT = _env.get('ART_TEST_ANDROID_RUNTIME_ROOT')
 
 ART_TEST_WITH_STRACE = _getEnvBoolean('ART_TEST_DEBUG_GC', False)
 
diff --git a/test/testrunner/testrunner.py b/test/testrunner/testrunner.py
index 4e873c1..0456fdb 100755
--- a/test/testrunner/testrunner.py
+++ b/test/testrunner/testrunner.py
@@ -400,12 +400,15 @@
       elif target == 'jvm':
         options_test += ' --jvm'
 
-      # Honor ART_TEST_CHROOT and ART_TEST_ANDROID_ROOT, but only for target tests.
+      # Honor ART_TEST_CHROOT, ART_TEST_ANDROID_ROOT and ART_TEST_ANDROID_RUNTIME_ROOT,
+      # but only for target tests.
       if target == 'target':
         if env.ART_TEST_CHROOT:
           options_test += ' --chroot ' + env.ART_TEST_CHROOT
         if env.ART_TEST_ANDROID_ROOT:
           options_test += ' --android-root ' + env.ART_TEST_ANDROID_ROOT
+        if env.ART_TEST_ANDROID_RUNTIME_ROOT:
+          options_test += ' --android-runtime-root ' + env.ART_TEST_ANDROID_RUNTIME_ROOT
 
       if run == 'ndebug':
         options_test += ' -O'
diff --git a/tools/art b/tools/art
index 6e43863..9efc470 100644
--- a/tools/art
+++ b/tools/art
@@ -199,6 +199,7 @@
     # (see run_art function)
     verbose_run ANDROID_DATA=$ANDROID_DATA                    \
           ANDROID_ROOT=$ANDROID_ROOT                          \
+          ANDROID_RUNTIME_ROOT=$ANDROID_RUNTIME_ROOT          \
           LD_LIBRARY_PATH=$LD_LIBRARY_PATH                    \
           PATH=$ANDROID_ROOT/bin:$PATH                        \
           LD_USE_LOAD_BIAS=1                                  \
@@ -399,7 +400,36 @@
 
 PROG_DIR="$(cd "${PROG_NAME%/*}" ; pwd -P)"
 ANDROID_ROOT="$(cd $PROG_DIR/..; pwd -P)"
-ANDROID_RUNTIME_ROOT=$ANDROID_ROOT/com.android.runtime
+# This script is used on host and target (device). However, the (expected)
+# default value `ANDROID_RUNTIME_ROOT` is not the same on host and target:
+# - on host, `ANDROID_RUNTIME_ROOT` is expected to be "$ANDROID_ROOT/com.android.apex";
+# - on target, `ANDROID_RUNTIME_ROOT` is expected to be "$ANDROID_ROOT/../apex/com.android.apex".
+#
+# We use the presence/absence of the `$ANDROID_ROOT/../apex` directory to
+# determine whether we are on target or host (this is brittle, but simple).
+if [ -d "$ANDROID_ROOT/../apex" ]; then
+  # Target case.
+  #
+  # We should be setting `ANDROID_RUNTIME_ROOT` to
+  # "$ANDROID_ROOT/../apex/com.android.runtime" here. However, the Runtime APEX
+  # is not (yet) supported by the ART Buildbot setup (see b/121117762); and yet
+  # ICU code depends on `ANDROID_RUNTIME_ROOT` to find ICU .dat files.
+  #
+  # As a temporary workaround, we:
+  # - make the ART Buildbot build script (art/tools/buildbot-build.sh) also
+  #   generate the ICU .dat files in `/system/etc/icu` on device (these files
+  #   are normally only put in the Runtime APEX on device);
+  # - set `ANDROID_RUNTIME_ROOT` to `$ANDROID_ROOT` (i.e. "/system") here.
+  #
+  # TODO(b/121117762): Set `ANDROID_RUNTIME_ROOT` to
+  # "$ANDROID_ROOT/../apex/com.android.runtime" when the Runtime APEX is fully
+  # supported on the ART Buildbot and Golem.
+  ANDROID_RUNTIME_ROOT=$ANDROID_ROOT
+else
+  # Host case.
+  ANDROID_RUNTIME_ROOT="$ANDROID_ROOT/com.android.runtime"
+fi
+
 ART_BINARY_PATH=$ANDROID_ROOT/bin/$ART_BINARY
 
 if [ ! -x "$ART_BINARY_PATH" ]; then
diff --git a/tools/buildbot-build.sh b/tools/buildbot-build.sh
index da463d5..d4888f9 100755
--- a/tools/buildbot-build.sh
+++ b/tools/buildbot-build.sh
@@ -73,7 +73,7 @@
     exit 1
   fi
   make_command="make $j_arg $extra_args $showcommands build-art-target-tests $common_targets"
-  make_command+=" libjavacrypto-target libnetd_client-target linker toybox toolbox sh"
+  make_command+=" libjavacrypto-target libnetd_client-target linker toybox toolbox sh unzip"
   make_command+=" debuggerd su"
   make_command+=" libstdc++ "
   make_command+=" ${ANDROID_PRODUCT_OUT#"${ANDROID_BUILD_TOP}/"}/system/etc/public.libraries.txt"
@@ -81,8 +81,17 @@
     # These targets are needed for the chroot environment.
     make_command+=" crash_dump event-log-tags"
   fi
-  # Build the Runtime APEX.
-  make_command+=" com.android.runtime"
+  # Build the Debug Runtime APEX (which is a superset of the Release Runtime APEX).
+  make_command+=" com.android.runtime.debug"
+  # Create a copy of the ICU .dat prebuilt files in /system/etc/icu on target,
+  # so that it can found even if the Runtime APEX is not available, by setting
+  # the environment variable `ART_TEST_ANDROID_RUNTIME_ROOT` to "/system" on
+  # device. This is a temporary change needed until both the ART Buildbot and
+  # Golem fully support the Runtime APEX.
+  #
+  # TODO(b/121117762): Remove this when the ART Buildbot and Golem have full
+  # support for the Runtime APEX.
+  make_command+=" icu-data-art-test"
   mode_suffix="-target"
 fi
 
diff --git a/tools/cpp-define-generator/globals.def b/tools/cpp-define-generator/globals.def
index 6443a0c..1054262 100644
--- a/tools/cpp-define-generator/globals.def
+++ b/tools/cpp-define-generator/globals.def
@@ -26,6 +26,7 @@
 #include "jit/jit.h"
 #include "mirror/object.h"
 #include "mirror/object_reference.h"
+#include "runtime_globals.h"
 #include "stack.h"
 #endif
 
diff --git a/tools/libcore_failures.txt b/tools/libcore_failures.txt
index 3c65b01..a2777e8 100644
--- a/tools/libcore_failures.txt
+++ b/tools/libcore_failures.txt
@@ -223,5 +223,17 @@
     "libcore.libcore.net.InetAddressUtilsTest#test_parseNonNumericAddress[8]",
     "libcore.libcore.net.InetAddressUtilsTest#test_parseNonNumericAddress[9]"
   ]
+},
+{
+  description: "Apex related",
+  result: EXEC_FAILED,
+  modes: [device_testdex],
+  bug: 122642227,
+  names: [
+    "libcore.java.lang.SystemTest#testSystemProperties_mutable",
+    "libcore.libcore.icu.TimeZoneIntegrationTest#testTimeZoneDataVersion",
+    "libcore.libcore.icu.TimeZoneIntegrationTest#testTimeZoneDebugInfo",
+    "libcore.libcore.icu.TimeZoneIntegrationTest#testTzDataSetVersions"
+  ]
 }
 ]
diff --git a/tools/mount-buildbot-apexes.sh b/tools/mount-buildbot-apexes.sh
new file mode 100755
index 0000000..778d634
--- /dev/null
+++ b/tools/mount-buildbot-apexes.sh
@@ -0,0 +1,79 @@
+#!/bin/bash
+#
+# Copyright (C) 2019 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.
+
+# Mount Android Runtime and Core Libraries APEX packages required in the chroot directory.
+# This script emulates some the actions performed by `apexd`.
+
+green='\033[0;32m'
+nc='\033[0m'
+
+# Setup as root, as some actions performed here require it.
+adb root
+adb wait-for-device
+
+# Exit early if there is no chroot.
+[[ -n "$ART_TEST_CHROOT" ]] || exit
+
+# Check that ART_TEST_CHROOT is correctly defined.
+[[ "$ART_TEST_CHROOT" = /* ]] || { echo "$ART_TEST_CHROOT is not an absolute path"; exit 1; }
+
+# Check that the "$ART_TEST_CHROOT/apex" directory exists.
+adb shell test -d "$ART_TEST_CHROOT/apex" \
+  || { echo "$ART_TEST_CHROOT/apex does not exist or is not a directory"; exit 1; }
+
+# Create a directory where we extract APEX packages' payloads (ext4 images)
+# under the chroot directory.
+apex_image_dir="/tmp/apex"
+adb shell mkdir -p "$ART_TEST_CHROOT$apex_image_dir"
+
+# activate_system_package APEX_PACKAGE APEX_NAME
+# ----------------------------------------------
+# Extract payload (ext4 image) from system APEX_PACKAGE and mount it as
+# APEX_NAME in `/apex` under the chroot directory.
+activate_system_package() {
+  local apex_package=$1
+  local apex_name=$2
+  local apex_package_path="/system/apex/$apex_package"
+  local abs_mount_point="$ART_TEST_CHROOT/apex/$apex_name"
+  local abs_image_filename="$ART_TEST_CHROOT$apex_image_dir/$apex_name.img"
+
+  # Make sure that the (absolute) path to the mounted ext4 image is less than
+  # 64 characters, which is a hard limit set in the kernel for loop device
+  # filenames (otherwise, we would get an error message from `losetup`, used
+  # by `mount` to manage the loop device).
+  [[ "${#abs_image_filename}" -ge 64 ]] \
+    && { echo "Filename $abs_image_filename is too long to be used with a loop device"; exit 1; }
+
+  echo -e "${green}Activating package $apex_package as $apex_name${nc}"
+
+  # Extract payload (ext4 image). As standard Android builds do not contain
+  # `unzip`, we use the one we built and sync'd to the chroot directory instead.
+  local payload_filename="apex_payload.img"
+  adb shell chroot "$ART_TEST_CHROOT" \
+    /system/bin/unzip -q "$apex_package_path" "$payload_filename" -d "$apex_image_dir"
+  # Rename the extracted payload to have its name match the APEX's name.
+  adb shell mv "$ART_TEST_CHROOT$apex_image_dir/$payload_filename" "$abs_image_filename"
+  # Check that the mount point is available.
+  adb shell mount | grep -q " on $abs_mount_point" && \
+    { echo "$abs_mount_point is already used as mount point"; exit 1; }
+  # Mount the ext4 image.
+  adb shell mkdir -p "$abs_mount_point"
+  adb shell mount -o loop,ro "$abs_image_filename" "$abs_mount_point"
+}
+
+# Activate the Android Runtime APEX.
+# Note: We use the Debug Runtime APEX (which is a superset of the Release Runtime APEX).
+activate_system_package com.android.runtime.debug.apex com.android.runtime
diff --git a/tools/setup-buildbot-device.sh b/tools/setup-buildbot-device.sh
index ef958d6..92b3672 100755
--- a/tools/setup-buildbot-device.sh
+++ b/tools/setup-buildbot-device.sh
@@ -165,4 +165,9 @@
   adb shell mkdir -p "$ART_TEST_CHROOT/dev"
   adb shell mount | grep -q "^tmpfs on $ART_TEST_CHROOT/dev type tmpfs " \
     || adb shell mount -o bind /dev "$ART_TEST_CHROOT/dev"
+
+  # Create /apex tmpfs in chroot.
+  adb shell mkdir -p "$ART_TEST_CHROOT/apex"
+  adb shell mount | grep -q "^tmpfs on $ART_TEST_CHROOT/apex type tmpfs " \
+    || adb shell mount -t tmpfs -o nodev,noexec,nosuid tmpfs "$ART_TEST_CHROOT/apex"
 fi
diff --git a/tools/teardown-buildbot-device.sh b/tools/teardown-buildbot-device.sh
index 6634fb4..7eb5cc3 100755
--- a/tools/teardown-buildbot-device.sh
+++ b/tools/teardown-buildbot-device.sh
@@ -89,6 +89,9 @@
            fi
     }
 
+    # Remove /apex from chroot.
+    remove_filesystem_from_chroot apex tmpfs true
+
     # Remove /dev from chroot.
     remove_filesystem_from_chroot dev tmpfs true
 
diff --git a/tools/unmount-buildbot-apexes.sh b/tools/unmount-buildbot-apexes.sh
new file mode 100755
index 0000000..8f0ad5f
--- /dev/null
+++ b/tools/unmount-buildbot-apexes.sh
@@ -0,0 +1,64 @@
+#!/bin/bash
+#
+# Copyright (C) 2019 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.
+
+# Unmount Android Runtime and Core Libraries APEX packages required in the chroot directory.
+# This script emulates some the actions performed by `apexd`.
+
+# This script undoes the work done by tools/mount-buildbot-apexes.sh.
+# Make sure to keep these files in sync.
+
+green='\033[0;32m'
+nc='\033[0m'
+
+# Setup as root, as some actions performed here require it.
+adb root
+adb wait-for-device
+
+# Exit early if there is no chroot.
+[[ -n "$ART_TEST_CHROOT" ]] || exit
+
+# Check that ART_TEST_CHROOT is correctly defined.
+[[ "$ART_TEST_CHROOT" = /* ]] || { echo "$ART_TEST_CHROOT is not an absolute path"; exit 1; }
+
+# Directory containing extracted APEX packages' payloads (ext4 images) under
+# the chroot directory.
+apex_image_dir="/tmp/apex"
+
+# deactivate_system_package APEX_NAME
+# -----------------------------------
+# Unmount APEX_NAME in `/apex` under the chroot directory and delete the
+# corresponding APEX package payload (ext4 image).
+deactivate_system_package() {
+  local apex_name=$1
+  local abs_image_filename="$ART_TEST_CHROOT$apex_image_dir/$apex_name.img"
+  local abs_mount_point="$ART_TEST_CHROOT/apex/$apex_name"
+
+  echo -e "${green}Deactivating package $apex_name${nc}"
+
+  # Unmount the package's payload (ext4 image).
+  if adb shell mount | grep -q "^/dev/block/loop[0-9]\+ on $abs_mount_point type ext4"; then
+    adb shell umount "$abs_mount_point"
+    adb shell rmdir "$abs_mount_point"
+    # Delete the ext4 image.
+    adb shell rm "$abs_image_filename"
+  fi
+}
+
+# Deactivate the Android Runtime APEX.
+deactivate_system_package com.android.runtime
+
+# Delete the image's directory.
+adb shell rmdir "$ART_TEST_CHROOT$apex_image_dir"