Merge "test: Remove icu cleanup hack"
diff --git a/Android.bp b/Android.bp
index 77b9ac3..b9f1db5 100644
--- a/Android.bp
+++ b/Android.bp
@@ -20,15 +20,21 @@
 subdirs = [
     "benchmark",
     "build",
+    "cmdline",
     "compiler",
     "dalvikvm",
+    "dex2oat",
     "dexdump",
     "dexlayout",
     "dexlist",
     "disassembler",
+    "imgdiag",
     "oatdump",
+    "patchoat",
+    "profman",
     "runtime",
     "sigchainlib",
+    "test",
     "tools/cpp-define-generator",
     "tools/dmtracedump",
 ]
diff --git a/Android.mk b/Android.mk
index 0ed5d87..d43118c 100644
--- a/Android.mk
+++ b/Android.mk
@@ -76,10 +76,7 @@
 ########################################################################
 # product rules
 
-include $(art_path)/dex2oat/Android.mk
-include $(art_path)/imgdiag/Android.mk
-include $(art_path)/patchoat/Android.mk
-include $(art_path)/profman/Android.mk
+include $(art_path)/oatdump/Android.mk
 include $(art_path)/tools/Android.mk
 include $(art_path)/tools/ahat/Android.mk
 include $(art_path)/tools/dexfuzz/Android.mk
diff --git a/build/Android.bp b/build/Android.bp
index 630cf3c..4be43ec 100644
--- a/build/Android.bp
+++ b/build/Android.bp
@@ -140,7 +140,6 @@
     },
 
     include_dirs: [
-        "external/gtest/include",
         "external/icu/icu4c/source/common",
         "external/lz4/lib",
         "external/valgrind/include",
diff --git a/build/Android.common_build.mk b/build/Android.common_build.mk
index 04a0344..7edc1cc 100644
--- a/build/Android.common_build.mk
+++ b/build/Android.common_build.mk
@@ -87,7 +87,6 @@
 ART_CPP_EXTENSION := .cc
 
 ART_C_INCLUDES := \
-  external/gtest/include \
   external/icu/icu4c/source/common \
   external/lz4/lib \
   external/valgrind/include \
@@ -244,6 +243,11 @@
   art_cflags += -DART_BUILD_HOST_STATIC=1
 endif
 
+# Temporary flag allowing to disable recent changes in oat file management.
+ifneq ($(ART_ENABLE_VDEX),false)
+  art_cflags += -DART_ENABLE_VDEX
+endif
+
 # Cflags for non-debug ART and ART tools.
 art_non_debug_cflags := \
   $(ART_NDEBUG_OPT_FLAG)
diff --git a/build/Android.common_path.mk b/build/Android.common_path.mk
index e88d027..00d29b9 100644
--- a/build/Android.common_path.mk
+++ b/build/Android.common_path.mk
@@ -114,29 +114,33 @@
 ART_TARGET_SHARED_LIBRARY_DEPENDENCIES += $(foreach lib,$(ART_CORE_SHARED_LIBRARIES), $(2ND_TARGET_OUT_SHARED_LIBRARIES)/$(lib).so)
 endif
 
-ART_CORE_EXECUTABLES := \
+ART_CORE_DEBUGGABLE_EXECUTABLES := \
     dex2oat \
     imgdiag \
     oatdump \
     patchoat \
     profman \
 
+ART_CORE_EXECUTABLES := \
+    dalvikvm \
+    dexlist \
+
 # Depend on the -target or -host phony targets generated by the build system
 # for each module
-ART_TARGET_EXECUTABLES := dalvikvm-target
+ART_TARGET_EXECUTABLES :=
 ifneq ($(ART_BUILD_TARGET_NDEBUG),false)
-ART_TARGET_EXECUTABLES += $(foreach name,$(ART_CORE_EXECUTABLES),$(name)-target)
+ART_TARGET_EXECUTABLES += $(foreach name,$(ART_CORE_EXECUTABLES) $(ART_CORE_DEBUGGABLE_EXECUTABLES),$(name)-target)
 endif
 ifneq ($(ART_BUILD_TARGET_DEBUG),false)
-ART_TARGET_EXECUTABLES += $(foreach name,$(ART_CORE_EXECUTABLES),$(name)d-target)
+ART_TARGET_EXECUTABLES += $(foreach name,$(ART_CORE_DEBUGGABLE_EXECUTABLES),$(name)d-target)
 endif
 
-ART_HOST_EXECUTABLES := dalvikvm-host
+ART_HOST_EXECUTABLES :=
 ifneq ($(ART_BUILD_HOST_NDEBUG),false)
-ART_HOST_EXECUTABLES += $(foreach name,$(ART_CORE_EXECUTABLES),$(name)-host)
+ART_HOST_EXECUTABLES += $(foreach name,$(ART_CORE_EXECUTABLES) $(ART_CORE_DEBUGGABLE_EXECUTABLES),$(name)-host)
 endif
 ifneq ($(ART_BUILD_HOST_DEBUG),false)
-ART_HOST_EXECUTABLES += $(foreach name,$(ART_CORE_EXECUTABLES),$(name)d-host)
+ART_HOST_EXECUTABLES += $(foreach name,$(ART_CORE_DEBUGGABLE_EXECUTABLES),$(name)d-host)
 endif
 
 endif # ART_ANDROID_COMMON_PATH_MK
diff --git a/build/Android.common_test.mk b/build/Android.common_test.mk
index 93e310e..6b7dc09 100644
--- a/build/Android.common_test.mk
+++ b/build/Android.common_test.mk
@@ -60,8 +60,8 @@
 # Do you want to test the optimizing compiler with graph coloring register allocation?
 ART_TEST_OPTIMIZING_GRAPH_COLOR ?= $(ART_TEST_FULL)
 
-# Do we want to test a PIC-compiled core image?
-ART_TEST_PIC_IMAGE ?= $(ART_TEST_FULL)
+# Do we want to test a non-PIC-compiled core image?
+ART_TEST_NPIC_IMAGE ?= $(ART_TEST_FULL)
 
 # Do we want to test PIC-compiled tests ("apps")?
 ART_TEST_PIC_TEST ?= $(ART_TEST_FULL)
diff --git a/build/Android.executable.mk b/build/Android.executable.mk
index c35833d..f38a14d 100644
--- a/build/Android.executable.mk
+++ b/build/Android.executable.mk
@@ -249,20 +249,3 @@
     )
   )
 endef
-
-# Note: the order is important because of static linking resolution.
-ART_STATIC_DEPENDENCIES := \
-  libziparchive \
-  libnativehelper \
-  libnativebridge \
-  libnativeloader \
-  libsigchain_dummy \
-  liblog \
-  libz \
-  libbacktrace \
-  libcutils \
-  libunwindbacktrace \
-  libutils \
-  libbase \
-  liblz4 \
-  liblzma
diff --git a/build/Android.gtest.mk b/build/Android.gtest.mk
index c09241a..b93c1af 100644
--- a/build/Android.gtest.mk
+++ b/build/Android.gtest.mk
@@ -37,6 +37,7 @@
   MyClassNatives \
   Nested \
   NonStaticLeafMethods \
+  Packages \
   ProtoCompare \
   ProtoCompare2 \
   ProfileTestMultiDex \
@@ -69,7 +70,7 @@
 
 ART_GTEST_class_linker_test_DEX_DEPS := Interfaces MultiDex MyClass Nested Statics StaticsFromCode
 ART_GTEST_compiler_driver_test_DEX_DEPS := AbstractMethod StaticLeafMethods ProfileTestMultiDex
-ART_GTEST_dex_cache_test_DEX_DEPS := Main
+ART_GTEST_dex_cache_test_DEX_DEPS := Main Packages
 ART_GTEST_dex_file_test_DEX_DEPS := GetMethodSignature Main Nested
 ART_GTEST_dex2oat_test_DEX_DEPS := $(ART_GTEST_dex2oat_environment_tests_DEX_DEPS) Statics
 ART_GTEST_exception_test_DEX_DEPS := ExceptionHandle
@@ -89,16 +90,16 @@
 ART_GTEST_type_lookup_table_test_DEX_DEPS := Lookup
 
 # The elf writer test has dependencies on core.oat.
-ART_GTEST_elf_writer_test_HOST_DEPS := $(HOST_CORE_IMAGE_default_no-pic_64) $(HOST_CORE_IMAGE_default_no-pic_32)
-ART_GTEST_elf_writer_test_TARGET_DEPS := $(TARGET_CORE_IMAGE_default_no-pic_64) $(TARGET_CORE_IMAGE_default_no-pic_32)
+ART_GTEST_elf_writer_test_HOST_DEPS := $(HOST_CORE_IMAGE_optimizing_no-pic_64) $(HOST_CORE_IMAGE_optimizing_no-pic_32)
+ART_GTEST_elf_writer_test_TARGET_DEPS := $(TARGET_CORE_IMAGE_optimizing_no-pic_64) $(TARGET_CORE_IMAGE_optimizing_no-pic_32)
 
 ART_GTEST_dex2oat_environment_tests_HOST_DEPS := \
-  $(HOST_CORE_IMAGE_default_no-pic_64) \
-  $(HOST_CORE_IMAGE_default_no-pic_32) \
+  $(HOST_CORE_IMAGE_optimizing_pic_64) \
+  $(HOST_CORE_IMAGE_optimizing_pic_32) \
   $(HOST_OUT_EXECUTABLES)/patchoatd
 ART_GTEST_dex2oat_environment_tests_TARGET_DEPS := \
-  $(TARGET_CORE_IMAGE_default_no-pic_64) \
-  $(TARGET_CORE_IMAGE_default_no-pic_32) \
+  $(TARGET_CORE_IMAGE_optimizing_pic_64) \
+  $(TARGET_CORE_IMAGE_optimizing_pic_32) \
   $(TARGET_OUT_EXECUTABLES)/patchoatd
 
 ART_GTEST_oat_file_assistant_test_HOST_DEPS := \
@@ -113,62 +114,62 @@
   $(ART_GTEST_dex2oat_environment_tests_TARGET_DEPS)
 
 # TODO: document why this is needed.
-ART_GTEST_proxy_test_HOST_DEPS := $(HOST_CORE_IMAGE_default_no-pic_64) $(HOST_CORE_IMAGE_default_no-pic_32)
+ART_GTEST_proxy_test_HOST_DEPS := $(HOST_CORE_IMAGE_optimizing_no-pic_64) $(HOST_CORE_IMAGE_optimizing_no-pic_32)
 
 # The dexdump test requires an image and the dexdump utility.
 # TODO: rename into dexdump when migration completes
 ART_GTEST_dexdump_test_HOST_DEPS := \
-  $(HOST_CORE_IMAGE_default_no-pic_64) \
-  $(HOST_CORE_IMAGE_default_no-pic_32) \
+  $(HOST_CORE_IMAGE_optimizing_no-pic_64) \
+  $(HOST_CORE_IMAGE_optimizing_no-pic_32) \
   $(HOST_OUT_EXECUTABLES)/dexdump2
 ART_GTEST_dexdump_test_TARGET_DEPS := \
-  $(TARGET_CORE_IMAGE_default_no-pic_64) \
-  $(TARGET_CORE_IMAGE_default_no-pic_32) \
+  $(TARGET_CORE_IMAGE_optimizing_no-pic_64) \
+  $(TARGET_CORE_IMAGE_optimizing_no-pic_32) \
   dexdump2
 
 # The dexlayout test requires an image and the dexlayout utility.
 # TODO: rename into dexdump when migration completes
 ART_GTEST_dexlayout_test_HOST_DEPS := \
-  $(HOST_CORE_IMAGE_default_no-pic_64) \
-  $(HOST_CORE_IMAGE_default_no-pic_32) \
+  $(HOST_CORE_IMAGE_optimizing_no-pic_64) \
+  $(HOST_CORE_IMAGE_optimizing_no-pic_32) \
   $(HOST_OUT_EXECUTABLES)/dexlayout \
   $(HOST_OUT_EXECUTABLES)/dexdump2
 ART_GTEST_dexlayout_test_TARGET_DEPS := \
-  $(TARGET_CORE_IMAGE_default_no-pic_64) \
-  $(TARGET_CORE_IMAGE_default_no-pic_32) \
+  $(TARGET_CORE_IMAGE_optimizing_no-pic_64) \
+  $(TARGET_CORE_IMAGE_optimizing_no-pic_32) \
   dexlayout \
   dexdump2
 
 # The dexlist test requires an image and the dexlist utility.
 ART_GTEST_dexlist_test_HOST_DEPS := \
-  $(HOST_CORE_IMAGE_default_no-pic_64) \
-  $(HOST_CORE_IMAGE_default_no-pic_32) \
+  $(HOST_CORE_IMAGE_optimizing_no-pic_64) \
+  $(HOST_CORE_IMAGE_optimizing_no-pic_32) \
   $(HOST_OUT_EXECUTABLES)/dexlist
 ART_GTEST_dexlist_test_TARGET_DEPS := \
-  $(TARGET_CORE_IMAGE_default_no-pic_64) \
-  $(TARGET_CORE_IMAGE_default_no-pic_32) \
+  $(TARGET_CORE_IMAGE_optimizing_no-pic_64) \
+  $(TARGET_CORE_IMAGE_optimizing_no-pic_32) \
   dexlist
 
 # The imgdiag test has dependencies on core.oat since it needs to load it during the test.
 # For the host, also add the installed tool (in the base size, that should suffice). For the
 # target, just the module is fine, the sync will happen late enough.
 ART_GTEST_imgdiag_test_HOST_DEPS := \
-  $(HOST_CORE_IMAGE_default_no-pic_64) \
-  $(HOST_CORE_IMAGE_default_no-pic_32) \
+  $(HOST_CORE_IMAGE_optimizing_no-pic_64) \
+  $(HOST_CORE_IMAGE_optimizing_no-pic_32) \
   $(HOST_OUT_EXECUTABLES)/imgdiagd
 ART_GTEST_imgdiag_test_TARGET_DEPS := \
-  $(TARGET_CORE_IMAGE_default_no-pic_64) \
-  $(TARGET_CORE_IMAGE_default_no-pic_32) \
+  $(TARGET_CORE_IMAGE_optimizing_no-pic_64) \
+  $(TARGET_CORE_IMAGE_optimizing_no-pic_32) \
   imgdiagd
 
 # Oatdump test requires an image and oatfile to dump.
 ART_GTEST_oatdump_test_HOST_DEPS := \
-  $(HOST_CORE_IMAGE_default_no-pic_64) \
-  $(HOST_CORE_IMAGE_default_no-pic_32) \
+  $(HOST_CORE_IMAGE_optimizing_no-pic_64) \
+  $(HOST_CORE_IMAGE_optimizing_no-pic_32) \
   $(HOST_OUT_EXECUTABLES)/oatdumpd
 ART_GTEST_oatdump_test_TARGET_DEPS := \
-  $(TARGET_CORE_IMAGE_default_no-pic_64) \
-  $(TARGET_CORE_IMAGE_default_no-pic_32) \
+  $(TARGET_CORE_IMAGE_optimizing_no-pic_64) \
+  $(TARGET_CORE_IMAGE_optimizing_no-pic_32) \
   oatdump
 
 # Profile assistant tests requires profman utility.
@@ -180,274 +181,28 @@
 # The path for which all the source files are relative, not actually the current directory.
 LOCAL_PATH := art
 
-RUNTIME_GTEST_COMMON_SRC_FILES := \
-  cmdline/cmdline_parser_test.cc \
-  dexdump/dexdump_test.cc \
-  dexlayout/dexlayout_test.cc \
-  dexlist/dexlist_test.cc \
-  dex2oat/dex2oat_test.cc \
-  imgdiag/imgdiag_test.cc \
-  oatdump/oatdump_test.cc \
-  profman/profile_assistant_test.cc \
-  runtime/arch/arch_test.cc \
-  runtime/arch/instruction_set_test.cc \
-  runtime/arch/instruction_set_features_test.cc \
-  runtime/arch/memcmp16_test.cc \
-  runtime/arch/stub_test.cc \
-  runtime/arch/arm/instruction_set_features_arm_test.cc \
-  runtime/arch/arm64/instruction_set_features_arm64_test.cc \
-  runtime/arch/mips/instruction_set_features_mips_test.cc \
-  runtime/arch/mips64/instruction_set_features_mips64_test.cc \
-  runtime/arch/x86/instruction_set_features_x86_test.cc \
-  runtime/arch/x86_64/instruction_set_features_x86_64_test.cc \
-  runtime/barrier_test.cc \
-  runtime/base/arena_allocator_test.cc \
-  runtime/base/bit_field_test.cc \
-  runtime/base/bit_utils_test.cc \
-  runtime/base/bit_vector_test.cc \
-  runtime/base/hash_set_test.cc \
-  runtime/base/hex_dump_test.cc \
-  runtime/base/histogram_test.cc \
-  runtime/base/mutex_test.cc \
-  runtime/base/scoped_flock_test.cc \
-  runtime/base/stringprintf_test.cc \
-  runtime/base/time_utils_test.cc \
-  runtime/base/timing_logger_test.cc \
-  runtime/base/variant_map_test.cc \
-  runtime/base/unix_file/fd_file_test.cc \
-  runtime/class_linker_test.cc \
-  runtime/compiler_filter_test.cc \
-  runtime/dex_file_test.cc \
-  runtime/dex_file_verifier_test.cc \
-  runtime/dex_instruction_test.cc \
-  runtime/dex_instruction_visitor_test.cc \
-  runtime/dex_method_iterator_test.cc \
-  runtime/entrypoints/math_entrypoints_test.cc \
-  runtime/entrypoints/quick/quick_trampoline_entrypoints_test.cc \
-  runtime/entrypoints_order_test.cc \
-  runtime/gc/accounting/card_table_test.cc \
-  runtime/gc/accounting/mod_union_table_test.cc \
-  runtime/gc/accounting/space_bitmap_test.cc \
-  runtime/gc/collector/immune_spaces_test.cc \
-  runtime/gc/heap_test.cc \
-  runtime/gc/reference_queue_test.cc \
-  runtime/gc/space/dlmalloc_space_static_test.cc \
-  runtime/gc/space/dlmalloc_space_random_test.cc \
-  runtime/gc/space/large_object_space_test.cc \
-  runtime/gc/space/rosalloc_space_static_test.cc \
-  runtime/gc/space/rosalloc_space_random_test.cc \
-  runtime/gc/space/space_create_test.cc \
-  runtime/gc/task_processor_test.cc \
-  runtime/gtest_test.cc \
-  runtime/handle_scope_test.cc \
-  runtime/indenter_test.cc \
-  runtime/indirect_reference_table_test.cc \
-  runtime/instrumentation_test.cc \
-  runtime/intern_table_test.cc \
-  runtime/interpreter/safe_math_test.cc \
-  runtime/interpreter/unstarted_runtime_test.cc \
-  runtime/java_vm_ext_test.cc \
-  runtime/jit/profile_compilation_info_test.cc \
-  runtime/leb128_test.cc \
-  runtime/mem_map_test.cc \
-  runtime/memory_region_test.cc \
-  runtime/mirror/dex_cache_test.cc \
-  runtime/mirror/object_test.cc \
-  runtime/monitor_pool_test.cc \
-  runtime/monitor_test.cc \
-  runtime/oat_file_test.cc \
-  runtime/oat_file_assistant_test.cc \
-  runtime/parsed_options_test.cc \
-  runtime/prebuilt_tools_test.cc \
-  runtime/reference_table_test.cc \
-  runtime/thread_pool_test.cc \
-  runtime/transaction_test.cc \
-  runtime/type_lookup_table_test.cc \
-  runtime/utf_test.cc \
-  runtime/utils_test.cc \
-  runtime/verifier/method_verifier_test.cc \
-  runtime/verifier/reg_type_test.cc \
-  runtime/zip_archive_test.cc
+ART_TEST_MODULES := \
+    art_cmdline_tests \
+    art_compiler_tests \
+    art_compiler_host_tests \
+    art_dex2oat_tests \
+    art_dexdump_tests \
+    art_dexlayout_tests \
+    art_dexlist_tests \
+    art_imgdiag_tests \
+    art_oatdump_tests \
+    art_profman_tests \
+    art_runtime_tests \
+    art_runtime_compiler_tests \
 
-COMPILER_GTEST_COMMON_SRC_FILES := \
-  runtime/jni_internal_test.cc \
-  runtime/proxy_test.cc \
-  runtime/reflection_test.cc \
-  compiler/compiled_method_test.cc \
-  compiler/debug/dwarf/dwarf_test.cc \
-  compiler/driver/compiled_method_storage_test.cc \
-  compiler/driver/compiler_driver_test.cc \
-  compiler/elf_writer_test.cc \
-  compiler/exception_test.cc \
-  compiler/image_test.cc \
-  compiler/jni/jni_compiler_test.cc \
-  compiler/linker/multi_oat_relative_patcher_test.cc \
-  compiler/linker/output_stream_test.cc \
-  compiler/oat_test.cc \
-  compiler/optimizing/bounds_check_elimination_test.cc \
-  compiler/optimizing/dominator_test.cc \
-  compiler/optimizing/find_loops_test.cc \
-  compiler/optimizing/graph_checker_test.cc \
-  compiler/optimizing/graph_test.cc \
-  compiler/optimizing/gvn_test.cc \
-  compiler/optimizing/induction_var_analysis_test.cc \
-  compiler/optimizing/induction_var_range_test.cc \
-  compiler/optimizing/licm_test.cc \
-  compiler/optimizing/live_interval_test.cc \
-  compiler/optimizing/nodes_test.cc \
-  compiler/optimizing/parallel_move_test.cc \
-  compiler/optimizing/pretty_printer_test.cc \
-  compiler/optimizing/reference_type_propagation_test.cc \
-  compiler/optimizing/side_effects_test.cc \
-  compiler/optimizing/ssa_test.cc \
-  compiler/optimizing/stack_map_test.cc \
-  compiler/optimizing/suspend_check_test.cc \
-  compiler/utils/dedupe_set_test.cc \
-  compiler/utils/intrusive_forward_list_test.cc \
-  compiler/utils/string_reference_test.cc \
-  compiler/utils/swap_space_test.cc \
-  compiler/utils/test_dex_file_builder_test.cc \
-  compiler/utils/transform_array_ref_test.cc \
-  compiler/utils/transform_iterator_test.cc \
+ART_TARGET_GTEST_FILES := $(foreach m,$(ART_TEST_MODULES),\
+    $(ART_TEST_LIST_device_$(TARGET_ARCH)_$(m)))
 
-COMPILER_GTEST_COMMON_SRC_FILES_all := \
-  compiler/jni/jni_cfi_test.cc \
-  compiler/optimizing/codegen_test.cc \
-  compiler/optimizing/optimizing_cfi_test.cc \
-
-COMPILER_GTEST_COMMON_SRC_FILES_arm := \
-  compiler/linker/arm/relative_patcher_thumb2_test.cc \
-  compiler/utils/arm/managed_register_arm_test.cc \
-
-COMPILER_GTEST_COMMON_SRC_FILES_arm64 := \
-  compiler/linker/arm64/relative_patcher_arm64_test.cc \
-  compiler/utils/arm64/managed_register_arm64_test.cc \
-
-COMPILER_GTEST_COMMON_SRC_FILES_mips := \
-  compiler/linker/mips/relative_patcher_mips_test.cc \
-  compiler/linker/mips/relative_patcher_mips32r6_test.cc \
-
-COMPILER_GTEST_COMMON_SRC_FILES_mips64 := \
-
-COMPILER_GTEST_COMMON_SRC_FILES_x86 := \
-  compiler/linker/x86/relative_patcher_x86_test.cc \
-  compiler/utils/x86/managed_register_x86_test.cc \
-
-# These tests are testing architecture-independent functionality, but happen
-# to use x86 codegen as part of the test.
-COMPILER_GTEST_COMMON_SRC_FILES_x86 += \
-  compiler/optimizing/constant_folding_test.cc \
-  compiler/optimizing/dead_code_elimination_test.cc \
-  compiler/optimizing/linearize_test.cc \
-  compiler/optimizing/live_ranges_test.cc \
-  compiler/optimizing/liveness_test.cc \
-  compiler/optimizing/register_allocator_test.cc \
-
-COMPILER_GTEST_COMMON_SRC_FILES_x86_64 := \
-  compiler/linker/x86_64/relative_patcher_x86_64_test.cc \
-
-RUNTIME_GTEST_TARGET_SRC_FILES := \
-  $(RUNTIME_GTEST_COMMON_SRC_FILES)
-
-RUNTIME_GTEST_HOST_SRC_FILES := \
-  $(RUNTIME_GTEST_COMMON_SRC_FILES)
-
-COMPILER_GTEST_TARGET_SRC_FILES := \
-  $(COMPILER_GTEST_COMMON_SRC_FILES)
-
-COMPILER_GTEST_TARGET_SRC_FILES_all := \
-  $(COMPILER_GTEST_COMMON_SRC_FILES_all) \
-
-COMPILER_GTEST_TARGET_SRC_FILES_arm := \
-  $(COMPILER_GTEST_COMMON_SRC_FILES_arm) \
-
-COMPILER_GTEST_TARGET_SRC_FILES_arm64 := \
-  $(COMPILER_GTEST_COMMON_SRC_FILES_arm64) \
-
-COMPILER_GTEST_TARGET_SRC_FILES_mips := \
-  $(COMPILER_GTEST_COMMON_SRC_FILES_mips) \
-
-COMPILER_GTEST_TARGET_SRC_FILES_mips64 := \
-  $(COMPILER_GTEST_COMMON_SRC_FILES_mips64) \
-
-COMPILER_GTEST_TARGET_SRC_FILES_x86 := \
-  $(COMPILER_GTEST_COMMON_SRC_FILES_x86) \
-
-COMPILER_GTEST_TARGET_SRC_FILES_x86_64 := \
-  $(COMPILER_GTEST_COMMON_SRC_FILES_x86_64) \
-
-$(foreach arch,$(ART_TARGET_CODEGEN_ARCHS),$(eval COMPILER_GTEST_TARGET_SRC_FILES += $$(COMPILER_GTEST_TARGET_SRC_FILES_$(arch))))
-COMPILER_GTEST_TARGET_SRC_FILES += $(COMPILER_GTEST_TARGET_SRC_FILES_all)
-
-COMPILER_GTEST_HOST_SRC_FILES := \
-  $(COMPILER_GTEST_COMMON_SRC_FILES) \
-
-COMPILER_GTEST_HOST_SRC_FILES_all := \
-  $(COMPILER_GTEST_COMMON_SRC_FILES_all) \
-
-COMPILER_GTEST_HOST_SRC_FILES_arm := \
-  $(COMPILER_GTEST_COMMON_SRC_FILES_arm) \
-  compiler/utils/arm/assembler_thumb2_test.cc \
-  compiler/utils/assembler_thumb_test.cc \
-
-COMPILER_GTEST_HOST_SRC_FILES_arm64 := \
-  $(COMPILER_GTEST_COMMON_SRC_FILES_arm64) \
-
-COMPILER_GTEST_HOST_SRC_FILES_mips := \
-  $(COMPILER_GTEST_COMMON_SRC_FILES_mips) \
-  compiler/utils/mips/assembler_mips_test.cc \
-  compiler/utils/mips/assembler_mips32r6_test.cc \
-
-COMPILER_GTEST_HOST_SRC_FILES_mips64 := \
-  $(COMPILER_GTEST_COMMON_SRC_FILES_mips64) \
-  compiler/utils/mips64/assembler_mips64_test.cc \
-
-COMPILER_GTEST_HOST_SRC_FILES_x86 := \
-  $(COMPILER_GTEST_COMMON_SRC_FILES_x86) \
-  compiler/utils/x86/assembler_x86_test.cc \
-
-COMPILER_GTEST_HOST_SRC_FILES_x86_64 := \
-  $(COMPILER_GTEST_COMMON_SRC_FILES_x86_64) \
-  compiler/utils/x86_64/assembler_x86_64_test.cc
-
-$(foreach arch,$(ART_HOST_CODEGEN_ARCHS),$(eval COMPILER_GTEST_HOST_SRC_FILES += $$(COMPILER_GTEST_HOST_SRC_FILES_$(arch))))
-COMPILER_GTEST_HOST_SRC_FILES += $(COMPILER_GTEST_HOST_SRC_FILES_all)
+ART_HOST_GTEST_FILES := $(foreach m,$(ART_TEST_MODULES),\
+    $(ART_TEST_LIST_host_$(ART_HOST_ARCH)_$(m)))
 
 ART_TEST_CFLAGS :=
 
-include $(CLEAR_VARS)
-LOCAL_MODULE := libart-gtest
-LOCAL_MODULE_TAGS := optional
-LOCAL_CPP_EXTENSION := cc
-LOCAL_SRC_FILES := runtime/common_runtime_test.cc compiler/common_compiler_test.cc
-LOCAL_C_INCLUDES := $(ART_C_INCLUDES) art/runtime art/cmdline art/compiler
-LOCAL_SHARED_LIBRARIES := libartd libartd-compiler libdl
-LOCAL_STATIC_LIBRARIES += libgtest
-LOCAL_ADDITIONAL_DEPENDENCIES := art/build/Android.common_build.mk
-LOCAL_ADDITIONAL_DEPENDENCIES += art/build/Android.gtest.mk
-$(eval LOCAL_CLANG := $(ART_TARGET_CLANG))
-$(eval $(call set-target-local-cflags-vars,debug))
-LOCAL_CFLAGS += -Wno-used-but-marked-unused -Wno-deprecated -Wno-missing-noreturn # gtest issue
-include $(BUILD_SHARED_LIBRARY)
-
-include $(CLEAR_VARS)
-LOCAL_MODULE := libart-gtest
-LOCAL_MODULE_TAGS := optional
-LOCAL_CPP_EXTENSION := cc
-LOCAL_CFLAGS := $(ART_HOST_CFLAGS)
-LOCAL_ASFLAGS := $(ART_HOST_ASFLAGS)
-LOCAL_SRC_FILES := runtime/common_runtime_test.cc compiler/common_compiler_test.cc
-LOCAL_C_INCLUDES := $(ART_C_INCLUDES) art/runtime art/cmdline art/compiler
-LOCAL_SHARED_LIBRARIES := libartd libartd-compiler
-LOCAL_STATIC_LIBRARIES := libgtest_host
-LOCAL_LDLIBS += -ldl -lpthread
-LOCAL_MULTILIB := both
-LOCAL_CLANG := $(ART_HOST_CLANG)
-LOCAL_CFLAGS += -Wno-used-but-marked-unused -Wno-deprecated -Wno-missing-noreturn  # gtest issue
-LOCAL_ADDITIONAL_DEPENDENCIES := art/build/Android.common_build.mk
-LOCAL_ADDITIONAL_DEPENDENCIES += art/build/Android.gtest.mk
-include $(BUILD_HOST_SHARED_LIBRARY)
-
 # Variables holding collections of gtest pre-requisits used to run a number of gtests.
 ART_TEST_HOST_GTEST$(ART_PHONY_TEST_HOST_SUFFIX)_RULES :=
 ART_TEST_HOST_GTEST$(2ND_ART_PHONY_TEST_HOST_SUFFIX)_RULES :=
@@ -492,63 +247,70 @@
 
 # Define a make rule for a target device gtest.
 # $(1): gtest name - the name of the test we're building such as leb128_test.
-# $(2): 2ND_ or undefined - used to differentiate between the primary and secondary architecture.
-# $(3): LD_LIBRARY_PATH or undefined - used in case libartd.so is not in /system/lib/
+# $(2): path relative to $OUT to the test binary
+# $(3): 2ND_ or undefined - used to differentiate between the primary and secondary architecture.
+# $(4): LD_LIBRARY_PATH or undefined - used in case libartd.so is not in /system/lib/
 define define-art-gtest-rule-target
-  gtest_rule := test-art-target-gtest-$(1)$$($(2)ART_PHONY_TEST_TARGET_SUFFIX)
+  gtest_rule := test-art-target-gtest-$(1)$$($(3)ART_PHONY_TEST_TARGET_SUFFIX)
+  gtest_exe := $(OUT_DIR)/$(2)
+  gtest_target_exe := $$(patsubst $(PRODUCT_OUT)/%,/%,$$(gtest_exe))
 
   # Add the test dependencies to test-art-target-sync, which will be a prerequisite for the test
   # to ensure files are pushed to the device.
   TEST_ART_TARGET_SYNC_DEPS += \
     $$(ART_GTEST_$(1)_TARGET_DEPS) \
     $(foreach file,$(ART_GTEST_$(1)_DEX_DEPS),$(ART_TEST_TARGET_GTEST_$(file)_DEX)) \
-    $$(ART_TARGET_NATIVETEST_OUT)/$$(TARGET_$(2)ARCH)/$(1) \
-    $$($(2)TARGET_OUT_SHARED_LIBRARIES)/libjavacore.so \
-    $$($(2)TARGET_OUT_SHARED_LIBRARIES)/libopenjdkd.so \
+    $$(gtest_exe) \
+    $$($(3)TARGET_OUT_SHARED_LIBRARIES)/libjavacore.so \
+    $$($(3)TARGET_OUT_SHARED_LIBRARIES)/libopenjdkd.so \
     $$(TARGET_OUT_JAVA_LIBRARIES)/core-libart-testdex.jar \
     $$(TARGET_OUT_JAVA_LIBRARIES)/core-oj-testdex.jar \
     $$(ART_TARGET_TEST_OUT)/valgrind-target-suppressions.txt
 
+$$(gtest_rule) valgrind-$$(gtest_rule): PRIVATE_TARGET_EXE := $$(gtest_target_exe)
+
 .PHONY: $$(gtest_rule)
 $$(gtest_rule): test-art-target-sync
-	$(hide) adb shell touch $(ART_TARGET_TEST_DIR)/$(TARGET_$(2)ARCH)/$$@-$$$$PPID
-	$(hide) adb shell rm $(ART_TARGET_TEST_DIR)/$(TARGET_$(2)ARCH)/$$@-$$$$PPID
-	$(hide) adb shell chmod 755 $(ART_TARGET_NATIVETEST_DIR)/$(TARGET_$(2)ARCH)/$(1)
+	$(hide) adb shell touch $(ART_TARGET_TEST_DIR)/$(TARGET_$(3)ARCH)/$$@-$$$$PPID
+	$(hide) adb shell rm $(ART_TARGET_TEST_DIR)/$(TARGET_$(3)ARCH)/$$@-$$$$PPID
+	$(hide) adb shell chmod 755 $$(PRIVATE_TARGET_EXE)
 	$(hide) $$(call ART_TEST_SKIP,$$@) && \
-	  (adb shell "$(GCOV_ENV) LD_LIBRARY_PATH=$(3) ANDROID_ROOT=$(ART_GTEST_TARGET_ANDROID_ROOT) \
-	    $(ART_TARGET_NATIVETEST_DIR)/$(TARGET_$(2)ARCH)/$(1) && touch $(ART_TARGET_TEST_DIR)/$(TARGET_$(2)ARCH)/$$@-$$$$PPID" \
-	  && (adb pull $(ART_TARGET_TEST_DIR)/$(TARGET_$(2)ARCH)/$$@-$$$$PPID /tmp/ \
+	  (adb shell "$(GCOV_ENV) LD_LIBRARY_PATH=$(4) ANDROID_ROOT=$(ART_GTEST_TARGET_ANDROID_ROOT) \
+	    $$(PRIVATE_TARGET_EXE) && touch $(ART_TARGET_TEST_DIR)/$(TARGET_$(3)ARCH)/$$@-$$$$PPID" \
+	  && (adb pull $(ART_TARGET_TEST_DIR)/$(TARGET_$(3)ARCH)/$$@-$$$$PPID /tmp/ \
 	      && $$(call ART_TEST_PASSED,$$@)) \
 	  || $$(call ART_TEST_FAILED,$$@))
 	$(hide) rm -f /tmp/$$@-$$$$PPID
 
-  ART_TEST_TARGET_GTEST$($(2)ART_PHONY_TEST_TARGET_SUFFIX)_RULES += $$(gtest_rule)
+  ART_TEST_TARGET_GTEST$($(3)ART_PHONY_TEST_TARGET_SUFFIX)_RULES += $$(gtest_rule)
   ART_TEST_TARGET_GTEST_RULES += $$(gtest_rule)
   ART_TEST_TARGET_GTEST_$(1)_RULES += $$(gtest_rule)
 
 .PHONY: valgrind-$$(gtest_rule)
 valgrind-$$(gtest_rule): $(ART_VALGRIND_TARGET_DEPENDENCIES) test-art-target-sync
-	$(hide) adb shell touch $(ART_TARGET_TEST_DIR)/$(TARGET_$(2)ARCH)/$$@-$$$$PPID
-	$(hide) adb shell rm $(ART_TARGET_TEST_DIR)/$(TARGET_$(2)ARCH)/$$@-$$$$PPID
-	$(hide) adb shell chmod 755 $(ART_TARGET_NATIVETEST_DIR)/$(TARGET_$(2)ARCH)/$(1)
+	$(hide) adb shell touch $(ART_TARGET_TEST_DIR)/$(TARGET_$(3)ARCH)/$$@-$$$$PPID
+	$(hide) adb shell rm $(ART_TARGET_TEST_DIR)/$(TARGET_$(3)ARCH)/$$@-$$$$PPID
+	$(hide) adb shell chmod 755 $$(PRIVATE_TARGET_EXE)
 	$(hide) $$(call ART_TEST_SKIP,$$@) && \
-	  (adb shell "$(GCOV_ENV) LD_LIBRARY_PATH=$(3) ANDROID_ROOT=$(ART_GTEST_TARGET_ANDROID_ROOT) \
+	  (adb shell "$(GCOV_ENV) LD_LIBRARY_PATH=$(4) ANDROID_ROOT=$(ART_GTEST_TARGET_ANDROID_ROOT) \
 	    valgrind --leak-check=full --error-exitcode=1 --workaround-gcc296-bugs=yes \
 	    --suppressions=$(ART_TARGET_TEST_DIR)/valgrind-target-suppressions.txt \
 	    --num-callers=50 \
-	    $(ART_TARGET_NATIVETEST_DIR)/$(TARGET_$(2)ARCH)/$(1) && touch $(ART_TARGET_TEST_DIR)/$(TARGET_$(2)ARCH)/$$@-$$$$PPID" \
-	  && (adb pull $(ART_TARGET_TEST_DIR)/$(TARGET_$(2)ARCH)/$$@-$$$$PPID /tmp/ \
+	    $$(PRIVATE_TARGET_EXE) && touch $(ART_TARGET_TEST_DIR)/$(TARGET_$(3)ARCH)/$$@-$$$$PPID" \
+	  && (adb pull $(ART_TARGET_TEST_DIR)/$(TARGET_$(3)ARCH)/$$@-$$$$PPID /tmp/ \
 	      && $$(call ART_TEST_PASSED,$$@)) \
 	  || $$(call ART_TEST_FAILED,$$@))
 	$(hide) rm -f /tmp/$$@-$$$$PPID
 
-  ART_TEST_TARGET_VALGRIND_GTEST$$($(2)ART_PHONY_TEST_TARGET_SUFFIX)_RULES += valgrind-$$(gtest_rule)
+  ART_TEST_TARGET_VALGRIND_GTEST$$($(3)ART_PHONY_TEST_TARGET_SUFFIX)_RULES += valgrind-$$(gtest_rule)
   ART_TEST_TARGET_VALGRIND_GTEST_RULES += valgrind-$$(gtest_rule)
   ART_TEST_TARGET_VALGRIND_GTEST_$(1)_RULES += valgrind-$$(gtest_rule)
 
   # Clear locally defined variables.
   valgrind_gtest_rule :=
   gtest_rule :=
+  gtest_exe :=
+  gtest_target_exe :=
 endef  # define-art-gtest-rule-target
 
 ART_VALGRIND_DEPENDENCIES := \
@@ -563,14 +325,15 @@
 
 # Define make rules for a host gtests.
 # $(1): gtest name - the name of the test we're building such as leb128_test.
-# $(2): 2ND_ or undefined - used to differentiate between the primary and secondary architecture.
+# $(2): path relative to $OUT to the test binary
+# $(3): 2ND_ or undefined - used to differentiate between the primary and secondary architecture.
 define define-art-gtest-rule-host
-  gtest_rule := test-art-host-gtest-$(1)$$($(2)ART_PHONY_TEST_HOST_SUFFIX)
-  gtest_exe := $$(HOST_OUT_EXECUTABLES)/$(1)$$($(2)ART_PHONY_TEST_HOST_SUFFIX)
+  gtest_rule := test-art-host-gtest-$(1)$$($(3)ART_PHONY_TEST_HOST_SUFFIX)
+  gtest_exe := $(OUT_DIR)/$(2)
   # Dependencies for all host gtests.
   gtest_deps := $$(HOST_CORE_DEX_LOCATIONS) \
-    $$($(2)ART_HOST_OUT_SHARED_LIBRARIES)/libjavacore$$(ART_HOST_SHLIB_EXTENSION) \
-    $$($(2)ART_HOST_OUT_SHARED_LIBRARIES)/libopenjdkd$$(ART_HOST_SHLIB_EXTENSION) \
+    $$($(3)ART_HOST_OUT_SHARED_LIBRARIES)/libjavacore$$(ART_HOST_SHLIB_EXTENSION) \
+    $$($(3)ART_HOST_OUT_SHARED_LIBRARIES)/libopenjdkd$$(ART_HOST_SHLIB_EXTENSION) \
     $$(gtest_exe) \
     $$(ART_GTEST_$(1)_HOST_DEPS) \
     $(foreach file,$(ART_GTEST_$(1)_DEX_DEPS),$(ART_TEST_HOST_GTEST_$(file)_DEX))
@@ -582,7 +345,7 @@
 	$(hide) ($$(call ART_TEST_SKIP,$$@) && $$< && $$(call ART_TEST_PASSED,$$@)) \
 	  || $$(call ART_TEST_FAILED,$$@)
 
-  ART_TEST_HOST_GTEST$$($(2)ART_PHONY_TEST_HOST_SUFFIX)_RULES += $$(gtest_rule)
+  ART_TEST_HOST_GTEST$$($(3)ART_PHONY_TEST_HOST_SUFFIX)_RULES += $$(gtest_rule)
   ART_TEST_HOST_GTEST_RULES += $$(gtest_rule)
   ART_TEST_HOST_GTEST_$(1)_RULES += $$(gtest_rule)
 
@@ -596,7 +359,7 @@
 	    $$< && \
 	    $$(call ART_TEST_PASSED,$$@) || $$(call ART_TEST_FAILED,$$@)
 
-  ART_TEST_HOST_VALGRIND_GTEST$$($(2)ART_PHONY_TEST_HOST_SUFFIX)_RULES += valgrind-$$(gtest_rule)
+  ART_TEST_HOST_VALGRIND_GTEST$$($(3)ART_PHONY_TEST_HOST_SUFFIX)_RULES += valgrind-$$(gtest_rule)
   ART_TEST_HOST_VALGRIND_GTEST_RULES += valgrind-$$(gtest_rule)
   ART_TEST_HOST_VALGRIND_GTEST_$(1)_RULES += valgrind-$$(gtest_rule)
 
@@ -610,8 +373,6 @@
 # Define the rules to build and run host and target gtests.
 # $(1): target or host
 # $(2): file name
-# $(3): extra C includes
-# $(4): extra shared libraries
 define define-art-gtest
   ifneq ($(1),target)
     ifneq ($(1),host)
@@ -621,40 +382,11 @@
 
   art_target_or_host := $(1)
   art_gtest_filename := $(2)
-  art_gtest_extra_c_includes := $(3)
-  art_gtest_extra_shared_libraries := $(4)
 
   include $$(CLEAR_VARS)
   art_gtest_name := $$(notdir $$(basename $$(art_gtest_filename)))
-  LOCAL_MODULE := $$(art_gtest_name)
+
   ifeq ($$(art_target_or_host),target)
-    LOCAL_MODULE_TAGS := tests
-  endif
-  LOCAL_CPP_EXTENSION := $$(ART_CPP_EXTENSION)
-  LOCAL_SRC_FILES := $$(art_gtest_filename)
-  LOCAL_C_INCLUDES += $$(ART_C_INCLUDES) art/runtime art/cmdline $$(art_gtest_extra_c_includes)
-  LOCAL_SHARED_LIBRARIES += libartd $$(art_gtest_extra_shared_libraries) libart-gtest libartd-disassembler
-  LOCAL_WHOLE_STATIC_LIBRARIES += libsigchain
-
-  LOCAL_ADDITIONAL_DEPENDENCIES := art/build/Android.common_build.mk
-  LOCAL_ADDITIONAL_DEPENDENCIES += art/build/Android.gtest.mk
-
-  # Mac OS linker doesn't understand --export-dynamic.
-  ifneq ($$(HOST_OS)-$$(art_target_or_host),darwin-host)
-    # Allow jni_compiler_test to find Java_MyClassNatives_bar within itself using dlopen(NULL, ...).
-    LOCAL_LDFLAGS := -Wl,--export-dynamic -Wl,-u,Java_MyClassNatives_bar -Wl,-u,Java_MyClassNatives_sbar
-  endif
-
-  LOCAL_CFLAGS := $$(ART_TEST_CFLAGS)
-  ifeq ($$(art_target_or_host),target)
-    $$(eval LOCAL_CLANG := $$(ART_TARGET_CLANG))
-    $$(eval $$(call set-target-local-cflags-vars,debug))
-    LOCAL_SHARED_LIBRARIES += libdl libicuuc libicui18n libnativehelper libz libcutils libvixld-arm libvixld-arm64
-    LOCAL_MODULE_PATH_32 := $$(ART_TARGET_NATIVETEST_OUT)/$$(ART_TARGET_ARCH_32)
-    LOCAL_MODULE_PATH_64 := $$(ART_TARGET_NATIVETEST_OUT)/$$(ART_TARGET_ARCH_64)
-    LOCAL_MULTILIB := both
-    LOCAL_CFLAGS += -Wno-used-but-marked-unused -Wno-deprecated -Wno-missing-noreturn  # gtest issue
-    include $$(BUILD_EXECUTABLE)
     library_path :=
     2nd_library_path :=
     ifneq ($$(ART_TEST_ANDROID_ROOT),)
@@ -673,9 +405,9 @@
     ART_TEST_TARGET_GTEST_$$(art_gtest_name)_RULES :=
     ART_TEST_TARGET_VALGRIND_GTEST_$$(art_gtest_name)_RULES :=
     ifdef TARGET_2ND_ARCH
-      $$(eval $$(call define-art-gtest-rule-target,$$(art_gtest_name),2ND_,$$(2nd_library_path)))
+      $$(eval $$(call define-art-gtest-rule-target,$$(art_gtest_name),$$(art_gtest_filename),2ND_,$$(2nd_library_path)))
     endif
-    $$(eval $$(call define-art-gtest-rule-target,$$(art_gtest_name),,$$(library_path)))
+    $$(eval $$(call define-art-gtest-rule-target,$$(art_gtest_name),$$(art_gtest_filename),,$$(library_path)))
 
     # A rule to run the different architecture versions of the gtest.
 .PHONY: test-art-target-gtest-$$(art_gtest_name)
@@ -690,24 +422,12 @@
     ART_TEST_TARGET_GTEST_$$(art_gtest_name)_RULES :=
     ART_TEST_TARGET_VALGRIND_GTEST_$$(art_gtest_name)_RULES :=
   else # host
-    LOCAL_CLANG := $$(ART_HOST_CLANG)
-    LOCAL_CFLAGS += $$(ART_HOST_CFLAGS) $$(ART_HOST_DEBUG_CFLAGS)
-    LOCAL_ASFLAGS += $$(ART_HOST_ASFLAGS) $$(ART_HOST_DEBUG_ASFLAGS)
-    LOCAL_SHARED_LIBRARIES += libicuuc-host libicui18n-host libnativehelper libziparchive libz-host libvixld-arm libvixld-arm64
-    LOCAL_LDLIBS := -lpthread -ldl
-    LOCAL_IS_HOST_MODULE := true
-    LOCAL_MULTILIB := both
-    LOCAL_MODULE_STEM_32 := $$(art_gtest_name)32
-    LOCAL_MODULE_STEM_64 := $$(art_gtest_name)64
-    LOCAL_CFLAGS += -Wno-used-but-marked-unused -Wno-deprecated -Wno-missing-noreturn  # gtest issue
-    include $$(BUILD_HOST_EXECUTABLE)
-
     ART_TEST_HOST_GTEST_$$(art_gtest_name)_RULES :=
     ART_TEST_HOST_VALGRIND_GTEST_$$(art_gtest_name)_RULES :=
     ifneq ($$(HOST_PREFER_32_BIT),true)
-      $$(eval $$(call define-art-gtest-rule-host,$$(art_gtest_name),2ND_))
+      $$(eval $$(call define-art-gtest-rule-host,$$(art_gtest_name),$$(art_gtest_filename),2ND_))
     endif
-    $$(eval $$(call define-art-gtest-rule-host,$$(art_gtest_name),))
+    $$(eval $$(call define-art-gtest-rule-host,$$(art_gtest_name),$$(art_gtest_filename),))
 
     # Rules to run the different architecture versions of the gtest.
 .PHONY: test-art-host-gtest-$$(art_gtest_name)
@@ -726,8 +446,6 @@
   # Clear locally defined variables.
   art_target_or_host :=
   art_gtest_filename :=
-  art_gtest_extra_c_includes :=
-  art_gtest_extra_shared_libraries :=
   art_gtest_name :=
   library_path :=
   2nd_library_path :=
@@ -735,19 +453,16 @@
 
 
 ifeq ($(ART_BUILD_TARGET),true)
-  $(foreach file,$(RUNTIME_GTEST_TARGET_SRC_FILES), $(eval $(call define-art-gtest,target,$(file),,libbacktrace)))
-  $(foreach file,$(COMPILER_GTEST_TARGET_SRC_FILES), $(eval $(call define-art-gtest,target,$(file),art/compiler,libartd-compiler libbacktrace libnativeloader)))
+  $(foreach file,$(ART_TARGET_GTEST_FILES), $(eval $(call define-art-gtest,target,$(file))))
 endif
 ifeq ($(ART_BUILD_HOST),true)
-  $(foreach file,$(RUNTIME_GTEST_HOST_SRC_FILES), $(eval $(call define-art-gtest,host,$(file),,libbacktrace)))
-  $(foreach file,$(COMPILER_GTEST_HOST_SRC_FILES), $(eval $(call define-art-gtest,host,$(file),art/compiler,libartd-compiler libbacktrace libnativeloader)))
+  $(foreach file,$(ART_HOST_GTEST_FILES), $(eval $(call define-art-gtest,host,$(file))))
 endif
 
 # Used outside the art project to get a list of the current tests
 RUNTIME_TARGET_GTEST_MAKE_TARGETS :=
-$(foreach file, $(RUNTIME_GTEST_TARGET_SRC_FILES), $(eval RUNTIME_TARGET_GTEST_MAKE_TARGETS += $$(notdir $$(basename $$(file)))))
+$(foreach file, $(ART_TARGET_GTEST_FILES), $(eval RUNTIME_TARGET_GTEST_MAKE_TARGETS += $$(notdir $$(basename $$(file)))))
 COMPILER_TARGET_GTEST_MAKE_TARGETS :=
-$(foreach file, $(COMPILER_GTEST_TARGET_SRC_FILES), $(eval COMPILER_TARGET_GTEST_MAKE_TARGETS += $$(notdir $$(basename $$(file)))))
 
 # Define all the combinations of host/target, valgrind and suffix such as:
 # test-art-host-gtest or valgrind-test-art-host-gtest64
diff --git a/build/Android.oat.mk b/build/Android.oat.mk
index 884f698..c4887e6 100644
--- a/build/Android.oat.mk
+++ b/build/Android.oat.mk
@@ -37,7 +37,7 @@
 endif
 
 # Use dex2oat debug version for better error reporting
-# $(1): compiler - default, optimizing, jit, interpreter or interpreter-access-checks.
+# $(1): compiler - optimizing, interpreter or interpreter-access-checks.
 # $(2): pic/no-pic
 # $(3): 2ND_ or undefined, 2ND_ for 32-bit host builds.
 # $(4): wrapper, e.g., valgrind.
@@ -53,13 +53,9 @@
   core_pic_infix :=
   core_dex2oat_dependency := $(DEX2OAT_DEPENDENCY)
 
-  ifeq ($(1),default)
-    core_compile_options += --compiler-backend=Quick
-  endif
   ifeq ($(1),optimizing)
     core_compile_options += --compiler-backend=Optimizing
     core_dex2oat_dependency := $(DEX2OAT)
-    core_infix := -optimizing
   endif
   ifeq ($(1),interpreter)
     core_compile_options += --compiler-filter=interpret-only
@@ -69,24 +65,16 @@
     core_compile_options += --compiler-filter=verify-at-runtime --runtime-arg -Xverify:softfail
     core_infix := -interp-ac
   endif
-  ifeq ($(1),jit)
-    core_compile_options += --compiler-filter=verify-at-runtime
-    core_infix := -jit
-  endif
-  ifeq ($(1),default)
-    # Default has no infix, no compile options.
-  endif
-  ifneq ($(filter-out default interpreter interp-ac jit optimizing,$(1)),)
+  ifneq ($(filter-out interpreter interp-ac optimizing,$(1)),)
     #Technically this test is not precise, but hopefully good enough.
-    $$(error found $(1) expected default, interpreter, interpreter-access-checks, jit or optimizing)
+    $$(error found $(1) expected interpreter, interpreter-access-checks, or optimizing)
   endif
 
   ifeq ($(2),pic)
     core_compile_options += --compile-pic
-    core_pic_infix := -pic
   endif
   ifeq ($(2),no-pic)
-    # No change for non-pic
+    core_pic_infix := -npic
   endif
   ifneq ($(filter-out pic no-pic,$(2)),)
     # Technically this test is not precise, but hopefully good enough.
@@ -148,7 +136,7 @@
   core_pic_infix :=
 endef  # create-core-oat-host-rules
 
-# $(1): compiler - default, optimizing, jit, interpreter or interpreter-access-checks.
+# $(1): compiler - optimizing, interpreter or interpreter-access-checks.
 # $(2): wrapper.
 # $(3): dex2oat suffix.
 # $(4): multi-image.
@@ -162,24 +150,18 @@
   endif
 endef
 
-$(eval $(call create-core-oat-host-rule-combination,default,,,false))
 $(eval $(call create-core-oat-host-rule-combination,optimizing,,,false))
 $(eval $(call create-core-oat-host-rule-combination,interpreter,,,false))
 $(eval $(call create-core-oat-host-rule-combination,interp-ac,,,false))
-$(eval $(call create-core-oat-host-rule-combination,jit,,,false))
-$(eval $(call create-core-oat-host-rule-combination,default,,,true))
 $(eval $(call create-core-oat-host-rule-combination,optimizing,,,true))
 $(eval $(call create-core-oat-host-rule-combination,interpreter,,,true))
 $(eval $(call create-core-oat-host-rule-combination,interp-ac,,,true))
-$(eval $(call create-core-oat-host-rule-combination,jit,,,true))
 
 valgrindHOST_CORE_IMG_OUTS :=
 valgrindHOST_CORE_OAT_OUTS :=
-$(eval $(call create-core-oat-host-rule-combination,default,valgrind,32,false))
 $(eval $(call create-core-oat-host-rule-combination,optimizing,valgrind,32,false))
 $(eval $(call create-core-oat-host-rule-combination,interpreter,valgrind,32,false))
 $(eval $(call create-core-oat-host-rule-combination,interp-ac,valgrind,32,false))
-$(eval $(call create-core-oat-host-rule-combination,jit,valgrind,32,false))
 
 valgrind-test-art-host-dex2oat-host: $(valgrindHOST_CORE_IMG_OUTS)
 
@@ -193,15 +175,11 @@
   core_pic_infix :=
   core_dex2oat_dependency := $(DEX2OAT_DEPENDENCY)
 
-  ifeq ($(1),default)
-    core_compile_options += --compiler-backend=Quick
-  endif
   ifeq ($(1),optimizing)
     core_compile_options += --compiler-backend=Optimizing
     # With the optimizing compiler, we want to rerun dex2oat whenever there is
     # a dex2oat change to catch regressions early.
     core_dex2oat_dependency := $(DEX2OAT)
-    core_infix := -optimizing
   endif
   ifeq ($(1),interpreter)
     core_compile_options += --compiler-filter=interpret-only
@@ -211,24 +189,16 @@
     core_compile_options += --compiler-filter=verify-at-runtime --runtime-arg -Xverify:softfail
     core_infix := -interp-ac
   endif
-  ifeq ($(1),jit)
-    core_compile_options += --compiler-filter=verify-at-runtime
-    core_infix := -jit
-  endif
-  ifeq ($(1),default)
-    # Default has no infix, no compile options.
-  endif
-  ifneq ($(filter-out default interpreter interp-ac jit optimizing,$(1)),)
+  ifneq ($(filter-out interpreter interp-ac optimizing,$(1)),)
     # Technically this test is not precise, but hopefully good enough.
-    $$(error found $(1) expected default, interpreter, interpreter-access-checks, jit or optimizing)
+    $$(error found $(1) expected interpreter, interpreter-access-checks, or optimizing)
   endif
 
   ifeq ($(2),pic)
     core_compile_options += --compile-pic
-    core_pic_infix := -pic
   endif
   ifeq ($(2),no-pic)
-    # No change for non-pic
+    core_pic_infix := -npic
   endif
   ifneq ($(filter-out pic no-pic,$(2)),)
     #Technically this test is not precise, but hopefully good enough.
@@ -283,7 +253,7 @@
   core_pic_infix :=
 endef  # create-core-oat-target-rules
 
-# $(1): compiler - default, optimizing, jit, interpreter or interpreter-access-checks.
+# $(1): compiler - optimizing, interpreter or interpreter-access-checks.
 # $(2): wrapper.
 # $(3): dex2oat suffix.
 define create-core-oat-target-rule-combination
@@ -296,19 +266,15 @@
   endif
 endef
 
-$(eval $(call create-core-oat-target-rule-combination,default,,))
 $(eval $(call create-core-oat-target-rule-combination,optimizing,,))
 $(eval $(call create-core-oat-target-rule-combination,interpreter,,))
 $(eval $(call create-core-oat-target-rule-combination,interp-ac,,))
-$(eval $(call create-core-oat-target-rule-combination,jit,,))
 
 valgrindTARGET_CORE_IMG_OUTS :=
 valgrindTARGET_CORE_OAT_OUTS :=
-$(eval $(call create-core-oat-target-rule-combination,default,valgrind,32))
 $(eval $(call create-core-oat-target-rule-combination,optimizing,valgrind,32))
 $(eval $(call create-core-oat-target-rule-combination,interpreter,valgrind,32))
 $(eval $(call create-core-oat-target-rule-combination,interp-ac,valgrind,32))
-$(eval $(call create-core-oat-target-rule-combination,jit,valgrind,32))
 
 valgrind-test-art-host-dex2oat-target: $(valgrindTARGET_CORE_IMG_OUTS)
 
diff --git a/build/art.go b/build/art.go
index 9cab3b9..f2efbfe 100644
--- a/build/art.go
+++ b/build/art.go
@@ -19,6 +19,7 @@
 	"android/soong/android"
 	"android/soong/cc"
 	"fmt"
+	"sync"
 
 	"github.com/google/blueprint"
 )
@@ -43,6 +44,10 @@
 		cflags = append(cflags, "-DART_USE_TLAB=1")
 	}
 
+	if !envFalse(ctx, "ART_ENABLE_VDEX") {
+		cflags = append(cflags, "-DART_ENABLE_VDEX")
+	}
+
 	imtSize := envDefault(ctx, "ART_IMT_SIZE", "43")
 	cflags = append(cflags, "-DIMT_SIZE="+imtSize)
 
@@ -118,7 +123,7 @@
 	return cflags
 }
 
-func (a *artGlobalDefaults) CustomizeProperties(ctx android.CustomizePropertiesContext) {
+func globalDefaults(ctx android.LoadHookContext) {
 	type props struct {
 		Target struct {
 			Android struct {
@@ -139,9 +144,7 @@
 	ctx.AppendProperties(p)
 }
 
-type artGlobalDefaults struct{}
-
-func (a *artCustomLinkerCustomizer) CustomizeProperties(ctx android.CustomizePropertiesContext) {
+func customLinker(ctx android.LoadHookContext) {
 	linker := envDefault(ctx, "CUSTOM_TARGET_LINKER", "")
 	if linker != "" {
 		type props struct {
@@ -154,9 +157,7 @@
 	}
 }
 
-type artCustomLinkerCustomizer struct{}
-
-func (a *artPrefer32BitCustomizer) CustomizeProperties(ctx android.CustomizePropertiesContext) {
+func prefer32Bit(ctx android.LoadHookContext) {
 	if envTrue(ctx, "HOST_PREFER_32_BIT") {
 		type props struct {
 			Target struct {
@@ -172,27 +173,52 @@
 	}
 }
 
-type artPrefer32BitCustomizer struct{}
+func testMap(config android.Config) map[string][]string {
+	return config.Once("artTests", func() interface{} {
+		return make(map[string][]string)
+	}).(map[string][]string)
+}
+
+func testInstall(ctx android.InstallHookContext) {
+	testMap := testMap(ctx.AConfig())
+
+	var name string
+	if ctx.Host() {
+		name = "host_"
+	} else {
+		name = "device_"
+	}
+	name += ctx.Arch().ArchType.String() + "_" + ctx.ModuleName()
+
+	artTestMutex.Lock()
+	defer artTestMutex.Unlock()
+
+	tests := testMap[name]
+	tests = append(tests, ctx.Path().RelPathString())
+	testMap[name] = tests
+}
+
+var artTestMutex sync.Mutex
 
 func init() {
 	soong.RegisterModuleType("art_cc_library", artLibrary)
 	soong.RegisterModuleType("art_cc_binary", artBinary)
+	soong.RegisterModuleType("art_cc_test", artTest)
 	soong.RegisterModuleType("art_cc_defaults", artDefaultsFactory)
 	soong.RegisterModuleType("art_global_defaults", artGlobalDefaultsFactory)
 }
 
 func artGlobalDefaultsFactory() (blueprint.Module, []interface{}) {
-	c := &artGlobalDefaults{}
 	module, props := artDefaultsFactory()
-	android.AddCustomizer(module.(android.Module), c)
+	android.AddLoadHook(module, globalDefaults)
 
 	return module, props
 }
 
 func artDefaultsFactory() (blueprint.Module, []interface{}) {
-	c := &codegenCustomizer{}
-	module, props := cc.DefaultsFactory(&c.codegenProperties)
-	android.AddCustomizer(module.(android.Module), c)
+	c := &codegenProperties{}
+	module, props := cc.DefaultsFactory(c)
+	android.AddLoadHook(module, func(ctx android.LoadHookContext) { codegen(ctx, c, true) })
 
 	return module, props
 }
@@ -201,9 +227,7 @@
 	library, _ := cc.NewLibrary(android.HostAndDeviceSupported, true, true)
 	module, props := library.Init()
 
-	c := &codegenCustomizer{}
-	android.AddCustomizer(library, c)
-	props = append(props, &c.codegenProperties)
+	props = installCodegenCustomizer(module, props, true)
 
 	return module, props
 }
@@ -212,8 +236,20 @@
 	binary, _ := cc.NewBinary(android.HostAndDeviceSupported)
 	module, props := binary.Init()
 
-	android.AddCustomizer(binary, &artCustomLinkerCustomizer{})
-	android.AddCustomizer(binary, &artPrefer32BitCustomizer{})
+	android.AddLoadHook(module, customLinker)
+	android.AddLoadHook(module, prefer32Bit)
+	return module, props
+}
+
+func artTest() (blueprint.Module, []interface{}) {
+	test := cc.NewTest(android.HostAndDeviceSupported)
+	module, props := test.Init()
+
+	props = installCodegenCustomizer(module, props, false)
+
+	android.AddLoadHook(module, customLinker)
+	android.AddLoadHook(module, prefer32Bit)
+	android.AddInstallHook(module, testInstall)
 	return module, props
 }
 
@@ -228,3 +264,7 @@
 func envTrue(ctx android.BaseContext, key string) bool {
 	return ctx.AConfig().Getenv(key) == "true"
 }
+
+func envFalse(ctx android.BaseContext, key string) bool {
+	return ctx.AConfig().Getenv(key) == "false"
+}
diff --git a/build/codegen.go b/build/codegen.go
index eb2c37d..ba6f214 100644
--- a/build/codegen.go
+++ b/build/codegen.go
@@ -22,11 +22,11 @@
 	"android/soong/android"
 	"sort"
 	"strings"
+
+	"github.com/google/blueprint"
 )
 
-func (a *codegenCustomizer) CustomizeProperties(ctx android.CustomizePropertiesContext) {
-	c := &a.codegenProperties.Codegen
-
+func codegen(ctx android.LoadHookContext, c *codegenProperties, library bool) {
 	var hostArches, deviceArches []string
 
 	e := envDefault(ctx, "ART_HOST_CODEGEN_ARCHS", "")
@@ -43,54 +43,77 @@
 		deviceArches = strings.Split(e, " ")
 	}
 
-	type props struct {
-		Target struct {
-			Android *codegenArchProperties
-			Host    *codegenArchProperties
+	addCodegenArchProperties := func(host bool, archName string) {
+		type props struct {
+			Target struct {
+				Android *CodegenCommonArchProperties
+				Host    *CodegenCommonArchProperties
+			}
 		}
-	}
 
-	addCodegenArchProperties := func(p *props, hod **codegenArchProperties, arch string) {
-		switch arch {
+		type libraryProps struct {
+			Target struct {
+				Android *CodegenLibraryArchProperties
+				Host    *CodegenLibraryArchProperties
+			}
+		}
+
+		var arch *codegenArchProperties
+		switch archName {
 		case "arm":
-			*hod = &c.Arm
+			arch = &c.Codegen.Arm
 		case "arm64":
-			*hod = &c.Arm64
+			arch = &c.Codegen.Arm64
 		case "mips":
-			*hod = &c.Mips
+			arch = &c.Codegen.Mips
 		case "mips64":
-			*hod = &c.Mips64
+			arch = &c.Codegen.Mips64
 		case "x86":
-			*hod = &c.X86
+			arch = &c.Codegen.X86
 		case "x86_64":
-			*hod = &c.X86_64
+			arch = &c.Codegen.X86_64
 		default:
-			ctx.ModuleErrorf("Unknown codegen architecture %q", arch)
+			ctx.ModuleErrorf("Unknown codegen architecture %q", archName)
 			return
 		}
+
+		p := &props{}
+		l := &libraryProps{}
+		if host {
+			p.Target.Host = &arch.CodegenCommonArchProperties
+			l.Target.Host = &arch.CodegenLibraryArchProperties
+		} else {
+			p.Target.Android = &arch.CodegenCommonArchProperties
+			l.Target.Android = &arch.CodegenLibraryArchProperties
+		}
+
 		ctx.AppendProperties(p)
+		if library {
+			ctx.AppendProperties(l)
+		}
 	}
 
-	for _, a := range deviceArches {
-		p := &props{}
-		addCodegenArchProperties(p, &p.Target.Android, a)
+	for _, arch := range deviceArches {
+		addCodegenArchProperties(false, arch)
 		if ctx.Failed() {
 			return
 		}
 	}
 
-	for _, a := range hostArches {
-		p := &props{}
-		addCodegenArchProperties(p, &p.Target.Host, a)
+	for _, arch := range hostArches {
+		addCodegenArchProperties(true, arch)
 		if ctx.Failed() {
 			return
 		}
 	}
 }
 
-type codegenArchProperties struct {
+type CodegenCommonArchProperties struct {
 	Srcs   []string
 	Cflags []string
+}
+
+type CodegenLibraryArchProperties struct {
 	Static struct {
 		Whole_static_libs []string
 	}
@@ -99,6 +122,11 @@
 	}
 }
 
+type codegenArchProperties struct {
+	CodegenCommonArchProperties
+	CodegenLibraryArchProperties
+}
+
 type codegenProperties struct {
 	Codegen struct {
 		Arm, Arm64, Mips, Mips64, X86, X86_64 codegenArchProperties
@@ -106,13 +134,22 @@
 }
 
 type codegenCustomizer struct {
+	library           bool
 	codegenProperties codegenProperties
 }
 
-func defaultDeviceCodegenArches(ctx android.CustomizePropertiesContext) []string {
+func defaultDeviceCodegenArches(ctx android.LoadHookContext) []string {
 	arches := make(map[string]bool)
 	for _, a := range ctx.DeviceConfig().Arches() {
-		arches[a.ArchType.String()] = true
+		s := a.ArchType.String()
+		arches[s] = true
+		if s == "arm64" {
+			arches["arm"] = true
+		} else if s == "mips64" {
+			arches["mips"] = true
+		} else if s == "x86_64" {
+			arches["x86"] = true
+		}
 	}
 	ret := make([]string, 0, len(arches))
 	for a := range arches {
@@ -121,3 +158,11 @@
 	sort.Strings(ret)
 	return ret
 }
+
+func installCodegenCustomizer(module blueprint.Module, props []interface{}, library bool) []interface{} {
+	c := &codegenProperties{}
+	android.AddLoadHook(module, func(ctx android.LoadHookContext) { codegen(ctx, c, library) })
+	props = append(props, c)
+
+	return props
+}
diff --git a/build/makevars.go b/build/makevars.go
index 5655c55..1faa0f6 100644
--- a/build/makevars.go
+++ b/build/makevars.go
@@ -14,7 +14,12 @@
 
 package art
 
-import "android/soong/android"
+import (
+	"sort"
+	"strings"
+
+	"android/soong/android"
+)
 
 var (
 	pctx = android.NewPackageContext("android/soong/art")
@@ -27,4 +32,16 @@
 func makeVarsProvider(ctx android.MakeVarsContext) {
 	ctx.Strict("LIBART_IMG_HOST_BASE_ADDRESS", ctx.Config().LibartImgHostBaseAddress())
 	ctx.Strict("LIBART_IMG_TARGET_BASE_ADDRESS", ctx.Config().LibartImgDeviceBaseAddress())
+
+	testMap := testMap(ctx.Config())
+	var testNames []string
+	for name := range testMap {
+		testNames = append(testNames, name)
+	}
+
+	sort.Strings(testNames)
+
+	for _, name := range testNames {
+		ctx.Strict("ART_TEST_LIST_"+name, strings.Join(testMap[name], " "))
+	}
 }
diff --git a/cmdline/Android.bp b/cmdline/Android.bp
new file mode 100644
index 0000000..c9cd9dc
--- /dev/null
+++ b/cmdline/Android.bp
@@ -0,0 +1,23 @@
+//
+// 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.
+//
+
+art_cc_test {
+    name: "art_cmdline_tests",
+    defaults: [
+        "art_test_defaults",
+    ],
+    srcs: ["cmdline_parser_test.cc"],
+}
diff --git a/compiler/Android.bp b/compiler/Android.bp
index 595a824..4af43cc 100644
--- a/compiler/Android.bp
+++ b/compiler/Android.bp
@@ -279,3 +279,153 @@
     },
     shared_libs: ["libartd"],
 }
+
+art_cc_library {
+    name: "libart-compiler-gtest",
+    defaults: ["libart-gtest-defaults"],
+    srcs: ["common_compiler_test.cc"],
+    shared_libs: [
+        "libartd-compiler",
+        "libart-runtime-gtest",
+    ],
+}
+
+art_cc_test {
+    name: "art_compiler_tests",
+    defaults: [
+        "art_test_defaults",
+    ],
+    srcs: [
+        "compiled_method_test.cc",
+        "debug/dwarf/dwarf_test.cc",
+        "driver/compiled_method_storage_test.cc",
+        "driver/compiler_driver_test.cc",
+        "elf_writer_test.cc",
+        "exception_test.cc",
+        "image_test.cc",
+        "jni/jni_compiler_test.cc",
+        "linker/multi_oat_relative_patcher_test.cc",
+        "linker/output_stream_test.cc",
+        "oat_test.cc",
+        "optimizing/bounds_check_elimination_test.cc",
+        "optimizing/dominator_test.cc",
+        "optimizing/find_loops_test.cc",
+        "optimizing/graph_checker_test.cc",
+        "optimizing/graph_test.cc",
+        "optimizing/gvn_test.cc",
+        "optimizing/induction_var_analysis_test.cc",
+        "optimizing/induction_var_range_test.cc",
+        "optimizing/licm_test.cc",
+        "optimizing/live_interval_test.cc",
+        "optimizing/nodes_test.cc",
+        "optimizing/parallel_move_test.cc",
+        "optimizing/pretty_printer_test.cc",
+        "optimizing/reference_type_propagation_test.cc",
+        "optimizing/side_effects_test.cc",
+        "optimizing/ssa_test.cc",
+        "optimizing/stack_map_test.cc",
+        "optimizing/suspend_check_test.cc",
+        "utils/dedupe_set_test.cc",
+        "utils/intrusive_forward_list_test.cc",
+        "utils/string_reference_test.cc",
+        "utils/swap_space_test.cc",
+        "utils/test_dex_file_builder_test.cc",
+
+        "jni/jni_cfi_test.cc",
+        "optimizing/codegen_test.cc",
+        "optimizing/optimizing_cfi_test.cc",
+    ],
+
+    codegen: {
+        arm: {
+            srcs: [
+                "linker/arm/relative_patcher_thumb2_test.cc",
+                "utils/arm/managed_register_arm_test.cc",
+            ],
+        },
+        arm64: {
+            srcs: [
+                "linker/arm64/relative_patcher_arm64_test.cc",
+                "utils/arm64/managed_register_arm64_test.cc",
+            ],
+        },
+        mips: {
+            srcs: [
+                "linker/mips/relative_patcher_mips_test.cc",
+                "linker/mips/relative_patcher_mips32r6_test.cc",
+            ],
+        },
+        x86: {
+            srcs: [
+                "linker/x86/relative_patcher_x86_test.cc",
+                "utils/x86/managed_register_x86_test.cc",
+
+                // These tests are testing architecture-independent
+                // functionality, but happen to use x86 codegen as part of the
+                // test.
+                "optimizing/constant_folding_test.cc",
+                "optimizing/dead_code_elimination_test.cc",
+                "optimizing/linearize_test.cc",
+                "optimizing/live_ranges_test.cc",
+                "optimizing/liveness_test.cc",
+                "optimizing/register_allocator_test.cc",
+            ],
+        },
+        x86_64: {
+            srcs: [
+                "linker/x86_64/relative_patcher_x86_64_test.cc",
+            ],
+        },
+    },
+
+    shared_libs: [
+        "libartd-compiler",
+        "libvixld-arm",
+        "libvixld-arm64",
+
+        "libbacktrace",
+        "libnativeloader",
+    ],
+}
+
+art_cc_test {
+    name: "art_compiler_host_tests",
+    device_supported: false,
+    defaults: [
+        "art_test_defaults",
+    ],
+    codegen: {
+        arm: {
+            srcs: [
+                "utils/arm/assembler_thumb2_test.cc",
+                "utils/assembler_thumb_test.cc",
+            ],
+        },
+        mips: {
+            srcs: [
+                "utils/mips/assembler_mips_test.cc",
+                "utils/mips/assembler_mips32r6_test.cc",
+            ],
+        },
+        mips64: {
+            srcs: [
+                "utils/mips64/assembler_mips64_test.cc",
+            ],
+        },
+        x86: {
+            srcs: [
+                "utils/x86/assembler_x86_test.cc",
+            ],
+        },
+        x86_64: {
+            srcs: [
+                "utils/x86_64/assembler_x86_64_test.cc",
+            ],
+        },
+    },
+    shared_libs: [
+        "libartd-compiler",
+        "libvixld-arm",
+        "libvixld-arm64",
+    ],
+}
diff --git a/compiler/compiled_method.h b/compiler/compiled_method.h
index 2a81804..1a87448 100644
--- a/compiler/compiled_method.h
+++ b/compiler/compiled_method.h
@@ -23,10 +23,10 @@
 #include <vector>
 
 #include "arch/instruction_set.h"
+#include "base/array_ref.h"
 #include "base/bit_utils.h"
 #include "base/length_prefixed_array.h"
 #include "method_reference.h"
-#include "utils/array_ref.h"
 
 namespace art {
 
diff --git a/compiler/compiler.h b/compiler/compiler.h
index ed42958..9a69456 100644
--- a/compiler/compiler.h
+++ b/compiler/compiler.h
@@ -25,10 +25,14 @@
 namespace jit {
   class JitCodeCache;
 }
+namespace mirror {
+  class DexCache;
+}
 
 class ArtMethod;
 class CompilerDriver;
 class CompiledMethod;
+template<class T> class Handle;
 class OatWriter;
 
 class Compiler {
diff --git a/compiler/debug/dwarf/headers.h b/compiler/debug/dwarf/headers.h
index 146d9fd..28f1084 100644
--- a/compiler/debug/dwarf/headers.h
+++ b/compiler/debug/dwarf/headers.h
@@ -19,13 +19,13 @@
 
 #include <cstdint>
 
+#include "base/array_ref.h"
 #include "debug/dwarf/debug_frame_opcode_writer.h"
 #include "debug/dwarf/debug_info_entry_writer.h"
 #include "debug/dwarf/debug_line_opcode_writer.h"
 #include "debug/dwarf/dwarf_constants.h"
 #include "debug/dwarf/register.h"
 #include "debug/dwarf/writer.h"
-#include "utils/array_ref.h"
 
 namespace art {
 namespace dwarf {
diff --git a/compiler/debug/elf_debug_writer.cc b/compiler/debug/elf_debug_writer.cc
index 5bfdd16..d1c10a9 100644
--- a/compiler/debug/elf_debug_writer.cc
+++ b/compiler/debug/elf_debug_writer.cc
@@ -18,6 +18,7 @@
 
 #include <vector>
 
+#include "base/array_ref.h"
 #include "debug/dwarf/dwarf_constants.h"
 #include "debug/elf_compilation_unit.h"
 #include "debug/elf_debug_frame_writer.h"
@@ -29,7 +30,6 @@
 #include "debug/method_debug_info.h"
 #include "elf_builder.h"
 #include "linker/vector_output_stream.h"
-#include "utils/array_ref.h"
 
 namespace art {
 namespace debug {
diff --git a/compiler/debug/elf_debug_writer.h b/compiler/debug/elf_debug_writer.h
index b0542c7..07f7229 100644
--- a/compiler/debug/elf_debug_writer.h
+++ b/compiler/debug/elf_debug_writer.h
@@ -19,11 +19,11 @@
 
 #include <vector>
 
+#include "base/array_ref.h"
 #include "base/macros.h"
 #include "base/mutex.h"
 #include "debug/dwarf/dwarf_constants.h"
 #include "elf_builder.h"
-#include "utils/array_ref.h"
 
 namespace art {
 class OatHeader;
diff --git a/compiler/driver/compiled_method_storage.h b/compiler/driver/compiled_method_storage.h
index 8674abf..124b5a6 100644
--- a/compiler/driver/compiled_method_storage.h
+++ b/compiler/driver/compiled_method_storage.h
@@ -20,9 +20,9 @@
 #include <iosfwd>
 #include <memory>
 
+#include "base/array_ref.h"
 #include "base/length_prefixed_array.h"
 #include "base/macros.h"
-#include "utils/array_ref.h"
 #include "utils/dedupe_set.h"
 #include "utils/swap_space.h"
 
diff --git a/compiler/driver/compiler_driver.cc b/compiler/driver/compiler_driver.cc
index daac7fb..a149c07 100644
--- a/compiler/driver/compiler_driver.cc
+++ b/compiler/driver/compiler_driver.cc
@@ -26,6 +26,7 @@
 
 #include "art_field-inl.h"
 #include "art_method-inl.h"
+#include "base/array_ref.h"
 #include "base/bit_vector.h"
 #include "base/enums.h"
 #include "base/stl_util.h"
@@ -67,11 +68,11 @@
 #include "thread_pool.h"
 #include "trampolines/trampoline_compiler.h"
 #include "transaction.h"
-#include "utils/array_ref.h"
 #include "utils/dex_cache_arrays_layout-inl.h"
 #include "utils/swap_space.h"
 #include "verifier/method_verifier.h"
 #include "verifier/method_verifier-inl.h"
+#include "verifier/verifier_log_mode.h"
 
 namespace art {
 
@@ -2258,7 +2259,7 @@
 
 class VerifyClassVisitor : public CompilationVisitor {
  public:
-  VerifyClassVisitor(const ParallelCompilationManager* manager, LogSeverity log_level)
+  VerifyClassVisitor(const ParallelCompilationManager* manager, verifier::HardFailLogMode log_level)
      : manager_(manager), log_level_(log_level) {}
 
   virtual void Visit(size_t class_def_index) REQUIRES(!Locks::mutator_lock_) OVERRIDE {
@@ -2329,7 +2330,7 @@
 
  private:
   const ParallelCompilationManager* const manager_;
-  const LogSeverity log_level_;
+  const verifier::HardFailLogMode log_level_;
 };
 
 void CompilerDriver::VerifyDexFile(jobject class_loader,
@@ -2342,9 +2343,9 @@
   ClassLinker* class_linker = Runtime::Current()->GetClassLinker();
   ParallelCompilationManager context(class_linker, class_loader, this, &dex_file, dex_files,
                                      thread_pool);
-  LogSeverity log_level = GetCompilerOptions().AbortOnHardVerifierFailure()
-                              ? LogSeverity::INTERNAL_FATAL
-                              : LogSeverity::WARNING;
+  verifier::HardFailLogMode log_level = GetCompilerOptions().AbortOnHardVerifierFailure()
+                              ? verifier::HardFailLogMode::kLogInternalFatal
+                              : verifier::HardFailLogMode::kLogWarning;
   VerifyClassVisitor visitor(&context, log_level);
   context.ForAll(0, dex_file.NumClassDefs(), &visitor, thread_count);
 }
@@ -2473,7 +2474,7 @@
               // mode which prevents the GC from visiting objects modified during the transaction.
               // Ensure GC is not run so don't access freed objects when aborting transaction.
 
-              ScopedAssertNoThreadSuspension ants(soa.Self(), "Transaction end");
+              ScopedAssertNoThreadSuspension ants("Transaction end");
               runtime->ExitTransactionMode();
 
               if (!success) {
diff --git a/compiler/driver/compiler_driver.h b/compiler/driver/compiler_driver.h
index fbc1edd..ee21efa 100644
--- a/compiler/driver/compiler_driver.h
+++ b/compiler/driver/compiler_driver.h
@@ -24,6 +24,7 @@
 
 #include "arch/instruction_set.h"
 #include "base/arena_allocator.h"
+#include "base/array_ref.h"
 #include "base/bit_utils.h"
 #include "base/mutex.h"
 #include "base/timing_logger.h"
@@ -39,7 +40,6 @@
 #include "runtime.h"
 #include "safe_map.h"
 #include "thread_pool.h"
-#include "utils/array_ref.h"
 #include "utils/dex_cache_arrays_layout.h"
 
 namespace art {
diff --git a/compiler/elf_builder.h b/compiler/elf_builder.h
index 7f2e193..02831c9 100644
--- a/compiler/elf_builder.h
+++ b/compiler/elf_builder.h
@@ -21,13 +21,13 @@
 
 #include "arch/instruction_set.h"
 #include "arch/mips/instruction_set_features_mips.h"
+#include "base/array_ref.h"
 #include "base/bit_utils.h"
 #include "base/casts.h"
 #include "base/unix_file/fd_file.h"
 #include "elf_utils.h"
 #include "leb128.h"
 #include "linker/error_delaying_output_stream.h"
-#include "utils/array_ref.h"
 
 namespace art {
 
diff --git a/compiler/elf_writer.h b/compiler/elf_writer.h
index c9ea0083..f8f9102 100644
--- a/compiler/elf_writer.h
+++ b/compiler/elf_writer.h
@@ -22,10 +22,10 @@
 #include <string>
 #include <vector>
 
+#include "base/array_ref.h"
 #include "base/macros.h"
 #include "base/mutex.h"
 #include "os.h"
-#include "utils/array_ref.h"
 
 namespace art {
 
diff --git a/compiler/image_test.cc b/compiler/image_test.cc
index e1ee0d2..a18935f 100644
--- a/compiler/image_test.cc
+++ b/compiler/image_test.cc
@@ -73,10 +73,12 @@
   CHECK_EQ(0, mkdir_result) << image_dir;
   ScratchFile image_file(OS::CreateEmptyFile(image_filename.c_str()));
 
-  std::string oat_filename(image_filename, 0, image_filename.size() - 3);
-  oat_filename += "oat";
+  std::string oat_filename = ReplaceFileExtension(image_filename, "oat");
   ScratchFile oat_file(OS::CreateEmptyFile(oat_filename.c_str()));
 
+  std::string vdex_filename = ReplaceFileExtension(image_filename, "vdex");
+  ScratchFile vdex_file(OS::CreateEmptyFile(vdex_filename.c_str()));
+
   const uintptr_t requested_image_base = ART_BASE_ADDRESS;
   std::unordered_map<const DexFile*, size_t> dex_file_to_oat_index_map;
   std::vector<const char*> oat_filename_vector(1, oat_filename.c_str());
@@ -109,7 +111,7 @@
           oat_file.GetFile());
       elf_writer->Start();
       OatWriter oat_writer(/*compiling_boot_image*/true, &timings);
-      OutputStream* rodata = elf_writer->StartRoData();
+      OutputStream* oat_rodata = elf_writer->StartRoData();
       for (const DexFile* dex_file : dex_files) {
         ArrayRef<const uint8_t> raw_dex_file(
             reinterpret_cast<const uint8_t*>(&dex_file->GetHeader()),
@@ -120,16 +122,18 @@
       }
       std::unique_ptr<MemMap> opened_dex_files_map;
       std::vector<std::unique_ptr<const DexFile>> opened_dex_files;
-      bool dex_files_ok = oat_writer.WriteAndOpenDexFiles(
-          rodata,
-          oat_file.GetFile(),
-          compiler_driver_->GetInstructionSet(),
-          compiler_driver_->GetInstructionSetFeatures(),
-          &key_value_store,
-          /* verify */ false,           // Dex files may be dex-to-dex-ed, don't verify.
-          &opened_dex_files_map,
-          &opened_dex_files);
-      ASSERT_TRUE(dex_files_ok);
+      {
+        bool dex_files_ok = oat_writer.WriteAndOpenDexFiles(
+            kIsVdexEnabled ? vdex_file.GetFile() : oat_file.GetFile(),
+            oat_rodata,
+            compiler_driver_->GetInstructionSet(),
+            compiler_driver_->GetInstructionSetFeatures(),
+            &key_value_store,
+            /* verify */ false,           // Dex files may be dex-to-dex-ed, don't verify.
+            &opened_dex_files_map,
+            &opened_dex_files);
+        ASSERT_TRUE(dex_files_ok);
+      }
 
       bool image_space_ok = writer->PrepareImageAddressSpace();
       ASSERT_TRUE(image_space_ok);
@@ -138,17 +142,17 @@
                                               instruction_set_features_.get());
       oat_writer.PrepareLayout(compiler_driver_.get(), writer.get(), dex_files, &patcher);
       size_t rodata_size = oat_writer.GetOatHeader().GetExecutableOffset();
-      size_t text_size = oat_writer.GetSize() - rodata_size;
+      size_t text_size = oat_writer.GetOatSize() - rodata_size;
       elf_writer->SetLoadedSectionSizes(rodata_size, text_size, oat_writer.GetBssSize());
 
       writer->UpdateOatFileLayout(/* oat_index */ 0u,
                                   elf_writer->GetLoadedSize(),
                                   oat_writer.GetOatDataOffset(),
-                                  oat_writer.GetSize());
+                                  oat_writer.GetOatSize());
 
-      bool rodata_ok = oat_writer.WriteRodata(rodata);
+      bool rodata_ok = oat_writer.WriteRodata(oat_rodata);
       ASSERT_TRUE(rodata_ok);
-      elf_writer->EndRoData(rodata);
+      elf_writer->EndRoData(oat_rodata);
 
       OutputStream* text = elf_writer->StartText();
       bool text_ok = oat_writer.WriteCode(text);
@@ -285,6 +289,7 @@
 
   image_file.Unlink();
   oat_file.Unlink();
+  vdex_file.Unlink();
   int rmdir_result = rmdir(image_dir.c_str());
   CHECK_EQ(0, rmdir_result);
 }
diff --git a/compiler/image_writer.cc b/compiler/image_writer.cc
index 7634510..6d86f7d 100644
--- a/compiler/image_writer.cc
+++ b/compiler/image_writer.cc
@@ -868,7 +868,7 @@
   // Clear references to removed classes from the DexCaches.
   ArtMethod* resolution_method = runtime->GetResolutionMethod();
 
-  ScopedAssertNoThreadSuspension sa(self, __FUNCTION__);
+  ScopedAssertNoThreadSuspension sa(__FUNCTION__);
   ReaderMutexLock mu(self, *Locks::classlinker_classes_lock_);  // For ClassInClassTable
   ReaderMutexLock mu2(self, *class_linker->DexLock());
   for (const ClassLinker::DexCacheData& data : class_linker->GetDexCachesData()) {
diff --git a/compiler/jni/quick/calling_convention.h b/compiler/jni/quick/calling_convention.h
index 3d89146..f541d8f 100644
--- a/compiler/jni/quick/calling_convention.h
+++ b/compiler/jni/quick/calling_convention.h
@@ -18,11 +18,11 @@
 #define ART_COMPILER_JNI_QUICK_CALLING_CONVENTION_H_
 
 #include "base/arena_object.h"
+#include "base/array_ref.h"
 #include "base/enums.h"
 #include "handle_scope.h"
 #include "primitive.h"
 #include "thread.h"
-#include "utils/array_ref.h"
 #include "utils/managed_register.h"
 
 namespace art {
diff --git a/compiler/linker/arm64/relative_patcher_arm64.h b/compiler/linker/arm64/relative_patcher_arm64.h
index 48ad105..a4a8018 100644
--- a/compiler/linker/arm64/relative_patcher_arm64.h
+++ b/compiler/linker/arm64/relative_patcher_arm64.h
@@ -17,8 +17,8 @@
 #ifndef ART_COMPILER_LINKER_ARM64_RELATIVE_PATCHER_ARM64_H_
 #define ART_COMPILER_LINKER_ARM64_RELATIVE_PATCHER_ARM64_H_
 
+#include "base/array_ref.h"
 #include "linker/arm/relative_patcher_arm_base.h"
-#include "utils/array_ref.h"
 
 namespace art {
 namespace linker {
diff --git a/compiler/linker/relative_patcher.h b/compiler/linker/relative_patcher.h
index a22b9f2..15e955b 100644
--- a/compiler/linker/relative_patcher.h
+++ b/compiler/linker/relative_patcher.h
@@ -21,9 +21,9 @@
 
 #include "arch/instruction_set.h"
 #include "arch/instruction_set_features.h"
+#include "base/array_ref.h"
 #include "base/macros.h"
 #include "method_reference.h"
-#include "utils/array_ref.h"
 
 namespace art {
 
diff --git a/compiler/linker/relative_patcher_test.h b/compiler/linker/relative_patcher_test.h
index d21f33e..304b31c 100644
--- a/compiler/linker/relative_patcher_test.h
+++ b/compiler/linker/relative_patcher_test.h
@@ -19,6 +19,7 @@
 
 #include "arch/instruction_set.h"
 #include "arch/instruction_set_features.h"
+#include "base/array_ref.h"
 #include "base/macros.h"
 #include "compiled_method.h"
 #include "dex/quick/dex_file_to_method_inliner_map.h"
@@ -31,7 +32,6 @@
 #include "method_reference.h"
 #include "oat.h"
 #include "oat_quick_method_header.h"
-#include "utils/array_ref.h"
 #include "vector_output_stream.h"
 
 namespace art {
diff --git a/compiler/oat_test.cc b/compiler/oat_test.cc
index b1e3811..24d102d 100644
--- a/compiler/oat_test.cc
+++ b/compiler/oat_test.cc
@@ -125,7 +125,8 @@
                                               /* profile_compilation_info */ nullptr));
   }
 
-  bool WriteElf(File* file,
+  bool WriteElf(File* vdex_file,
+                File* oat_file,
                 const std::vector<const DexFile*>& dex_files,
                 SafeMap<std::string, std::string>& key_value_store,
                 bool verify) {
@@ -141,10 +142,11 @@
         return false;
       }
     }
-    return DoWriteElf(file, oat_writer, key_value_store, verify);
+    return DoWriteElf(vdex_file, oat_file, oat_writer, key_value_store, verify);
   }
 
-  bool WriteElf(File* file,
+  bool WriteElf(File* vdex_file,
+                File* oat_file,
                 const std::vector<const char*>& dex_filenames,
                 SafeMap<std::string, std::string>& key_value_store,
                 bool verify) {
@@ -155,10 +157,11 @@
         return false;
       }
     }
-    return DoWriteElf(file, oat_writer, key_value_store, verify);
+    return DoWriteElf(vdex_file, oat_file, oat_writer, key_value_store, verify);
   }
 
-  bool WriteElf(File* file,
+  bool WriteElf(File* vdex_file,
+                File* oat_file,
                 File&& zip_fd,
                 const char* location,
                 SafeMap<std::string, std::string>& key_value_store,
@@ -168,10 +171,11 @@
     if (!oat_writer.AddZippedDexFilesSource(std::move(zip_fd), location)) {
       return false;
     }
-    return DoWriteElf(file, oat_writer, key_value_store, verify);
+    return DoWriteElf(vdex_file, oat_file, oat_writer, key_value_store, verify);
   }
 
-  bool DoWriteElf(File* file,
+  bool DoWriteElf(File* vdex_file,
+                  File* oat_file,
                   OatWriter& oat_writer,
                   SafeMap<std::string, std::string>& key_value_store,
                   bool verify) {
@@ -179,13 +183,13 @@
         compiler_driver_->GetInstructionSet(),
         compiler_driver_->GetInstructionSetFeatures(),
         &compiler_driver_->GetCompilerOptions(),
-        file);
+        oat_file);
     elf_writer->Start();
-    OutputStream* rodata = elf_writer->StartRoData();
+    OutputStream* oat_rodata = elf_writer->StartRoData();
     std::unique_ptr<MemMap> opened_dex_files_map;
     std::vector<std::unique_ptr<const DexFile>> opened_dex_files;
-    if (!oat_writer.WriteAndOpenDexFiles(rodata,
-                                         file,
+    if (!oat_writer.WriteAndOpenDexFiles(kIsVdexEnabled ? vdex_file : oat_file,
+                                         oat_rodata,
                                          compiler_driver_->GetInstructionSet(),
                                          compiler_driver_->GetInstructionSetFeatures(),
                                          &key_value_store,
@@ -206,13 +210,13 @@
                                             instruction_set_features_.get());
     oat_writer.PrepareLayout(compiler_driver_.get(), nullptr, dex_files, &patcher);
     size_t rodata_size = oat_writer.GetOatHeader().GetExecutableOffset();
-    size_t text_size = oat_writer.GetSize() - rodata_size;
+    size_t text_size = oat_writer.GetOatSize() - rodata_size;
     elf_writer->SetLoadedSectionSizes(rodata_size, text_size, oat_writer.GetBssSize());
 
-    if (!oat_writer.WriteRodata(rodata)) {
+    if (!oat_writer.WriteRodata(oat_rodata)) {
       return false;
     }
-    elf_writer->EndRoData(rodata);
+    elf_writer->EndRoData(oat_rodata);
 
     OutputStream* text = elf_writer->StartText();
     if (!oat_writer.WriteCode(text)) {
@@ -366,17 +370,21 @@
     compiler_driver_->CompileAll(class_loader, class_linker->GetBootClassPath(), &timings2);
   }
 
-  ScratchFile tmp;
+  ScratchFile tmp_oat, tmp_vdex(tmp_oat, ".vdex");
   SafeMap<std::string, std::string> key_value_store;
   key_value_store.Put(OatHeader::kImageLocationKey, "lue.art");
-  bool success = WriteElf(tmp.GetFile(), class_linker->GetBootClassPath(), key_value_store, false);
+  bool success = WriteElf(tmp_vdex.GetFile(),
+                          tmp_oat.GetFile(),
+                          class_linker->GetBootClassPath(),
+                          key_value_store,
+                          false);
   ASSERT_TRUE(success);
 
   if (kCompile) {  // OatWriter strips the code, regenerate to compare
     compiler_driver_->CompileAll(class_loader, class_linker->GetBootClassPath(), &timings);
   }
-  std::unique_ptr<OatFile> oat_file(OatFile::Open(tmp.GetFilename(),
-                                                  tmp.GetFilename(),
+  std::unique_ptr<OatFile> oat_file(OatFile::Open(tmp_oat.GetFilename(),
+                                                  tmp_oat.GetFilename(),
                                                   nullptr,
                                                   nullptr,
                                                   false,
@@ -445,7 +453,7 @@
   EXPECT_EQ(72U, sizeof(OatHeader));
   EXPECT_EQ(4U, sizeof(OatMethodOffsets));
   EXPECT_EQ(20U, sizeof(OatQuickMethodHeader));
-  EXPECT_EQ(164 * static_cast<size_t>(GetInstructionSetPointerSize(kRuntimeISA)),
+  EXPECT_EQ(163 * static_cast<size_t>(GetInstructionSetPointerSize(kRuntimeISA)),
             sizeof(QuickEntryPoints));
 }
 
@@ -498,14 +506,14 @@
   compiler_driver_->SetDexFilesForOatFile(dex_files);
   compiler_driver_->CompileAll(class_loader, dex_files, &timings);
 
-  ScratchFile tmp;
+  ScratchFile tmp_oat, tmp_vdex(tmp_oat, ".vdex");
   SafeMap<std::string, std::string> key_value_store;
   key_value_store.Put(OatHeader::kImageLocationKey, "test.art");
-  bool success = WriteElf(tmp.GetFile(), dex_files, key_value_store, false);
+  bool success = WriteElf(tmp_vdex.GetFile(), tmp_oat.GetFile(), dex_files, key_value_store, false);
   ASSERT_TRUE(success);
 
-  std::unique_ptr<OatFile> oat_file(OatFile::Open(tmp.GetFilename(),
-                                                  tmp.GetFilename(),
+  std::unique_ptr<OatFile> oat_file(OatFile::Open(tmp_oat.GetFilename(),
+                                                  tmp_oat.GetFilename(),
                                                   nullptr,
                                                   nullptr,
                                                   false,
@@ -513,7 +521,8 @@
                                                   nullptr,
                                                   &error_msg));
   ASSERT_TRUE(oat_file != nullptr);
-  EXPECT_LT(static_cast<size_t>(oat_file->Size()), static_cast<size_t>(tmp.GetFile()->GetLength()));
+  EXPECT_LT(static_cast<size_t>(oat_file->Size()),
+            static_cast<size_t>(tmp_oat.GetFile()->GetLength()));
 }
 
 static void MaybeModifyDexFileToFail(bool verify, std::unique_ptr<const DexFile>& data) {
@@ -559,10 +568,14 @@
   ASSERT_TRUE(success);
   input_filenames.push_back(dex_file2.GetFilename().c_str());
 
-  ScratchFile oat_file;
+  ScratchFile oat_file, vdex_file(oat_file, ".vdex");
   SafeMap<std::string, std::string> key_value_store;
   key_value_store.Put(OatHeader::kImageLocationKey, "test.art");
-  success = WriteElf(oat_file.GetFile(), input_filenames, key_value_store, verify);
+  success = WriteElf(vdex_file.GetFile(),
+                     oat_file.GetFile(),
+                     input_filenames,
+                     key_value_store,
+                     verify);
 
   // In verify mode, we expect failure.
   if (verify) {
@@ -668,8 +681,9 @@
     // Test using the AddDexFileSource() interface with the zip file.
     std::vector<const char*> input_filenames { zip_file.GetFilename().c_str() };  // NOLINT [readability/braces] [4]
 
-    ScratchFile oat_file;
-    success = WriteElf(oat_file.GetFile(), input_filenames, key_value_store, verify);
+    ScratchFile oat_file, vdex_file(oat_file, ".vdex");
+    success = WriteElf(vdex_file.GetFile(), oat_file.GetFile(),
+                       input_filenames, key_value_store, verify);
 
     if (verify) {
       ASSERT_FALSE(success);
@@ -713,8 +727,9 @@
     File zip_fd(dup(zip_file.GetFd()), /* check_usage */ false);
     ASSERT_NE(-1, zip_fd.Fd());
 
-    ScratchFile oat_file;
-    success = WriteElf(oat_file.GetFile(),
+    ScratchFile oat_file, vdex_file(oat_file, ".vdex");
+    success = WriteElf(vdex_file.GetFile(),
+                       oat_file.GetFile(),
                        std::move(zip_fd),
                        zip_file.GetFilename().c_str(),
                        key_value_store,
diff --git a/compiler/oat_writer.cc b/compiler/oat_writer.cc
index c9c5d24..5e0c64b 100644
--- a/compiler/oat_writer.cc
+++ b/compiler/oat_writer.cc
@@ -39,6 +39,8 @@
 #include "gc/space/space.h"
 #include "handle_scope-inl.h"
 #include "image_writer.h"
+#include "linker/buffered_output_stream.h"
+#include "linker/file_output_stream.h"
 #include "linker/multi_oat_relative_patcher.h"
 #include "linker/output_stream.h"
 #include "mirror/array.h"
@@ -51,6 +53,7 @@
 #include "scoped_thread_state_change.h"
 #include "type_lookup_table.h"
 #include "utils/dex_cache_arrays_layout-inl.h"
+#include "vdex_file.h"
 #include "verifier/method_verifier.h"
 #include "zip_archive.h"
 
@@ -283,10 +286,13 @@
     image_writer_(nullptr),
     compiling_boot_image_(compiling_boot_image),
     dex_files_(nullptr),
-    size_(0u),
+    vdex_size_(0u),
+    vdex_dex_files_offset_(0u),
+    oat_size_(0u),
     bss_size_(0u),
     oat_data_offset_(0u),
     oat_header_(nullptr),
+    size_vdex_header_(0),
     size_dex_file_alignment_(0),
     size_executable_offset_alignment_(0),
     size_oat_header_(0),
@@ -421,8 +427,8 @@
 }
 
 bool OatWriter::WriteAndOpenDexFiles(
-    OutputStream* rodata,
-    File* file,
+    File* vdex_file,
+    OutputStream* oat_rodata,
     InstructionSet instruction_set,
     const InstructionSetFeatures* instruction_set_features,
     SafeMap<std::string, std::string>* key_value_store,
@@ -431,37 +437,67 @@
     /*out*/ std::vector<std::unique_ptr<const DexFile>>* opened_dex_files) {
   CHECK(write_state_ == WriteState::kAddingDexFileSources);
 
-  size_t offset = InitOatHeader(instruction_set,
-                                instruction_set_features,
-                                dchecked_integral_cast<uint32_t>(oat_dex_files_.size()),
-                                key_value_store);
-  size_ = InitOatDexFiles(offset);
+  // Record the ELF rodata section offset, i.e. the beginning of the OAT data.
+  if (!RecordOatDataOffset(oat_rodata)) {
+     return false;
+  }
 
   std::unique_ptr<MemMap> dex_files_map;
   std::vector<std::unique_ptr<const DexFile>> dex_files;
-  if (!WriteDexFiles(rodata, file) ||
-      !OpenDexFiles(file, verify, &dex_files_map, &dex_files)) {
-    return false;
+
+  // Initialize VDEX and OAT headers.
+  if (kIsVdexEnabled) {
+    size_vdex_header_ = sizeof(VdexFile::Header);
+    vdex_size_ = size_vdex_header_;
+  }
+  size_t oat_data_offset = InitOatHeader(instruction_set,
+                                        instruction_set_features,
+                                        dchecked_integral_cast<uint32_t>(oat_dex_files_.size()),
+                                        key_value_store);
+  oat_size_ = InitOatDexFiles(oat_data_offset);
+
+  ChecksumUpdatingOutputStream checksum_updating_rodata(oat_rodata, oat_header_.get());
+
+  if (kIsVdexEnabled) {
+    std::unique_ptr<BufferedOutputStream> vdex_out(
+        MakeUnique<BufferedOutputStream>(MakeUnique<FileOutputStream>(vdex_file)));
+
+    // Write DEX files into VDEX, mmap and open them.
+    if (!WriteDexFiles(vdex_out.get(), vdex_file) ||
+        !OpenDexFiles(vdex_file, verify, &dex_files_map, &dex_files)) {
+      return false;
+    }
+
+    // VDEX is finalized. Seek to the beginning of the file and write the header.
+    if (!WriteVdexHeader(vdex_out.get())) {
+      return false;
+    }
+  } else {
+    // Write DEX files into OAT, mmap and open them.
+    if (!WriteDexFiles(oat_rodata, vdex_file) ||
+        !OpenDexFiles(vdex_file, verify, &dex_files_map, &dex_files)) {
+      return false;
+    }
+
+    // Do a bulk checksum update for Dex[]. Doing it piece by piece would be
+    // difficult because we're not using the OutputStream directly.
+    if (!oat_dex_files_.empty()) {
+      size_t size = oat_size_ - oat_dex_files_[0].dex_file_offset_;
+      oat_header_->UpdateChecksum(dex_files_map->Begin(), size);
+    }
   }
 
-  // Do a bulk checksum update for Dex[]. Doing it piece by piece would be
-  // difficult because we're not using the OutputStream directly.
-  if (!oat_dex_files_.empty()) {
-    size_t size = size_ - oat_dex_files_[0].dex_file_offset_;
-    oat_header_->UpdateChecksum(dex_files_map->Begin(), size);
-  }
-
-  ChecksumUpdatingOutputStream checksum_updating_rodata(rodata, oat_header_.get());
-
+  // Write TypeLookupTables into OAT.
   if (!WriteTypeLookupTables(&checksum_updating_rodata, dex_files)) {
     return false;
   }
 
-  // Reserve space for class offsets and update class_offsets_offset_.
+  // Reserve space for class offsets in OAT and update class_offsets_offset_.
   for (OatDexFile& oat_dex_file : oat_dex_files_) {
     oat_dex_file.ReserveClassOffsets(this);
   }
 
+  // Write OatDexFiles into OAT. Needs to be done last, once offsets are collected.
   if (!WriteOatDexFiles(&checksum_updating_rodata)) {
     return false;
   }
@@ -490,7 +526,7 @@
   InstructionSet instruction_set = compiler_driver_->GetInstructionSet();
   CHECK_EQ(instruction_set, oat_header_->GetInstructionSet());
 
-  uint32_t offset = size_;
+  uint32_t offset = oat_size_;
   {
     TimingLogger::ScopedTiming split("InitOatClasses", timings_);
     offset = InitOatClasses(offset);
@@ -507,11 +543,11 @@
     TimingLogger::ScopedTiming split("InitOatCodeDexFiles", timings_);
     offset = InitOatCodeDexFiles(offset);
   }
-  size_ = offset;
+  oat_size_ = offset;
 
   if (!HasBootImage()) {
     // Allocate space for app dex cache arrays in the .bss section.
-    size_t bss_start = RoundUp(size_, kPageSize);
+    size_t bss_start = RoundUp(oat_size_, kPageSize);
     PointerSize pointer_size = GetInstructionSetPointerSize(instruction_set);
     bss_size_ = 0u;
     for (const DexFile* dex_file : *dex_files_) {
@@ -958,7 +994,7 @@
       out_(out),
       file_offset_(file_offset),
       soa_(Thread::Current()),
-      no_thread_suspension_(soa_.Self(), "OatWriter patching"),
+      no_thread_suspension_("OatWriter patching"),
       class_linker_(Runtime::Current()->GetClassLinker()),
       dex_cache_(nullptr) {
     patched_code_.reserve(16 * KB);
@@ -1000,7 +1036,7 @@
     const CompiledMethod* compiled_method = oat_class->GetCompiledMethod(class_def_method_index);
 
     // No thread suspension since dex_cache_ that may get invalidated if that occurs.
-    ScopedAssertNoThreadSuspension tsc(Thread::Current(), __FUNCTION__);
+    ScopedAssertNoThreadSuspension tsc(__FUNCTION__);
     if (compiled_method != nullptr) {  // ie. not an abstract method
       size_t file_offset = file_offset_;
       OutputStream* out = out_;
@@ -1587,6 +1623,7 @@
       VLOG(compiler) << #x "=" << PrettySize(x) << " (" << (x) << "B)"; \
       size_total += (x);
 
+    DO_STAT(size_vdex_header_);
     DO_STAT(size_dex_file_alignment_);
     DO_STAT(size_executable_offset_alignment_);
     DO_STAT(size_oat_header_);
@@ -1622,13 +1659,14 @@
     DO_STAT(size_oat_class_method_offsets_);
     #undef DO_STAT
 
-    VLOG(compiler) << "size_total=" << PrettySize(size_total) << " (" << size_total << "B)"; \
-    CHECK_EQ(file_offset + size_total, static_cast<size_t>(oat_end_file_offset));
-    CHECK_EQ(size_, size_total);
+    VLOG(compiler) << "size_total=" << PrettySize(size_total) << " (" << size_total << "B)";
+
+    CHECK_EQ(vdex_size_ + oat_size_, size_total);
+    CHECK_EQ(file_offset + size_total - vdex_size_, static_cast<size_t>(oat_end_file_offset));
   }
 
-  CHECK_EQ(file_offset + size_, static_cast<size_t>(oat_end_file_offset));
-  CHECK_EQ(size_, relative_offset);
+  CHECK_EQ(file_offset + oat_size_, static_cast<size_t>(oat_end_file_offset));
+  CHECK_EQ(oat_size_, relative_offset);
 
   write_state_ = WriteState::kWriteHeader;
   return true;
@@ -1831,17 +1869,14 @@
   return true;
 }
 
-bool OatWriter::WriteDexFiles(OutputStream* rodata, File* file) {
-  TimingLogger::ScopedTiming split("WriteDexFiles", timings_);
+bool OatWriter::WriteDexFiles(OutputStream* out, File* file) {
+  TimingLogger::ScopedTiming split("Write Dex files", timings_);
 
-  // Get the elf file offset of the oat file.
-  if (!RecordOatDataOffset(rodata)) {
-    return false;
-  }
+  vdex_dex_files_offset_ = vdex_size_;
 
   // Write dex files.
   for (OatDexFile& oat_dex_file : oat_dex_files_) {
-    if (!WriteDexFile(rodata, file, &oat_dex_file)) {
+    if (!WriteDexFile(out, file, &oat_dex_file)) {
       return false;
     }
   }
@@ -1856,45 +1891,50 @@
   return true;
 }
 
-bool OatWriter::WriteDexFile(OutputStream* rodata, File* file, OatDexFile* oat_dex_file) {
-  if (!SeekToDexFile(rodata, file, oat_dex_file)) {
+bool OatWriter::WriteDexFile(OutputStream* out, File* file, OatDexFile* oat_dex_file) {
+  if (!SeekToDexFile(out, file, oat_dex_file)) {
     return false;
   }
   if (oat_dex_file->source_.IsZipEntry()) {
-    if (!WriteDexFile(rodata, file, oat_dex_file, oat_dex_file->source_.GetZipEntry())) {
+    if (!WriteDexFile(out, file, oat_dex_file, oat_dex_file->source_.GetZipEntry())) {
       return false;
     }
   } else if (oat_dex_file->source_.IsRawFile()) {
-    if (!WriteDexFile(rodata, file, oat_dex_file, oat_dex_file->source_.GetRawFile())) {
+    if (!WriteDexFile(out, file, oat_dex_file, oat_dex_file->source_.GetRawFile())) {
       return false;
     }
   } else {
     DCHECK(oat_dex_file->source_.IsRawData());
-    if (!WriteDexFile(rodata, oat_dex_file, oat_dex_file->source_.GetRawData())) {
+    if (!WriteDexFile(out, oat_dex_file, oat_dex_file->source_.GetRawData())) {
       return false;
     }
   }
 
   // Update current size and account for the written data.
-  DCHECK_EQ(size_, oat_dex_file->dex_file_offset_);
-  size_ += oat_dex_file->dex_file_size_;
+  if (kIsVdexEnabled) {
+    DCHECK_EQ(vdex_size_, oat_dex_file->dex_file_offset_);
+    vdex_size_ += oat_dex_file->dex_file_size_;
+  } else {
+    DCHECK_EQ(oat_size_, oat_dex_file->dex_file_offset_);
+    oat_size_ += oat_dex_file->dex_file_size_;
+  }
   size_dex_file_ += oat_dex_file->dex_file_size_;
   return true;
 }
 
 bool OatWriter::SeekToDexFile(OutputStream* out, File* file, OatDexFile* oat_dex_file) {
   // Dex files are required to be 4 byte aligned.
-  size_t original_offset = size_;
-  size_t offset = RoundUp(original_offset, 4);
-  size_dex_file_alignment_ += offset - original_offset;
+  size_t initial_offset = kIsVdexEnabled ? vdex_size_ : oat_size_;
+  size_t start_offset = RoundUp(initial_offset, 4);
+  size_t file_offset = kIsVdexEnabled ? start_offset : (oat_data_offset_ + start_offset);
+  size_dex_file_alignment_ += start_offset - initial_offset;
 
   // Seek to the start of the dex file and flush any pending operations in the stream.
   // Verify that, after flushing the stream, the file is at the same offset as the stream.
-  uint32_t start_offset = oat_data_offset_ + offset;
-  off_t actual_offset = out->Seek(start_offset, kSeekSet);
-  if (actual_offset != static_cast<off_t>(start_offset)) {
+  off_t actual_offset = out->Seek(file_offset, kSeekSet);
+  if (actual_offset != static_cast<off_t>(file_offset)) {
     PLOG(ERROR) << "Failed to seek to dex file section. Actual: " << actual_offset
-                << " Expected: " << start_offset
+                << " Expected: " << file_offset
                 << " File: " << oat_dex_file->GetLocation() << " Output: " << file->GetPath();
     return false;
   }
@@ -1904,24 +1944,28 @@
     return false;
   }
   actual_offset = lseek(file->Fd(), 0, SEEK_CUR);
-  if (actual_offset != static_cast<off_t>(start_offset)) {
+  if (actual_offset != static_cast<off_t>(file_offset)) {
     PLOG(ERROR) << "Stream/file position mismatch! Actual: " << actual_offset
-                << " Expected: " << start_offset
+                << " Expected: " << file_offset
                 << " File: " << oat_dex_file->GetLocation() << " Output: " << file->GetPath();
     return false;
   }
 
-  size_ = offset;
-  oat_dex_file->dex_file_offset_ = offset;
+  if (kIsVdexEnabled) {
+    vdex_size_ = start_offset;
+  } else {
+    oat_size_ = start_offset;
+  }
+  oat_dex_file->dex_file_offset_ = start_offset;
   return true;
 }
 
-bool OatWriter::WriteDexFile(OutputStream* rodata,
+bool OatWriter::WriteDexFile(OutputStream* out,
                              File* file,
                              OatDexFile* oat_dex_file,
                              ZipEntry* dex_file) {
-  size_t start_offset = oat_data_offset_ + size_;
-  DCHECK_EQ(static_cast<off_t>(start_offset), rodata->Seek(0, kSeekCurrent));
+  size_t start_offset = kIsVdexEnabled ? vdex_size_ : oat_data_offset_ + oat_size_;
+  DCHECK_EQ(static_cast<off_t>(start_offset), out->Seek(0, kSeekCurrent));
 
   // Extract the dex file and get the extracted size.
   std::string error_msg;
@@ -1984,13 +2028,13 @@
                 << " File: " << oat_dex_file->GetLocation() << " Output: " << file->GetPath();
     return false;
   }
-  actual_offset = rodata->Seek(end_offset, kSeekSet);
+  actual_offset = out->Seek(end_offset, kSeekSet);
   if (actual_offset != static_cast<off_t>(end_offset)) {
     PLOG(ERROR) << "Failed to seek stream to end of dex file. Actual: " << actual_offset
                 << " Expected: " << end_offset << " File: " << oat_dex_file->GetLocation();
     return false;
   }
-  if (!rodata->Flush()) {
+  if (!out->Flush()) {
     PLOG(ERROR) << "Failed to flush stream after seeking over dex file."
                 << " File: " << oat_dex_file->GetLocation() << " Output: " << file->GetPath();
     return false;
@@ -2000,7 +2044,8 @@
   if (extracted_size > oat_dex_file->dex_file_size_) {
     if (file->SetLength(end_offset) != 0) {
       PLOG(ERROR) << "Failed to truncate excessive dex file length."
-                  << " File: " << oat_dex_file->GetLocation() << " Output: " << file->GetPath();
+                  << " File: " << oat_dex_file->GetLocation()
+                  << " Output: " << file->GetPath();
       return false;
     }
   }
@@ -2008,12 +2053,12 @@
   return true;
 }
 
-bool OatWriter::WriteDexFile(OutputStream* rodata,
+bool OatWriter::WriteDexFile(OutputStream* out,
                              File* file,
                              OatDexFile* oat_dex_file,
                              File* dex_file) {
-  size_t start_offset = oat_data_offset_ + size_;
-  DCHECK_EQ(static_cast<off_t>(start_offset), rodata->Seek(0, kSeekCurrent));
+  size_t start_offset = kIsVdexEnabled ? vdex_size_ : oat_data_offset_ + oat_size_;
+  DCHECK_EQ(static_cast<off_t>(start_offset), out->Seek(0, kSeekCurrent));
 
   off_t input_offset = lseek(dex_file->Fd(), 0, SEEK_SET);
   if (input_offset != static_cast<off_t>(0)) {
@@ -2047,13 +2092,13 @@
                 << " File: " << oat_dex_file->GetLocation() << " Output: " << file->GetPath();
     return false;
   }
-  actual_offset = rodata->Seek(end_offset, kSeekSet);
+  actual_offset = out->Seek(end_offset, kSeekSet);
   if (actual_offset != static_cast<off_t>(end_offset)) {
     PLOG(ERROR) << "Failed to seek stream to end of dex file. Actual: " << actual_offset
                 << " Expected: " << end_offset << " File: " << oat_dex_file->GetLocation();
     return false;
   }
-  if (!rodata->Flush()) {
+  if (!out->Flush()) {
     PLOG(ERROR) << "Failed to flush stream after seeking over dex file."
                 << " File: " << oat_dex_file->GetLocation() << " Output: " << file->GetPath();
     return false;
@@ -2062,7 +2107,7 @@
   return true;
 }
 
-bool OatWriter::WriteDexFile(OutputStream* rodata,
+bool OatWriter::WriteDexFile(OutputStream* out,
                              OatDexFile* oat_dex_file,
                              const uint8_t* dex_file) {
   // Note: The raw data has already been checked to contain the header
@@ -2071,12 +2116,12 @@
   DCHECK(ValidateDexFileHeader(dex_file, oat_dex_file->GetLocation()));
   const UnalignedDexFileHeader* header = AsUnalignedDexFileHeader(dex_file);
 
-  if (!rodata->WriteFully(dex_file, header->file_size_)) {
+  if (!out->WriteFully(dex_file, header->file_size_)) {
     PLOG(ERROR) << "Failed to write dex file " << oat_dex_file->GetLocation()
-                << " to " << rodata->GetLocation();
+                << " to " << out->GetLocation();
     return false;
   }
-  if (!rodata->Flush()) {
+  if (!out->Flush()) {
     PLOG(ERROR) << "Failed to flush stream after writing dex file."
                 << " File: " << oat_dex_file->GetLocation();
     return false;
@@ -2146,16 +2191,18 @@
   }
 
   size_t map_offset = oat_dex_files_[0].dex_file_offset_;
-  size_t length = size_ - map_offset;
+  size_t length = kIsVdexEnabled ? (vdex_size_ - map_offset) : (oat_size_ - map_offset);
+
   std::string error_msg;
-  std::unique_ptr<MemMap> dex_files_map(MemMap::MapFile(length,
-                                                        PROT_READ | PROT_WRITE,
-                                                        MAP_SHARED,
-                                                        file->Fd(),
-                                                        oat_data_offset_ + map_offset,
-                                                        /* low_4gb */ false,
-                                                        file->GetPath().c_str(),
-                                                        &error_msg));
+  std::unique_ptr<MemMap> dex_files_map(MemMap::MapFile(
+      length,
+      PROT_READ | PROT_WRITE,
+      MAP_SHARED,
+      file->Fd(),
+      kIsVdexEnabled ? map_offset : (oat_data_offset_ + map_offset),
+      /* low_4gb */ false,
+      file->GetPath().c_str(),
+      &error_msg));
   if (dex_files_map == nullptr) {
     LOG(ERROR) << "Failed to mmap() dex files from oat file. File: " << file->GetPath()
                << " error: " << error_msg;
@@ -2210,10 +2257,18 @@
 }
 
 bool OatWriter::WriteTypeLookupTables(
-    OutputStream* rodata,
+    OutputStream* oat_rodata,
     const std::vector<std::unique_ptr<const DexFile>>& opened_dex_files) {
   TimingLogger::ScopedTiming split("WriteTypeLookupTables", timings_);
 
+  uint32_t expected_offset = oat_data_offset_ + oat_size_;
+  off_t actual_offset = oat_rodata->Seek(expected_offset, kSeekSet);
+  if (static_cast<uint32_t>(actual_offset) != expected_offset) {
+    PLOG(ERROR) << "Failed to seek to TypeLookupTable section. Actual: " << actual_offset
+                << " Expected: " << expected_offset << " File: " << oat_rodata->GetLocation();
+    return false;
+  }
+
   DCHECK_EQ(opened_dex_files.size(), oat_dex_files_.size());
   for (size_t i = 0, size = opened_dex_files.size(); i != size; ++i) {
     OatDexFile* oat_dex_file = &oat_dex_files_[i];
@@ -2235,41 +2290,58 @@
     TypeLookupTable* table = opened_dex_files[i]->GetTypeLookupTable();
 
     // Type tables are required to be 4 byte aligned.
-    size_t original_offset = size_;
-    size_t rodata_offset = RoundUp(original_offset, 4);
-    size_t padding_size = rodata_offset - original_offset;
+    size_t initial_offset = oat_size_;
+    size_t rodata_offset = RoundUp(initial_offset, 4);
+    size_t padding_size = rodata_offset - initial_offset;
 
     if (padding_size != 0u) {
       std::vector<uint8_t> buffer(padding_size, 0u);
-      if (!rodata->WriteFully(buffer.data(), padding_size)) {
+      if (!oat_rodata->WriteFully(buffer.data(), padding_size)) {
         PLOG(ERROR) << "Failed to write lookup table alignment padding."
                     << " File: " << oat_dex_file->GetLocation()
-                    << " Output: " << rodata->GetLocation();
+                    << " Output: " << oat_rodata->GetLocation();
         return false;
       }
     }
 
     DCHECK_EQ(oat_data_offset_ + rodata_offset,
-              static_cast<size_t>(rodata->Seek(0u, kSeekCurrent)));
+              static_cast<size_t>(oat_rodata->Seek(0u, kSeekCurrent)));
     DCHECK_EQ(table_size, table->RawDataLength());
 
-    if (!rodata->WriteFully(table->RawData(), table_size)) {
+    if (!oat_rodata->WriteFully(table->RawData(), table_size)) {
       PLOG(ERROR) << "Failed to write lookup table."
                   << " File: " << oat_dex_file->GetLocation()
-                  << " Output: " << rodata->GetLocation();
+                  << " Output: " << oat_rodata->GetLocation();
       return false;
     }
 
     oat_dex_file->lookup_table_offset_ = rodata_offset;
 
-    size_ += padding_size + table_size;
+    oat_size_ += padding_size + table_size;
     size_oat_lookup_table_ += table_size;
     size_oat_lookup_table_alignment_ += padding_size;
   }
 
-  if (!rodata->Flush()) {
+  if (!oat_rodata->Flush()) {
     PLOG(ERROR) << "Failed to flush stream after writing type lookup tables."
-                << " File: " << rodata->GetLocation();
+                << " File: " << oat_rodata->GetLocation();
+    return false;
+  }
+
+  return true;
+}
+
+bool OatWriter::WriteVdexHeader(OutputStream* vdex_out) {
+  off_t actual_offset = vdex_out->Seek(0, kSeekSet);
+  if (actual_offset != 0) {
+    PLOG(ERROR) << "Failed to seek to the beginning of vdex file. Actual: " << actual_offset
+                << " File: " << vdex_out->GetLocation();
+    return false;
+  }
+
+  VdexFile::Header vdex_header;
+  if (!vdex_out->WriteFully(&vdex_header, sizeof(VdexFile::Header))) {
+    PLOG(ERROR) << "Failed to write vdex header. File: " << vdex_out->GetLocation();
     return false;
   }
 
@@ -2329,11 +2401,11 @@
   DCHECK_EQ(class_offsets_offset_, 0u);
   if (!class_offsets_.empty()) {
     // Class offsets are required to be 4 byte aligned.
-    size_t original_offset = oat_writer->size_;
-    size_t offset = RoundUp(original_offset, 4);
-    oat_writer->size_oat_class_offsets_alignment_ += offset - original_offset;
+    size_t initial_offset = oat_writer->oat_size_;
+    size_t offset = RoundUp(initial_offset, 4);
+    oat_writer->size_oat_class_offsets_alignment_ += offset - initial_offset;
     class_offsets_offset_ = offset;
-    oat_writer->size_ = offset + GetClassOffsetsRawSize();
+    oat_writer->oat_size_ = offset + GetClassOffsetsRawSize();
   }
 }
 
diff --git a/compiler/oat_writer.h b/compiler/oat_writer.h
index 93e2e44..dd7d699 100644
--- a/compiler/oat_writer.h
+++ b/compiler/oat_writer.h
@@ -21,6 +21,7 @@
 #include <cstddef>
 #include <memory>
 
+#include "base/array_ref.h"
 #include "base/dchecked_vector.h"
 #include "linker/relative_patcher.h"  // For linker::RelativePatcherTargetProvider.
 #include "mem_map.h"
@@ -29,7 +30,6 @@
 #include "oat.h"
 #include "os.h"
 #include "safe_map.h"
-#include "utils/array_ref.h"
 
 namespace art {
 
@@ -57,11 +57,6 @@
 // ...
 // OatDexFile[D]
 //
-// Dex[0]            one variable sized DexFile for each OatDexFile.
-// Dex[1]            these are literal copies of the input .dex files.
-// ...
-// Dex[D]
-//
 // TypeLookupTable[0] one descriptor to class def index hash table for each OatDexFile.
 // TypeLookupTable[1]
 // ...
@@ -142,11 +137,12 @@
       CreateTypeLookupTable create_type_lookup_table = CreateTypeLookupTable::kDefault);
   dchecked_vector<const char*> GetSourceLocations() const;
 
-  // Write raw dex files to the .rodata section and open them from the oat file. The verify
-  // setting dictates whether the dex file verifier should check the dex files. This is generally
-  // the case, and should only be false for tests.
-  bool WriteAndOpenDexFiles(OutputStream* rodata,
-                            File* file,
+  // Write raw dex files to the vdex file, mmap the file and open the dex files from it.
+  // Supporting data structures are written into the .rodata section of the oat file.
+  // The `verify` setting dictates whether the dex file verifier should check the dex files.
+  // This is generally the case, and should only be false for tests.
+  bool WriteAndOpenDexFiles(File* vdex_file,
+                            OutputStream* oat_rodata,
                             InstructionSet instruction_set,
                             const InstructionSetFeatures* instruction_set_features,
                             SafeMap<std::string, std::string>* key_value_store,
@@ -183,8 +179,8 @@
     return *oat_header_;
   }
 
-  size_t GetSize() const {
-    return size_;
+  size_t GetOatSize() const {
+    return oat_size_;
   }
 
   size_t GetBssSize() const {
@@ -236,6 +232,25 @@
   // with a given DexMethodVisitor.
   bool VisitDexMethods(DexMethodVisitor* visitor);
 
+  bool WriteVdexHeader(OutputStream* vdex_out);
+
+  bool WriteDexFiles(OutputStream* out, File* file);
+  bool WriteDexFile(OutputStream* out, File* file, OatDexFile* oat_dex_file);
+  bool SeekToDexFile(OutputStream* out, File* file, OatDexFile* oat_dex_file);
+  bool WriteDexFile(OutputStream* out,
+                    File* file,
+                    OatDexFile* oat_dex_file,
+                    ZipEntry* dex_file);
+  bool WriteDexFile(OutputStream* out,
+                    File* file,
+                    OatDexFile* oat_dex_file,
+                    File* dex_file);
+  bool WriteDexFile(OutputStream* out, OatDexFile* oat_dex_file, const uint8_t* dex_file);
+  bool OpenDexFiles(File* file,
+                    bool verify,
+                    /*out*/ std::unique_ptr<MemMap>* opened_dex_files_map,
+                    /*out*/ std::vector<std::unique_ptr<const DexFile>>* opened_dex_files);
+
   size_t InitOatHeader(InstructionSet instruction_set,
                        const InstructionSetFeatures* instruction_set_features,
                        uint32_t num_dex_files,
@@ -253,20 +268,10 @@
   size_t WriteCodeDexFiles(OutputStream* out, const size_t file_offset, size_t relative_offset);
 
   bool RecordOatDataOffset(OutputStream* out);
-  bool ReadDexFileHeader(File* file, OatDexFile* oat_dex_file);
+  bool ReadDexFileHeader(File* oat_file, OatDexFile* oat_dex_file);
   bool ValidateDexFileHeader(const uint8_t* raw_header, const char* location);
-  bool WriteDexFiles(OutputStream* rodata, File* file);
-  bool WriteDexFile(OutputStream* rodata, File* file, OatDexFile* oat_dex_file);
-  bool SeekToDexFile(OutputStream* rodata, File* file, OatDexFile* oat_dex_file);
-  bool WriteDexFile(OutputStream* rodata, File* file, OatDexFile* oat_dex_file, ZipEntry* dex_file);
-  bool WriteDexFile(OutputStream* rodata, File* file, OatDexFile* oat_dex_file, File* dex_file);
-  bool WriteDexFile(OutputStream* rodata, OatDexFile* oat_dex_file, const uint8_t* dex_file);
-  bool WriteOatDexFiles(OutputStream* rodata);
-  bool OpenDexFiles(File* file,
-                    bool verify,
-                    /*out*/ std::unique_ptr<MemMap>* opened_dex_files_map,
-                    /*out*/ std::vector<std::unique_ptr<const DexFile>>* opened_dex_files);
-  bool WriteTypeLookupTables(OutputStream* rodata,
+  bool WriteOatDexFiles(OutputStream* oat_rodata);
+  bool WriteTypeLookupTables(OutputStream* oat_rodata,
                              const std::vector<std::unique_ptr<const DexFile>>& opened_dex_files);
   bool WriteCodeAlignment(OutputStream* out, uint32_t aligned_code_delta);
   void SetMultiOatRelativePatcherAdjustment();
@@ -300,8 +305,14 @@
   // note OatFile does not take ownership of the DexFiles
   const std::vector<const DexFile*>* dex_files_;
 
+  // Size required for Vdex data structures.
+  size_t vdex_size_;
+
+  // Offset of section holding Dex files inside Vdex.
+  size_t vdex_dex_files_offset_;
+
   // Size required for Oat data structures.
-  size_t size_;
+  size_t oat_size_;
 
   // The size of the required .bss section holding the DexCache data.
   size_t bss_size_;
@@ -324,6 +335,7 @@
   std::unique_ptr<const std::vector<uint8_t>> quick_to_interpreter_bridge_;
 
   // output stats
+  uint32_t size_vdex_header_;
   uint32_t size_dex_file_alignment_;
   uint32_t size_executable_offset_alignment_;
   uint32_t size_oat_header_;
diff --git a/compiler/optimizing/bounds_check_elimination.cc b/compiler/optimizing/bounds_check_elimination.cc
index 8aefd9e..994d394 100644
--- a/compiler/optimizing/bounds_check_elimination.cc
+++ b/compiler/optimizing/bounds_check_elimination.cc
@@ -887,7 +887,7 @@
       bool needs_finite_test = false;
       bool needs_taken_test = false;
       if (DynamicBCESeemsProfitable(loop, bounds_check->GetBlock()) &&
-          induction_range_.CanGenerateCode(
+          induction_range_.CanGenerateRange(
               bounds_check, index, &needs_finite_test, &needs_taken_test) &&
           CanHandleInfiniteLoop(loop, index, needs_finite_test) &&
           // Do this test last, since it may generate code.
@@ -1403,10 +1403,10 @@
           // whether code generation on the original and, thus, related bounds check was possible.
           // It handles either loop invariants (lower is not set) or unit strides.
           if (other_c == max_c) {
-            induction_range_.GenerateRangeCode(
+            induction_range_.GenerateRange(
                 other_bounds_check, other_index, GetGraph(), block, &max_lower, &max_upper);
           } else if (other_c == min_c && base != nullptr) {
-            induction_range_.GenerateRangeCode(
+            induction_range_.GenerateRange(
                 other_bounds_check, other_index, GetGraph(), block, &min_lower, &min_upper);
           }
           ReplaceInstruction(other_bounds_check, other_index);
@@ -1699,11 +1699,8 @@
     // Insert the taken-test to see if the loop body is entered. If the
     // loop isn't entered at all, it jumps around the deoptimization block.
     if_block->AddInstruction(new (GetGraph()->GetArena()) HGoto());  // placeholder
-    HInstruction* condition = nullptr;
-    induction_range_.GenerateTakenTest(header->GetLastInstruction(),
-                                       GetGraph(),
-                                       if_block,
-                                       &condition);
+    HInstruction* condition = induction_range_.GenerateTakenTest(
+        header->GetLastInstruction(), GetGraph(), if_block);
     DCHECK(condition != nullptr);
     if_block->RemoveInstruction(if_block->GetLastInstruction());
     if_block->AddInstruction(new (GetGraph()->GetArena()) HIf(condition));
diff --git a/compiler/optimizing/code_generator.cc b/compiler/optimizing/code_generator.cc
index 2087888..6732670 100644
--- a/compiler/optimizing/code_generator.cc
+++ b/compiler/optimizing/code_generator.cc
@@ -1081,13 +1081,6 @@
   }
 }
 
-bool CodeGenerator::IsImplicitNullCheckAllowed(HNullCheck* null_check) const {
-  return compiler_options_.GetImplicitNullChecks() &&
-         // Null checks which might throw into a catch block need to save live
-         // registers and therefore cannot be done implicitly.
-         !null_check->CanThrowIntoCatchBlock();
-}
-
 bool CodeGenerator::CanMoveNullCheckToUser(HNullCheck* null_check) {
   HInstruction* first_next_not_move = null_check->GetNextDisregardingMoves();
 
@@ -1096,6 +1089,10 @@
 }
 
 void CodeGenerator::MaybeRecordImplicitNullCheck(HInstruction* instr) {
+  if (!compiler_options_.GetImplicitNullChecks()) {
+    return;
+  }
+
   // If we are from a static path don't record the pc as we can't throw NPE.
   // NB: having the checks here makes the code much less verbose in the arch
   // specific code generators.
@@ -1114,16 +1111,35 @@
   // and needs to record the pc.
   if (first_prev_not_move != nullptr && first_prev_not_move->IsNullCheck()) {
     HNullCheck* null_check = first_prev_not_move->AsNullCheck();
-    if (IsImplicitNullCheckAllowed(null_check)) {
-      // TODO: The parallel moves modify the environment. Their changes need to be
-      // reverted otherwise the stack maps at the throw point will not be correct.
-      RecordPcInfo(null_check, null_check->GetDexPc());
-    }
+    // TODO: The parallel moves modify the environment. Their changes need to be
+    // reverted otherwise the stack maps at the throw point will not be correct.
+    RecordPcInfo(null_check, null_check->GetDexPc());
   }
 }
 
+LocationSummary* CodeGenerator::CreateNullCheckLocations(HNullCheck* null_check) {
+  // Note: Using kNoCall allows the method to be treated as leaf (and eliminate the
+  // HSuspendCheck from entry block). However, it will still get a valid stack frame
+  // because the HNullCheck needs an environment.
+  LocationSummary::CallKind call_kind = LocationSummary::kNoCall;
+  // When throwing from a try block, we may need to retrieve dalvik registers from
+  // physical registers and we also need to set up stack mask for GC. This is
+  // implicitly achieved by passing kCallOnSlowPath to the LocationSummary.
+  bool can_throw_into_catch_block = null_check->CanThrowIntoCatchBlock();
+  if (can_throw_into_catch_block) {
+    call_kind = LocationSummary::kCallOnSlowPath;
+  }
+  LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(null_check, call_kind);
+  if (can_throw_into_catch_block && compiler_options_.GetImplicitNullChecks()) {
+    locations->SetCustomSlowPathCallerSaves(RegisterSet());  // No caller-save registers.
+  }
+  locations->SetInAt(0, Location::RequiresRegister());
+  DCHECK(!null_check->HasUses());
+  return locations;
+}
+
 void CodeGenerator::GenerateNullCheck(HNullCheck* instruction) {
-  if (IsImplicitNullCheckAllowed(instruction)) {
+  if (compiler_options_.GetImplicitNullChecks()) {
     MaybeRecordStat(kImplicitNullCheckGenerated);
     GenerateImplicitNullCheck(instruction);
   } else {
diff --git a/compiler/optimizing/code_generator.h b/compiler/optimizing/code_generator.h
index 0c60a98..b4d4b9b 100644
--- a/compiler/optimizing/code_generator.h
+++ b/compiler/optimizing/code_generator.h
@@ -313,6 +313,7 @@
 
   bool CanMoveNullCheckToUser(HNullCheck* null_check);
   void MaybeRecordImplicitNullCheck(HInstruction* instruction);
+  LocationSummary* CreateNullCheckLocations(HNullCheck* null_check);
   void GenerateNullCheck(HNullCheck* null_check);
   virtual void GenerateImplicitNullCheck(HNullCheck* null_check) = 0;
   virtual void GenerateExplicitNullCheck(HNullCheck* null_check) = 0;
@@ -322,12 +323,6 @@
   // TODO: Replace with a catch-entering instruction that records the environment.
   void RecordCatchBlockInfo();
 
-  // Returns true if implicit null checks are allowed in the compiler options
-  // and if the null check is not inside a try block. We currently cannot do
-  // implicit null checks in that case because we need the NullCheckSlowPath to
-  // save live registers, which may be needed by the runtime to set catch phis.
-  bool IsImplicitNullCheckAllowed(HNullCheck* null_check) const;
-
   // TODO: Avoid creating the `std::unique_ptr` here.
   void AddSlowPath(SlowPathCode* slow_path) {
     slow_paths_.push_back(std::unique_ptr<SlowPathCode>(slow_path));
@@ -713,6 +708,8 @@
   bool is_leaf_;
 
   // Whether an instruction in the graph accesses the current method.
+  // TODO: Rename: this actually indicates that some instruction in the method
+  // needs the environment including a valid stack frame.
   bool requires_current_method_;
 
   friend class OptimizingCFITest;
diff --git a/compiler/optimizing/code_generator_arm.cc b/compiler/optimizing/code_generator_arm.cc
index 3c4a3e8..40c2b9c 100644
--- a/compiler/optimizing/code_generator_arm.cc
+++ b/compiler/optimizing/code_generator_arm.cc
@@ -4251,14 +4251,7 @@
 }
 
 void LocationsBuilderARM::VisitNullCheck(HNullCheck* instruction) {
-  LocationSummary::CallKind call_kind = instruction->CanThrowIntoCatchBlock()
-      ? LocationSummary::kCallOnSlowPath
-      : LocationSummary::kNoCall;
-  LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(instruction, call_kind);
-  locations->SetInAt(0, Location::RequiresRegister());
-  if (instruction->HasUses()) {
-    locations->SetOut(Location::SameAsFirstInput());
-  }
+  codegen_->CreateNullCheckLocations(instruction);
 }
 
 void CodeGeneratorARM::GenerateImplicitNullCheck(HNullCheck* instruction) {
@@ -5422,17 +5415,6 @@
 
 HLoadString::LoadKind CodeGeneratorARM::GetSupportedLoadStringKind(
     HLoadString::LoadKind desired_string_load_kind) {
-  if (kEmitCompilerReadBarrier) {
-    switch (desired_string_load_kind) {
-      case HLoadString::LoadKind::kBootImageLinkTimeAddress:
-      case HLoadString::LoadKind::kBootImageLinkTimePcRelative:
-      case HLoadString::LoadKind::kBootImageAddress:
-        // TODO: Implement for read barrier.
-        return HLoadString::LoadKind::kDexCacheViaMethod;
-      default:
-        break;
-    }
-  }
   switch (desired_string_load_kind) {
     case HLoadString::LoadKind::kBootImageLinkTimeAddress:
       DCHECK(!GetCompilerOptions().GetCompilePic());
@@ -5485,13 +5467,11 @@
 
   switch (load_kind) {
     case HLoadString::LoadKind::kBootImageLinkTimeAddress: {
-      DCHECK(!kEmitCompilerReadBarrier);
       __ LoadLiteral(out, codegen_->DeduplicateBootImageStringLiteral(load->GetDexFile(),
                                                                       load->GetStringIndex()));
       return;  // No dex cache slow path.
     }
     case HLoadString::LoadKind::kBootImageLinkTimePcRelative: {
-      DCHECK(!kEmitCompilerReadBarrier);
       CodeGeneratorARM::PcRelativePatchInfo* labels =
           codegen_->NewPcRelativeStringPatch(load->GetDexFile(), load->GetStringIndex());
       __ BindTrackedLabel(&labels->movw_label);
@@ -5503,7 +5483,6 @@
       return;  // No dex cache slow path.
     }
     case HLoadString::LoadKind::kBootImageAddress: {
-      DCHECK(!kEmitCompilerReadBarrier);
       DCHECK_NE(load->GetAddress(), 0u);
       uint32_t address = dchecked_integral_cast<uint32_t>(load->GetAddress());
       __ LoadLiteral(out, codegen_->DeduplicateBootImageAddressLiteral(address));
@@ -5759,7 +5738,6 @@
   bool throws_into_catch = instruction->CanThrowIntoCatchBlock();
 
   TypeCheckKind type_check_kind = instruction->GetTypeCheckKind();
-  bool baker_read_barrier_slow_path = false;
   switch (type_check_kind) {
     case TypeCheckKind::kExactCheck:
     case TypeCheckKind::kAbstractClassCheck:
@@ -5768,7 +5746,6 @@
       call_kind = (throws_into_catch || kEmitCompilerReadBarrier) ?
           LocationSummary::kCallOnSlowPath :
           LocationSummary::kNoCall;  // In fact, call on a fatal (non-returning) slow path.
-      baker_read_barrier_slow_path = kUseBakerReadBarrier && !throws_into_catch;
       break;
     case TypeCheckKind::kArrayCheck:
     case TypeCheckKind::kUnresolvedCheck:
@@ -5778,9 +5755,6 @@
   }
 
   LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(instruction, call_kind);
-  if (baker_read_barrier_slow_path) {
-    locations->SetCustomSlowPathCallerSaves(RegisterSet());  // No caller-save registers.
-  }
   locations->SetInAt(0, Location::RequiresRegister());
   locations->SetInAt(1, Location::RequiresRegister());
   // Note that TypeCheckSlowPathARM uses this "temp" register too.
diff --git a/compiler/optimizing/code_generator_arm.h b/compiler/optimizing/code_generator_arm.h
index ce9d7e6..38a2410 100644
--- a/compiler/optimizing/code_generator_arm.h
+++ b/compiler/optimizing/code_generator_arm.h
@@ -556,10 +556,10 @@
   // artReadBarrierForRootSlow.
   void GenerateReadBarrierForRootSlow(HInstruction* instruction, Location out, Location root);
 
-  void GenerateNop();
+  void GenerateNop() OVERRIDE;
 
-  void GenerateImplicitNullCheck(HNullCheck* instruction);
-  void GenerateExplicitNullCheck(HNullCheck* instruction);
+  void GenerateImplicitNullCheck(HNullCheck* instruction) OVERRIDE;
+  void GenerateExplicitNullCheck(HNullCheck* instruction) OVERRIDE;
 
  private:
   Register GetInvokeStaticOrDirectExtraParameter(HInvokeStaticOrDirect* invoke, Register temp);
diff --git a/compiler/optimizing/code_generator_arm64.cc b/compiler/optimizing/code_generator_arm64.cc
index 1d2f334..599185a 100644
--- a/compiler/optimizing/code_generator_arm64.cc
+++ b/compiler/optimizing/code_generator_arm64.cc
@@ -448,7 +448,7 @@
   }
 
   const char* GetDescription() const OVERRIDE { return "TypeCheckSlowPathARM64"; }
-  bool IsFatal() const { return is_fatal_; }
+  bool IsFatal() const OVERRIDE { return is_fatal_; }
 
  private:
   const bool is_fatal_;
@@ -3250,7 +3250,6 @@
   bool throws_into_catch = instruction->CanThrowIntoCatchBlock();
 
   TypeCheckKind type_check_kind = instruction->GetTypeCheckKind();
-  bool baker_read_barrier_slow_path = false;
   switch (type_check_kind) {
     case TypeCheckKind::kExactCheck:
     case TypeCheckKind::kAbstractClassCheck:
@@ -3259,7 +3258,6 @@
       call_kind = (throws_into_catch || kEmitCompilerReadBarrier) ?
           LocationSummary::kCallOnSlowPath :
           LocationSummary::kNoCall;  // In fact, call on a fatal (non-returning) slow path.
-      baker_read_barrier_slow_path = kUseBakerReadBarrier && !throws_into_catch;
       break;
     case TypeCheckKind::kArrayCheck:
     case TypeCheckKind::kUnresolvedCheck:
@@ -3269,9 +3267,6 @@
   }
 
   LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(instruction, call_kind);
-  if (baker_read_barrier_slow_path) {
-    locations->SetCustomSlowPathCallerSaves(RegisterSet());  // No caller-save registers.
-  }
   locations->SetInAt(0, Location::RequiresRegister());
   locations->SetInAt(1, Location::RequiresRegister());
   // Note that TypeCheckSlowPathARM64 uses this "temp" register too.
@@ -4124,17 +4119,6 @@
 
 HLoadString::LoadKind CodeGeneratorARM64::GetSupportedLoadStringKind(
     HLoadString::LoadKind desired_string_load_kind) {
-  if (kEmitCompilerReadBarrier) {
-    switch (desired_string_load_kind) {
-      case HLoadString::LoadKind::kBootImageLinkTimeAddress:
-      case HLoadString::LoadKind::kBootImageLinkTimePcRelative:
-      case HLoadString::LoadKind::kBootImageAddress:
-        // TODO: Implement for read barrier.
-        return HLoadString::LoadKind::kDexCacheViaMethod;
-      default:
-        break;
-    }
-  }
   switch (desired_string_load_kind) {
     case HLoadString::LoadKind::kBootImageLinkTimeAddress:
       DCHECK(!GetCompilerOptions().GetCompilePic());
@@ -4175,12 +4159,10 @@
 
   switch (load->GetLoadKind()) {
     case HLoadString::LoadKind::kBootImageLinkTimeAddress:
-      DCHECK(!kEmitCompilerReadBarrier);
       __ Ldr(out, codegen_->DeduplicateBootImageStringLiteral(load->GetDexFile(),
                                                               load->GetStringIndex()));
       return;  // No dex cache slow path.
     case HLoadString::LoadKind::kBootImageLinkTimePcRelative: {
-      DCHECK(!kEmitCompilerReadBarrier);
       // Add ADRP with its PC-relative String patch.
       const DexFile& dex_file = load->GetDexFile();
       uint32_t string_index = load->GetStringIndex();
@@ -4201,7 +4183,6 @@
       return;  // No dex cache slow path.
     }
     case HLoadString::LoadKind::kBootImageAddress: {
-      DCHECK(!kEmitCompilerReadBarrier);
       DCHECK(load->GetAddress() != 0u && IsUint<32>(load->GetAddress()));
       __ Ldr(out.W(), codegen_->DeduplicateBootImageAddressLiteral(load->GetAddress()));
       return;  // No dex cache slow path.
@@ -4403,14 +4384,7 @@
 }
 
 void LocationsBuilderARM64::VisitNullCheck(HNullCheck* instruction) {
-  LocationSummary::CallKind call_kind = instruction->CanThrowIntoCatchBlock()
-      ? LocationSummary::kCallOnSlowPath
-      : LocationSummary::kNoCall;
-  LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(instruction, call_kind);
-  locations->SetInAt(0, Location::RequiresRegister());
-  if (instruction->HasUses()) {
-    locations->SetOut(Location::SameAsFirstInput());
-  }
+  codegen_->CreateNullCheckLocations(instruction);
 }
 
 void CodeGeneratorARM64::GenerateImplicitNullCheck(HNullCheck* instruction) {
diff --git a/compiler/optimizing/code_generator_arm64.h b/compiler/optimizing/code_generator_arm64.h
index f0d7910..f1dc7ee 100644
--- a/compiler/optimizing/code_generator_arm64.h
+++ b/compiler/optimizing/code_generator_arm64.h
@@ -644,10 +644,10 @@
   // artReadBarrierForRootSlow.
   void GenerateReadBarrierForRootSlow(HInstruction* instruction, Location out, Location root);
 
-  void GenerateNop();
+  void GenerateNop() OVERRIDE;
 
-  void GenerateImplicitNullCheck(HNullCheck* instruction);
-  void GenerateExplicitNullCheck(HNullCheck* instruction);
+  void GenerateImplicitNullCheck(HNullCheck* instruction) OVERRIDE;
+  void GenerateExplicitNullCheck(HNullCheck* instruction) OVERRIDE;
 
  private:
   using Uint64ToLiteralMap = ArenaSafeMap<uint64_t, vixl::aarch64::Literal<uint64_t>*>;
diff --git a/compiler/optimizing/code_generator_mips.cc b/compiler/optimizing/code_generator_mips.cc
index f07f8a0..b767aa5 100644
--- a/compiler/optimizing/code_generator_mips.cc
+++ b/compiler/optimizing/code_generator_mips.cc
@@ -5075,14 +5075,7 @@
 }
 
 void LocationsBuilderMIPS::VisitNullCheck(HNullCheck* instruction) {
-  LocationSummary::CallKind call_kind = instruction->CanThrowIntoCatchBlock()
-      ? LocationSummary::kCallOnSlowPath
-      : LocationSummary::kNoCall;
-  LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(instruction, call_kind);
-  locations->SetInAt(0, Location::RequiresRegister());
-  if (instruction->HasUses()) {
-    locations->SetOut(Location::SameAsFirstInput());
-  }
+  codegen_->CreateNullCheckLocations(instruction);
 }
 
 void CodeGeneratorMIPS::GenerateImplicitNullCheck(HNullCheck* instruction) {
@@ -5824,13 +5817,11 @@
   locations->SetInAt(0, Location::RequiresRegister());
 }
 
-void InstructionCodeGeneratorMIPS::VisitPackedSwitch(HPackedSwitch* switch_instr) {
-  int32_t lower_bound = switch_instr->GetStartValue();
-  int32_t num_entries = switch_instr->GetNumEntries();
-  LocationSummary* locations = switch_instr->GetLocations();
-  Register value_reg = locations->InAt(0).AsRegister<Register>();
-  HBasicBlock* default_block = switch_instr->GetDefaultBlock();
-
+void InstructionCodeGeneratorMIPS::GenPackedSwitchWithCompares(Register value_reg,
+                                                               int32_t lower_bound,
+                                                               uint32_t num_entries,
+                                                               HBasicBlock* switch_block,
+                                                               HBasicBlock* default_block) {
   // Create a set of compare/jumps.
   Register temp_reg = TMP;
   __ Addiu32(temp_reg, value_reg, -lower_bound);
@@ -5839,7 +5830,7 @@
   // this case, index >= num_entries must be true. So that we can save one branch instruction.
   __ Bltz(temp_reg, codegen_->GetLabelOf(default_block));
 
-  const ArenaVector<HBasicBlock*>& successors = switch_instr->GetBlock()->GetSuccessors();
+  const ArenaVector<HBasicBlock*>& successors = switch_block->GetSuccessors();
   // Jump to successors[0] if value == lower_bound.
   __ Beqz(temp_reg, codegen_->GetLabelOf(successors[0]));
   int32_t last_index = 0;
@@ -5857,11 +5848,107 @@
   }
 
   // And the default for any other value.
-  if (!codegen_->GoesToNextBlock(switch_instr->GetBlock(), default_block)) {
+  if (!codegen_->GoesToNextBlock(switch_block, default_block)) {
     __ B(codegen_->GetLabelOf(default_block));
   }
 }
 
+void InstructionCodeGeneratorMIPS::GenTableBasedPackedSwitch(Register value_reg,
+                                                             Register constant_area,
+                                                             int32_t lower_bound,
+                                                             uint32_t num_entries,
+                                                             HBasicBlock* switch_block,
+                                                             HBasicBlock* default_block) {
+  // Create a jump table.
+  std::vector<MipsLabel*> labels(num_entries);
+  const ArenaVector<HBasicBlock*>& successors = switch_block->GetSuccessors();
+  for (uint32_t i = 0; i < num_entries; i++) {
+    labels[i] = codegen_->GetLabelOf(successors[i]);
+  }
+  JumpTable* table = __ CreateJumpTable(std::move(labels));
+
+  // Is the value in range?
+  __ Addiu32(TMP, value_reg, -lower_bound);
+  if (IsInt<16>(static_cast<int32_t>(num_entries))) {
+    __ Sltiu(AT, TMP, num_entries);
+    __ Beqz(AT, codegen_->GetLabelOf(default_block));
+  } else {
+    __ LoadConst32(AT, num_entries);
+    __ Bgeu(TMP, AT, codegen_->GetLabelOf(default_block));
+  }
+
+  // We are in the range of the table.
+  // Load the target address from the jump table, indexing by the value.
+  __ LoadLabelAddress(AT, constant_area, table->GetLabel());
+  __ Sll(TMP, TMP, 2);
+  __ Addu(TMP, TMP, AT);
+  __ Lw(TMP, TMP, 0);
+  // Compute the absolute target address by adding the table start address
+  // (the table contains offsets to targets relative to its start).
+  __ Addu(TMP, TMP, AT);
+  // And jump.
+  __ Jr(TMP);
+  __ NopIfNoReordering();
+}
+
+void InstructionCodeGeneratorMIPS::VisitPackedSwitch(HPackedSwitch* switch_instr) {
+  int32_t lower_bound = switch_instr->GetStartValue();
+  uint32_t num_entries = switch_instr->GetNumEntries();
+  LocationSummary* locations = switch_instr->GetLocations();
+  Register value_reg = locations->InAt(0).AsRegister<Register>();
+  HBasicBlock* switch_block = switch_instr->GetBlock();
+  HBasicBlock* default_block = switch_instr->GetDefaultBlock();
+
+  if (codegen_->GetInstructionSetFeatures().IsR6() &&
+      num_entries > kPackedSwitchJumpTableThreshold) {
+    // R6 uses PC-relative addressing to access the jump table.
+    // R2, OTOH, requires an HMipsComputeBaseMethodAddress input to access
+    // the jump table and it is implemented by changing HPackedSwitch to
+    // HMipsPackedSwitch, which bears HMipsComputeBaseMethodAddress.
+    // See VisitMipsPackedSwitch() for the table-based implementation on R2.
+    GenTableBasedPackedSwitch(value_reg,
+                              ZERO,
+                              lower_bound,
+                              num_entries,
+                              switch_block,
+                              default_block);
+  } else {
+    GenPackedSwitchWithCompares(value_reg,
+                                lower_bound,
+                                num_entries,
+                                switch_block,
+                                default_block);
+  }
+}
+
+void LocationsBuilderMIPS::VisitMipsPackedSwitch(HMipsPackedSwitch* switch_instr) {
+  LocationSummary* locations =
+      new (GetGraph()->GetArena()) LocationSummary(switch_instr, LocationSummary::kNoCall);
+  locations->SetInAt(0, Location::RequiresRegister());
+  // Constant area pointer (HMipsComputeBaseMethodAddress).
+  locations->SetInAt(1, Location::RequiresRegister());
+}
+
+void InstructionCodeGeneratorMIPS::VisitMipsPackedSwitch(HMipsPackedSwitch* switch_instr) {
+  int32_t lower_bound = switch_instr->GetStartValue();
+  uint32_t num_entries = switch_instr->GetNumEntries();
+  LocationSummary* locations = switch_instr->GetLocations();
+  Register value_reg = locations->InAt(0).AsRegister<Register>();
+  Register constant_area = locations->InAt(1).AsRegister<Register>();
+  HBasicBlock* switch_block = switch_instr->GetBlock();
+  HBasicBlock* default_block = switch_instr->GetDefaultBlock();
+
+  // This is an R2-only path. HPackedSwitch has been changed to
+  // HMipsPackedSwitch, which bears HMipsComputeBaseMethodAddress
+  // required to address the jump table relative to PC.
+  GenTableBasedPackedSwitch(value_reg,
+                            constant_area,
+                            lower_bound,
+                            num_entries,
+                            switch_block,
+                            default_block);
+}
+
 void LocationsBuilderMIPS::VisitMipsComputeBaseMethodAddress(
     HMipsComputeBaseMethodAddress* insn) {
   LocationSummary* locations =
diff --git a/compiler/optimizing/code_generator_mips.h b/compiler/optimizing/code_generator_mips.h
index 0039981..a42374f 100644
--- a/compiler/optimizing/code_generator_mips.h
+++ b/compiler/optimizing/code_generator_mips.h
@@ -218,6 +218,14 @@
 
   MipsAssembler* GetAssembler() const { return assembler_; }
 
+  // Compare-and-jump packed switch generates approx. 3 + 2.5 * N 32-bit
+  // instructions for N cases.
+  // Table-based packed switch generates approx. 11 32-bit instructions
+  // and N 32-bit data words for N cases.
+  // At N = 6 they come out as 18 and 17 32-bit words respectively.
+  // We switch to the table-based method starting with 7 cases.
+  static constexpr uint32_t kPackedSwitchJumpTableThreshold = 6;
+
  private:
   void GenerateClassInitializationCheck(SlowPathCodeMIPS* slow_path, Register class_reg);
   void GenerateMemoryBarrier(MemBarrierKind kind);
@@ -262,6 +270,17 @@
   void GenerateDivRemIntegral(HBinaryOperation* instruction);
   void HandleGoto(HInstruction* got, HBasicBlock* successor);
   auto GetImplicitNullChecker(HInstruction* instruction);
+  void GenPackedSwitchWithCompares(Register value_reg,
+                                   int32_t lower_bound,
+                                   uint32_t num_entries,
+                                   HBasicBlock* switch_block,
+                                   HBasicBlock* default_block);
+  void GenTableBasedPackedSwitch(Register value_reg,
+                                 Register constant_area,
+                                 int32_t lower_bound,
+                                 uint32_t num_entries,
+                                 HBasicBlock* switch_block,
+                                 HBasicBlock* default_block);
 
   MipsAssembler* const assembler_;
   CodeGeneratorMIPS* const codegen_;
@@ -310,10 +329,10 @@
 
   void SetupBlockedRegisters() const OVERRIDE;
 
-  size_t SaveCoreRegister(size_t stack_index, uint32_t reg_id);
-  size_t RestoreCoreRegister(size_t stack_index, uint32_t reg_id);
-  size_t SaveFloatingPointRegister(size_t stack_index, uint32_t reg_id);
-  size_t RestoreFloatingPointRegister(size_t stack_index, uint32_t reg_id);
+  size_t SaveCoreRegister(size_t stack_index, uint32_t reg_id) OVERRIDE;
+  size_t RestoreCoreRegister(size_t stack_index, uint32_t reg_id) OVERRIDE;
+  size_t SaveFloatingPointRegister(size_t stack_index, uint32_t reg_id) OVERRIDE;
+  size_t RestoreFloatingPointRegister(size_t stack_index, uint32_t reg_id) OVERRIDE;
   void ClobberRA() {
     clobbered_ra_ = true;
   }
@@ -344,7 +363,7 @@
 
   void MoveLocation(Location dst, Location src, Primitive::Type dst_type) OVERRIDE;
 
-  void MoveConstant(Location destination, int32_t value);
+  void MoveConstant(Location destination, int32_t value) OVERRIDE;
 
   void AddLocationAsTemp(Location location, LocationSummary* locations) OVERRIDE;
 
@@ -356,7 +375,7 @@
 
   ParallelMoveResolver* GetMoveResolver() OVERRIDE { return &move_resolver_; }
 
-  bool NeedsTwoRegisters(Primitive::Type type) const {
+  bool NeedsTwoRegisters(Primitive::Type type) const OVERRIDE {
     return type == Primitive::kPrimLong;
   }
 
@@ -384,9 +403,9 @@
     UNIMPLEMENTED(FATAL) << "Not implemented on MIPS";
   }
 
-  void GenerateNop();
-  void GenerateImplicitNullCheck(HNullCheck* instruction);
-  void GenerateExplicitNullCheck(HNullCheck* instruction);
+  void GenerateNop() OVERRIDE;
+  void GenerateImplicitNullCheck(HNullCheck* instruction) OVERRIDE;
+  void GenerateExplicitNullCheck(HNullCheck* instruction) OVERRIDE;
 
   // The PcRelativePatchInfo is used for PC-relative addressing of dex cache arrays
   // and boot image strings. The only difference is the interpretation of the offset_or_index.
diff --git a/compiler/optimizing/code_generator_mips64.cc b/compiler/optimizing/code_generator_mips64.cc
index 664d498..4d87523 100644
--- a/compiler/optimizing/code_generator_mips64.cc
+++ b/compiler/optimizing/code_generator_mips64.cc
@@ -3461,14 +3461,7 @@
 }
 
 void LocationsBuilderMIPS64::VisitNullCheck(HNullCheck* instruction) {
-  LocationSummary::CallKind call_kind = instruction->CanThrowIntoCatchBlock()
-      ? LocationSummary::kCallOnSlowPath
-      : LocationSummary::kNoCall;
-  LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(instruction, call_kind);
-  locations->SetInAt(0, Location::RequiresRegister());
-  if (instruction->HasUses()) {
-    locations->SetOut(Location::SameAsFirstInput());
-  }
+  codegen_->CreateNullCheckLocations(instruction);
 }
 
 void CodeGeneratorMIPS64::GenerateImplicitNullCheck(HNullCheck* instruction) {
diff --git a/compiler/optimizing/code_generator_mips64.h b/compiler/optimizing/code_generator_mips64.h
index 3910530..2dd409a 100644
--- a/compiler/optimizing/code_generator_mips64.h
+++ b/compiler/optimizing/code_generator_mips64.h
@@ -285,10 +285,10 @@
 
   void SetupBlockedRegisters() const OVERRIDE;
 
-  size_t SaveCoreRegister(size_t stack_index, uint32_t reg_id);
-  size_t RestoreCoreRegister(size_t stack_index, uint32_t reg_id);
-  size_t SaveFloatingPointRegister(size_t stack_index, uint32_t reg_id);
-  size_t RestoreFloatingPointRegister(size_t stack_index, uint32_t reg_id);
+  size_t SaveCoreRegister(size_t stack_index, uint32_t reg_id) OVERRIDE;
+  size_t RestoreCoreRegister(size_t stack_index, uint32_t reg_id) OVERRIDE;
+  size_t SaveFloatingPointRegister(size_t stack_index, uint32_t reg_id) OVERRIDE;
+  size_t RestoreFloatingPointRegister(size_t stack_index, uint32_t reg_id) OVERRIDE;
 
   void DumpCoreRegister(std::ostream& stream, int reg) const OVERRIDE;
   void DumpFloatingPointRegister(std::ostream& stream, int reg) const OVERRIDE;
@@ -327,7 +327,7 @@
 
   ParallelMoveResolver* GetMoveResolver() OVERRIDE { return &move_resolver_; }
 
-  bool NeedsTwoRegisters(Primitive::Type type ATTRIBUTE_UNUSED) const { return false; }
+  bool NeedsTwoRegisters(Primitive::Type type ATTRIBUTE_UNUSED) const OVERRIDE { return false; }
 
   // Check if the desired_string_load_kind is supported. If it is, return it,
   // otherwise return a fall-back kind that should be used instead.
@@ -353,9 +353,9 @@
     UNIMPLEMENTED(FATAL) << "Not implemented on MIPS64";
   }
 
-  void GenerateNop();
-  void GenerateImplicitNullCheck(HNullCheck* instruction);
-  void GenerateExplicitNullCheck(HNullCheck* instruction);
+  void GenerateNop() OVERRIDE;
+  void GenerateImplicitNullCheck(HNullCheck* instruction) OVERRIDE;
+  void GenerateExplicitNullCheck(HNullCheck* instruction) OVERRIDE;
 
  private:
   // Labels for each block that will be compiled.
diff --git a/compiler/optimizing/code_generator_x86.cc b/compiler/optimizing/code_generator_x86.cc
index 5953bad..28db29c 100644
--- a/compiler/optimizing/code_generator_x86.cc
+++ b/compiler/optimizing/code_generator_x86.cc
@@ -4950,16 +4950,10 @@
 }
 
 void LocationsBuilderX86::VisitNullCheck(HNullCheck* instruction) {
-  LocationSummary::CallKind call_kind = instruction->CanThrowIntoCatchBlock()
-      ? LocationSummary::kCallOnSlowPath
-      : LocationSummary::kNoCall;
-  LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(instruction, call_kind);
-  Location loc = codegen_->IsImplicitNullCheckAllowed(instruction)
-      ? Location::RequiresRegister()
-      : Location::Any();
-  locations->SetInAt(0, loc);
-  if (instruction->HasUses()) {
-    locations->SetOut(Location::SameAsFirstInput());
+  LocationSummary* locations = codegen_->CreateNullCheckLocations(instruction);
+  if (!codegen_->GetCompilerOptions().GetImplicitNullChecks()) {
+    // Explicit null checks can use any location.
+    locations->SetInAt(0, Location::Any());
   }
 }
 
@@ -6065,17 +6059,6 @@
 
 HLoadString::LoadKind CodeGeneratorX86::GetSupportedLoadStringKind(
     HLoadString::LoadKind desired_string_load_kind) {
-  if (kEmitCompilerReadBarrier) {
-    switch (desired_string_load_kind) {
-      case HLoadString::LoadKind::kBootImageLinkTimeAddress:
-      case HLoadString::LoadKind::kBootImageLinkTimePcRelative:
-      case HLoadString::LoadKind::kBootImageAddress:
-        // TODO: Implement for read barrier.
-        return HLoadString::LoadKind::kDexCacheViaMethod;
-      default:
-        break;
-    }
-  }
   switch (desired_string_load_kind) {
     case HLoadString::LoadKind::kBootImageLinkTimeAddress:
       DCHECK(!GetCompilerOptions().GetCompilePic());
@@ -6129,20 +6112,17 @@
 
   switch (load->GetLoadKind()) {
     case HLoadString::LoadKind::kBootImageLinkTimeAddress: {
-      DCHECK(!kEmitCompilerReadBarrier);
       __ movl(out, Immediate(/* placeholder */ 0));
       codegen_->RecordStringPatch(load);
       return;  // No dex cache slow path.
     }
     case HLoadString::LoadKind::kBootImageLinkTimePcRelative: {
-      DCHECK(!kEmitCompilerReadBarrier);
       Register method_address = locations->InAt(0).AsRegister<Register>();
       __ leal(out, Address(method_address, CodeGeneratorX86::kDummy32BitOffset));
       codegen_->RecordStringPatch(load);
       return;  // No dex cache slow path.
     }
     case HLoadString::LoadKind::kBootImageAddress: {
-      DCHECK(!kEmitCompilerReadBarrier);
       DCHECK_NE(load->GetAddress(), 0u);
       uint32_t address = dchecked_integral_cast<uint32_t>(load->GetAddress());
       __ movl(out, Immediate(address));
@@ -6423,7 +6403,6 @@
   LocationSummary::CallKind call_kind = LocationSummary::kNoCall;
   bool throws_into_catch = instruction->CanThrowIntoCatchBlock();
   TypeCheckKind type_check_kind = instruction->GetTypeCheckKind();
-  bool baker_read_barrier_slow_path = false;
   switch (type_check_kind) {
     case TypeCheckKind::kExactCheck:
     case TypeCheckKind::kAbstractClassCheck:
@@ -6432,7 +6411,6 @@
       call_kind = (throws_into_catch || kEmitCompilerReadBarrier) ?
           LocationSummary::kCallOnSlowPath :
           LocationSummary::kNoCall;  // In fact, call on a fatal (non-returning) slow path.
-      baker_read_barrier_slow_path = kUseBakerReadBarrier && !throws_into_catch;
       break;
     case TypeCheckKind::kArrayCheck:
     case TypeCheckKind::kUnresolvedCheck:
@@ -6441,9 +6419,6 @@
       break;
   }
   LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(instruction, call_kind);
-  if (baker_read_barrier_slow_path) {
-    locations->SetCustomSlowPathCallerSaves(RegisterSet());  // No caller-save registers.
-  }
   locations->SetInAt(0, Location::RequiresRegister());
   locations->SetInAt(1, Location::Any());
   // Note that TypeCheckSlowPathX86 uses this "temp" register too.
diff --git a/compiler/optimizing/code_generator_x86.h b/compiler/optimizing/code_generator_x86.h
index e225098..04a0a3d 100644
--- a/compiler/optimizing/code_generator_x86.h
+++ b/compiler/optimizing/code_generator_x86.h
@@ -561,9 +561,9 @@
     }
   }
 
-  void GenerateNop();
-  void GenerateImplicitNullCheck(HNullCheck* instruction);
-  void GenerateExplicitNullCheck(HNullCheck* instruction);
+  void GenerateNop() OVERRIDE;
+  void GenerateImplicitNullCheck(HNullCheck* instruction) OVERRIDE;
+  void GenerateExplicitNullCheck(HNullCheck* instruction) OVERRIDE;
 
   // When we don't know the proper offset for the value, we use kDummy32BitOffset.
   // The correct value will be inserted when processing Assembler fixups.
diff --git a/compiler/optimizing/code_generator_x86_64.cc b/compiler/optimizing/code_generator_x86_64.cc
index b3228f8..88d98fc 100644
--- a/compiler/optimizing/code_generator_x86_64.cc
+++ b/compiler/optimizing/code_generator_x86_64.cc
@@ -288,37 +288,6 @@
   DISALLOW_COPY_AND_ASSIGN(LoadClassSlowPathX86_64);
 };
 
-class LoadStringSlowPathX86_64 : public SlowPathCode {
- public:
-  explicit LoadStringSlowPathX86_64(HLoadString* instruction) : SlowPathCode(instruction) {}
-
-  void EmitNativeCode(CodeGenerator* codegen) OVERRIDE {
-    LocationSummary* locations = instruction_->GetLocations();
-    DCHECK(!locations->GetLiveRegisters()->ContainsCoreRegister(locations->Out().reg()));
-
-    CodeGeneratorX86_64* x86_64_codegen = down_cast<CodeGeneratorX86_64*>(codegen);
-    __ Bind(GetEntryLabel());
-    SaveLiveRegisters(codegen, locations);
-
-    InvokeRuntimeCallingConvention calling_convention;
-    const uint32_t string_index = instruction_->AsLoadString()->GetStringIndex();
-    __ movl(CpuRegister(calling_convention.GetRegisterAt(0)), Immediate(string_index));
-    x86_64_codegen->InvokeRuntime(kQuickResolveString,
-                                  instruction_,
-                                  instruction_->GetDexPc(),
-                                  this);
-    CheckEntrypointTypes<kQuickResolveString, void*, uint32_t>();
-    x86_64_codegen->Move(locations->Out(), Location::RegisterLocation(RAX));
-    RestoreLiveRegisters(codegen, locations);
-    __ jmp(GetExitLabel());
-  }
-
-  const char* GetDescription() const OVERRIDE { return "LoadStringSlowPathX86_64"; }
-
- private:
-  DISALLOW_COPY_AND_ASSIGN(LoadStringSlowPathX86_64);
-};
-
 class TypeCheckSlowPathX86_64 : public SlowPathCode {
  public:
   TypeCheckSlowPathX86_64(HInstruction* instruction, bool is_fatal)
@@ -4490,16 +4459,10 @@
 }
 
 void LocationsBuilderX86_64::VisitNullCheck(HNullCheck* instruction) {
-  LocationSummary::CallKind call_kind = instruction->CanThrowIntoCatchBlock()
-      ? LocationSummary::kCallOnSlowPath
-      : LocationSummary::kNoCall;
-  LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(instruction, call_kind);
-  Location loc = codegen_->IsImplicitNullCheckAllowed(instruction)
-      ? Location::RequiresRegister()
-      : Location::Any();
-  locations->SetInAt(0, loc);
-  if (instruction->HasUses()) {
-    locations->SetOut(Location::SameAsFirstInput());
+  LocationSummary* locations = codegen_->CreateNullCheckLocations(instruction);
+  if (!codegen_->GetCompilerOptions().GetImplicitNullChecks()) {
+    // Explicit null checks can use any location.
+    locations->SetInAt(0, Location::Any());
   }
 }
 
@@ -5526,17 +5489,6 @@
 
 HLoadString::LoadKind CodeGeneratorX86_64::GetSupportedLoadStringKind(
     HLoadString::LoadKind desired_string_load_kind) {
-  if (kEmitCompilerReadBarrier) {
-    switch (desired_string_load_kind) {
-      case HLoadString::LoadKind::kBootImageLinkTimeAddress:
-      case HLoadString::LoadKind::kBootImageLinkTimePcRelative:
-      case HLoadString::LoadKind::kBootImageAddress:
-        // TODO: Implement for read barrier.
-        return HLoadString::LoadKind::kDexCacheViaMethod;
-      default:
-        break;
-    }
-  }
   switch (desired_string_load_kind) {
     case HLoadString::LoadKind::kBootImageLinkTimeAddress:
       DCHECK(!GetCompilerOptions().GetCompilePic());
@@ -5560,18 +5512,16 @@
 }
 
 void LocationsBuilderX86_64::VisitLoadString(HLoadString* load) {
-  LocationSummary::CallKind call_kind = (load->NeedsEnvironment() || kEmitCompilerReadBarrier)
-      ? LocationSummary::kCallOnSlowPath
+  LocationSummary::CallKind call_kind = load->NeedsEnvironment()
+      ? LocationSummary::kCallOnMainOnly
       : LocationSummary::kNoCall;
   LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(load, call_kind);
-  if (kUseBakerReadBarrier && !load->NeedsEnvironment()) {
-    locations->SetCustomSlowPathCallerSaves(RegisterSet());  // No caller-save registers.
-  }
-
   if (load->GetLoadKind() == HLoadString::LoadKind::kDexCacheViaMethod) {
     locations->SetInAt(0, Location::RequiresRegister());
+    locations->SetOut(Location::RegisterLocation(RAX));
+  } else {
+    locations->SetOut(Location::RequiresRegister());
   }
-  locations->SetOut(Location::RequiresRegister());
 }
 
 void InstructionCodeGeneratorX86_64::VisitLoadString(HLoadString* load) {
@@ -5581,13 +5531,11 @@
 
   switch (load->GetLoadKind()) {
     case HLoadString::LoadKind::kBootImageLinkTimePcRelative: {
-      DCHECK(!kEmitCompilerReadBarrier);
       __ leal(out, Address::Absolute(CodeGeneratorX86_64::kDummy32BitOffset, /* no_rip */ false));
       codegen_->RecordStringPatch(load);
       return;  // No dex cache slow path.
     }
     case HLoadString::LoadKind::kBootImageAddress: {
-      DCHECK(!kEmitCompilerReadBarrier);
       DCHECK_NE(load->GetAddress(), 0u);
       uint32_t address = dchecked_integral_cast<uint32_t>(load->GetAddress());
       __ movl(out, Immediate(address));  // Zero-extended.
@@ -5599,10 +5547,13 @@
   }
 
   // TODO: Re-add the compiler code to do string dex cache lookup again.
-  SlowPathCode* slow_path = new (GetGraph()->GetArena()) LoadStringSlowPathX86_64(load);
-  codegen_->AddSlowPath(slow_path);
-  __ jmp(slow_path->GetEntryLabel());
-  __ Bind(slow_path->GetExitLabel());
+  InvokeRuntimeCallingConvention calling_convention;
+  __ movl(CpuRegister(calling_convention.GetRegisterAt(0)),
+          Immediate(load->GetStringIndex()));
+  codegen_->InvokeRuntime(kQuickResolveString,
+                          load,
+                          load->GetDexPc());
+  CheckEntrypointTypes<kQuickResolveString, void*, uint32_t>();
 }
 
 static Address GetExceptionTlsAddress() {
@@ -5874,7 +5825,6 @@
   LocationSummary::CallKind call_kind = LocationSummary::kNoCall;
   bool throws_into_catch = instruction->CanThrowIntoCatchBlock();
   TypeCheckKind type_check_kind = instruction->GetTypeCheckKind();
-  bool baker_read_barrier_slow_path = false;
   switch (type_check_kind) {
     case TypeCheckKind::kExactCheck:
     case TypeCheckKind::kAbstractClassCheck:
@@ -5883,7 +5833,6 @@
       call_kind = (throws_into_catch || kEmitCompilerReadBarrier) ?
           LocationSummary::kCallOnSlowPath :
           LocationSummary::kNoCall;  // In fact, call on a fatal (non-returning) slow path.
-      baker_read_barrier_slow_path = kUseBakerReadBarrier && !throws_into_catch;
       break;
     case TypeCheckKind::kArrayCheck:
     case TypeCheckKind::kUnresolvedCheck:
@@ -5892,9 +5841,6 @@
       break;
   }
   LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(instruction, call_kind);
-  if (baker_read_barrier_slow_path) {
-    locations->SetCustomSlowPathCallerSaves(RegisterSet());  // No caller-save registers.
-  }
   locations->SetInAt(0, Location::RequiresRegister());
   locations->SetInAt(1, Location::Any());
   // Note that TypeCheckSlowPathX86_64 uses this "temp" register too.
diff --git a/compiler/optimizing/code_generator_x86_64.h b/compiler/optimizing/code_generator_x86_64.h
index d939083..693d0b8 100644
--- a/compiler/optimizing/code_generator_x86_64.h
+++ b/compiler/optimizing/code_generator_x86_64.h
@@ -533,9 +533,9 @@
     }
   }
 
-  void GenerateNop();
-  void GenerateImplicitNullCheck(HNullCheck* instruction);
-  void GenerateExplicitNullCheck(HNullCheck* instruction);
+  void GenerateNop() OVERRIDE;
+  void GenerateImplicitNullCheck(HNullCheck* instruction) OVERRIDE;
+  void GenerateExplicitNullCheck(HNullCheck* instruction) OVERRIDE;
 
   // When we don't know the proper offset for the value, we use kDummy32BitOffset.
   // We will fix this up in the linker later to have the right value.
diff --git a/compiler/optimizing/codegen_test.cc b/compiler/optimizing/codegen_test.cc
index d00a786..070cbb3 100644
--- a/compiler/optimizing/codegen_test.cc
+++ b/compiler/optimizing/codegen_test.cc
@@ -74,6 +74,24 @@
 
 namespace art {
 
+typedef CodeGenerator* (*CreateCodegenFn)(HGraph*, const CompilerOptions&);
+
+class CodegenTargetConfig {
+ public:
+  CodegenTargetConfig(InstructionSet isa, CreateCodegenFn create_codegen)
+      : isa_(isa), create_codegen_(create_codegen) {
+  }
+  InstructionSet GetInstructionSet() const { return isa_; }
+  CodeGenerator* CreateCodeGenerator(HGraph* graph, const CompilerOptions& compiler_options) {
+    return create_codegen_(graph, compiler_options);
+  }
+
+ private:
+  CodegenTargetConfig() {}
+  InstructionSet isa_;
+  CreateCodegenFn create_codegen_;
+};
+
 #ifdef ART_ENABLE_CODEGEN_arm
 // Provide our own codegen, that ensures the C calling conventions
 // are preserved. Currently, ART and C do not match as R4 is caller-save
@@ -222,12 +240,7 @@
   VerifyGeneratedCode(target_isa, f, has_result, expected);
 }
 
-template <typename Expected>
-static void RunCode(CodeGenerator* codegen,
-                    HGraph* graph,
-                    std::function<void(HGraph*)> hook_before_codegen,
-                    bool has_result,
-                    Expected expected) {
+static void ValidateGraph(HGraph* graph) {
   GraphChecker graph_checker(graph);
   graph_checker.Run();
   if (!graph_checker.IsValid()) {
@@ -236,92 +249,129 @@
     }
   }
   ASSERT_TRUE(graph_checker.IsValid());
+}
 
+template <typename Expected>
+static void RunCodeNoCheck(CodeGenerator* codegen,
+                           HGraph* graph,
+                           std::function<void(HGraph*)> hook_before_codegen,
+                           bool has_result,
+                           Expected expected) {
   SsaLivenessAnalysis liveness(graph, codegen);
-
   PrepareForRegisterAllocation(graph).Run();
   liveness.Analyze();
   RegisterAllocator::Create(graph->GetArena(), codegen, liveness)->AllocateRegisters();
   hook_before_codegen(graph);
-
   InternalCodeAllocator allocator;
   codegen->Compile(&allocator);
   Run(allocator, *codegen, has_result, expected);
 }
 
 template <typename Expected>
-static void RunCode(InstructionSet target_isa,
+static void RunCode(CodeGenerator* codegen,
+                    HGraph* graph,
+                    std::function<void(HGraph*)> hook_before_codegen,
+                    bool has_result,
+                    Expected expected) {
+  ValidateGraph(graph);
+  RunCodeNoCheck(codegen, graph, hook_before_codegen, has_result, expected);
+}
+
+template <typename Expected>
+static void RunCode(CodegenTargetConfig target_config,
                     HGraph* graph,
                     std::function<void(HGraph*)> hook_before_codegen,
                     bool has_result,
                     Expected expected) {
   CompilerOptions compiler_options;
-#ifdef ART_ENABLE_CODEGEN_arm
-  if (target_isa == kArm || target_isa == kThumb2) {
-    std::unique_ptr<const ArmInstructionSetFeatures> features_arm(
-        ArmInstructionSetFeatures::FromCppDefines());
-    TestCodeGeneratorARM codegenARM(graph, *features_arm.get(), compiler_options);
-    RunCode(&codegenARM, graph, hook_before_codegen, has_result, expected);
-  }
-#endif
-#ifdef ART_ENABLE_CODEGEN_arm64
-  if (target_isa == kArm64) {
-    std::unique_ptr<const Arm64InstructionSetFeatures> features_arm64(
-        Arm64InstructionSetFeatures::FromCppDefines());
-    arm64::CodeGeneratorARM64 codegenARM64(graph, *features_arm64.get(), compiler_options);
-    RunCode(&codegenARM64, graph, hook_before_codegen, has_result, expected);
-  }
-#endif
-#ifdef ART_ENABLE_CODEGEN_x86
-  if (target_isa == kX86) {
-    std::unique_ptr<const X86InstructionSetFeatures> features_x86(
-        X86InstructionSetFeatures::FromCppDefines());
-    TestCodeGeneratorX86 codegenX86(graph, *features_x86.get(), compiler_options);
-    RunCode(&codegenX86, graph, hook_before_codegen, has_result, expected);
-  }
-#endif
-#ifdef ART_ENABLE_CODEGEN_x86_64
-  if (target_isa == kX86_64) {
-    std::unique_ptr<const X86_64InstructionSetFeatures> features_x86_64(
-        X86_64InstructionSetFeatures::FromCppDefines());
-    x86_64::CodeGeneratorX86_64 codegenX86_64(graph, *features_x86_64.get(), compiler_options);
-    RunCode(&codegenX86_64, graph, hook_before_codegen, has_result, expected);
-  }
-#endif
-#ifdef ART_ENABLE_CODEGEN_mips
-  if (target_isa == kMips) {
-    std::unique_ptr<const MipsInstructionSetFeatures> features_mips(
-        MipsInstructionSetFeatures::FromCppDefines());
-    mips::CodeGeneratorMIPS codegenMIPS(graph, *features_mips.get(), compiler_options);
-    RunCode(&codegenMIPS, graph, hook_before_codegen, has_result, expected);
-  }
-#endif
-#ifdef ART_ENABLE_CODEGEN_mips64
-  if (target_isa == kMips64) {
-    std::unique_ptr<const Mips64InstructionSetFeatures> features_mips64(
-        Mips64InstructionSetFeatures::FromCppDefines());
-    mips64::CodeGeneratorMIPS64 codegenMIPS64(graph, *features_mips64.get(), compiler_options);
-    RunCode(&codegenMIPS64, graph, hook_before_codegen, has_result, expected);
-  }
-#endif
+  CodeGenerator* codegen = target_config.CreateCodeGenerator(graph, compiler_options);
+  RunCode(codegen, graph, hook_before_codegen, has_result, expected);
 }
 
-static ::std::vector<InstructionSet> GetTargetISAs() {
-  ::std::vector<InstructionSet> v;
-  // Add all ISAs that are executable on hardware or on simulator.
-  const ::std::vector<InstructionSet> executable_isa_candidates = {
-    kArm,
-    kArm64,
-    kThumb2,
-    kX86,
-    kX86_64,
-    kMips,
-    kMips64
+#ifdef ART_ENABLE_CODEGEN_arm
+CodeGenerator* create_codegen_arm(HGraph* graph, const CompilerOptions& compiler_options) {
+  std::unique_ptr<const ArmInstructionSetFeatures> features_arm(
+      ArmInstructionSetFeatures::FromCppDefines());
+  return new (graph->GetArena()) TestCodeGeneratorARM(graph,
+                                                      *features_arm.get(),
+                                                      compiler_options);
+}
+#endif
+
+#ifdef ART_ENABLE_CODEGEN_arm64
+CodeGenerator* create_codegen_arm64(HGraph* graph, const CompilerOptions& compiler_options) {
+  std::unique_ptr<const Arm64InstructionSetFeatures> features_arm64(
+      Arm64InstructionSetFeatures::FromCppDefines());
+  return new (graph->GetArena()) arm64::CodeGeneratorARM64(graph,
+                                                           *features_arm64.get(),
+                                                           compiler_options);
+}
+#endif
+
+#ifdef ART_ENABLE_CODEGEN_x86
+CodeGenerator* create_codegen_x86(HGraph* graph, const CompilerOptions& compiler_options) {
+  std::unique_ptr<const X86InstructionSetFeatures> features_x86(
+      X86InstructionSetFeatures::FromCppDefines());
+  return new (graph->GetArena()) TestCodeGeneratorX86(graph, *features_x86.get(), compiler_options);
+}
+#endif
+
+#ifdef ART_ENABLE_CODEGEN_x86_64
+CodeGenerator* create_codegen_x86_64(HGraph* graph, const CompilerOptions& compiler_options) {
+  std::unique_ptr<const X86_64InstructionSetFeatures> features_x86_64(
+     X86_64InstructionSetFeatures::FromCppDefines());
+  return new (graph->GetArena())
+      x86_64::CodeGeneratorX86_64(graph, *features_x86_64.get(), compiler_options);
+}
+#endif
+
+#ifdef ART_ENABLE_CODEGEN_mips
+CodeGenerator* create_codegen_mips(HGraph* graph, const CompilerOptions& compiler_options) {
+  std::unique_ptr<const MipsInstructionSetFeatures> features_mips(
+      MipsInstructionSetFeatures::FromCppDefines());
+  return new (graph->GetArena())
+      mips::CodeGeneratorMIPS(graph, *features_mips.get(), compiler_options);
+}
+#endif
+
+#ifdef ART_ENABLE_CODEGEN_mips64
+CodeGenerator* create_codegen_mips64(HGraph* graph, const CompilerOptions& compiler_options) {
+  std::unique_ptr<const Mips64InstructionSetFeatures> features_mips64(
+      Mips64InstructionSetFeatures::FromCppDefines());
+  return new (graph->GetArena())
+      mips64::CodeGeneratorMIPS64(graph, *features_mips64.get(), compiler_options);
+}
+#endif
+
+// Return all combinations of ISA and code generator that are executable on
+// hardware, or on simulator, and that we'd like to test.
+static ::std::vector<CodegenTargetConfig> GetTargetConfigs() {
+  ::std::vector<CodegenTargetConfig> v;
+  ::std::vector<CodegenTargetConfig> test_config_candidates = {
+#ifdef ART_ENABLE_CODEGEN_arm
+    CodegenTargetConfig(kArm, create_codegen_arm),
+    CodegenTargetConfig(kThumb2, create_codegen_arm),
+#endif
+#ifdef ART_ENABLE_CODEGEN_arm64
+    CodegenTargetConfig(kArm64, create_codegen_arm64),
+#endif
+#ifdef ART_ENABLE_CODEGEN_x86
+    CodegenTargetConfig(kX86, create_codegen_x86),
+#endif
+#ifdef ART_ENABLE_CODEGEN_x86_64
+    CodegenTargetConfig(kX86_64, create_codegen_x86_64),
+#endif
+#ifdef ART_ENABLE_CODEGEN_mips
+    CodegenTargetConfig(kMips, create_codegen_mips),
+#endif
+#ifdef ART_ENABLE_CODEGEN_mips64
+    CodegenTargetConfig(kMips64, create_codegen_mips64)
+#endif
   };
 
-  for (auto target_isa : executable_isa_candidates) {
-    if (CanExecute(target_isa)) {
-      v.push_back(target_isa);
+  for (auto test_config : test_config_candidates) {
+    if (CanExecute(test_config.GetInstructionSet())) {
+      v.push_back(test_config);
     }
   }
 
@@ -331,26 +381,26 @@
 static void TestCode(const uint16_t* data,
                      bool has_result = false,
                      int32_t expected = 0) {
-  for (InstructionSet target_isa : GetTargetISAs()) {
+  for (CodegenTargetConfig target_config : GetTargetConfigs()) {
     ArenaPool pool;
     ArenaAllocator arena(&pool);
     HGraph* graph = CreateCFG(&arena, data);
     // Remove suspend checks, they cannot be executed in this context.
     RemoveSuspendChecks(graph);
-    RunCode(target_isa, graph, [](HGraph*) {}, has_result, expected);
+    RunCode(target_config, graph, [](HGraph*) {}, has_result, expected);
   }
 }
 
 static void TestCodeLong(const uint16_t* data,
                          bool has_result,
                          int64_t expected) {
-  for (InstructionSet target_isa : GetTargetISAs()) {
+  for (CodegenTargetConfig target_config : GetTargetConfigs()) {
     ArenaPool pool;
     ArenaAllocator arena(&pool);
     HGraph* graph = CreateCFG(&arena, data, Primitive::kPrimLong);
     // Remove suspend checks, they cannot be executed in this context.
     RemoveSuspendChecks(graph);
-    RunCode(target_isa, graph, [](HGraph*) {}, has_result, expected);
+    RunCode(target_config, graph, [](HGraph*) {}, has_result, expected);
   }
 }
 
@@ -667,7 +717,7 @@
 }
 
 TEST_F(CodegenTest, NonMaterializedCondition) {
-  for (InstructionSet target_isa : GetTargetISAs()) {
+  for (CodegenTargetConfig target_config : GetTargetConfigs()) {
     ArenaPool pool;
     ArenaAllocator allocator(&pool);
 
@@ -715,12 +765,12 @@
       block->InsertInstructionBefore(move, block->GetLastInstruction());
     };
 
-    RunCode(target_isa, graph, hook_before_codegen, true, 0);
+    RunCode(target_config, graph, hook_before_codegen, true, 0);
   }
 }
 
 TEST_F(CodegenTest, MaterializedCondition1) {
-  for (InstructionSet target_isa : GetTargetISAs()) {
+  for (CodegenTargetConfig target_config : GetTargetConfigs()) {
     // Check that condition are materialized correctly. A materialized condition
     // should yield `1` if it evaluated to true, and `0` otherwise.
     // We force the materialization of comparisons for different combinations of
@@ -762,13 +812,13 @@
         HParallelMove* move = new (graph_in->GetArena()) HParallelMove(graph_in->GetArena());
         block->InsertInstructionBefore(move, block->GetLastInstruction());
       };
-      RunCode(target_isa, graph, hook_before_codegen, true, lhs[i] < rhs[i]);
+      RunCode(target_config, graph, hook_before_codegen, true, lhs[i] < rhs[i]);
     }
   }
 }
 
 TEST_F(CodegenTest, MaterializedCondition2) {
-  for (InstructionSet target_isa : GetTargetISAs()) {
+  for (CodegenTargetConfig target_config : GetTargetConfigs()) {
     // Check that HIf correctly interprets a materialized condition.
     // We force the materialization of comparisons for different combinations of
     // inputs. An HIf takes the materialized combination as input and returns a
@@ -830,7 +880,7 @@
         HParallelMove* move = new (graph_in->GetArena()) HParallelMove(graph_in->GetArena());
         block->InsertInstructionBefore(move, block->GetLastInstruction());
       };
-      RunCode(target_isa, graph, hook_before_codegen, true, lhs[i] < rhs[i]);
+      RunCode(target_config, graph, hook_before_codegen, true, lhs[i] < rhs[i]);
     }
   }
 }
@@ -859,7 +909,7 @@
                            int64_t i,
                            int64_t j,
                            Primitive::Type type,
-                           const InstructionSet target_isa) {
+                           const CodegenTargetConfig target_config) {
   ArenaPool pool;
   ArenaAllocator allocator(&pool);
   HGraph* graph = CreateGraph(&allocator);
@@ -941,51 +991,28 @@
   block->AddInstruction(new (&allocator) HReturn(comparison));
 
   graph->BuildDominatorTree();
-  RunCode(target_isa, graph, [](HGraph*) {}, true, expected_result);
+  RunCode(target_config, graph, [](HGraph*) {}, true, expected_result);
 }
 
 TEST_F(CodegenTest, ComparisonsInt) {
-  for (InstructionSet target_isa : GetTargetISAs()) {
+  for (CodegenTargetConfig target_config : GetTargetConfigs()) {
     for (int64_t i = -1; i <= 1; i++) {
       for (int64_t j = -1; j <= 1; j++) {
-        TestComparison(kCondEQ, i, j, Primitive::kPrimInt, target_isa);
-        TestComparison(kCondNE, i, j, Primitive::kPrimInt, target_isa);
-        TestComparison(kCondLT, i, j, Primitive::kPrimInt, target_isa);
-        TestComparison(kCondLE, i, j, Primitive::kPrimInt, target_isa);
-        TestComparison(kCondGT, i, j, Primitive::kPrimInt, target_isa);
-        TestComparison(kCondGE, i, j, Primitive::kPrimInt, target_isa);
-        TestComparison(kCondB,  i, j, Primitive::kPrimInt, target_isa);
-        TestComparison(kCondBE, i, j, Primitive::kPrimInt, target_isa);
-        TestComparison(kCondA,  i, j, Primitive::kPrimInt, target_isa);
-        TestComparison(kCondAE, i, j, Primitive::kPrimInt, target_isa);
+        for (int cond = kCondFirst; cond <= kCondLast; cond++) {
+          TestComparison(static_cast<IfCondition>(cond), i, j, Primitive::kPrimInt, target_config);
+        }
       }
     }
   }
 }
 
 TEST_F(CodegenTest, ComparisonsLong) {
-  // TODO: make MIPS work for long
-  if (kRuntimeISA == kMips || kRuntimeISA == kMips64) {
-    return;
-  }
-
-  for (InstructionSet target_isa : GetTargetISAs()) {
-    if (target_isa == kMips || target_isa == kMips64) {
-      continue;
-    }
-
+  for (CodegenTargetConfig target_config : GetTargetConfigs()) {
     for (int64_t i = -1; i <= 1; i++) {
       for (int64_t j = -1; j <= 1; j++) {
-        TestComparison(kCondEQ, i, j, Primitive::kPrimLong, target_isa);
-        TestComparison(kCondNE, i, j, Primitive::kPrimLong, target_isa);
-        TestComparison(kCondLT, i, j, Primitive::kPrimLong, target_isa);
-        TestComparison(kCondLE, i, j, Primitive::kPrimLong, target_isa);
-        TestComparison(kCondGT, i, j, Primitive::kPrimLong, target_isa);
-        TestComparison(kCondGE, i, j, Primitive::kPrimLong, target_isa);
-        TestComparison(kCondB,  i, j, Primitive::kPrimLong, target_isa);
-        TestComparison(kCondBE, i, j, Primitive::kPrimLong, target_isa);
-        TestComparison(kCondA,  i, j, Primitive::kPrimLong, target_isa);
-        TestComparison(kCondAE, i, j, Primitive::kPrimLong, target_isa);
+        for (int cond = kCondFirst; cond <= kCondLast; cond++) {
+          TestComparison(static_cast<IfCondition>(cond), i, j, Primitive::kPrimLong, target_config);
+        }
       }
     }
   }
diff --git a/compiler/optimizing/dead_code_elimination.cc b/compiler/optimizing/dead_code_elimination.cc
index e1bde7c..aa3f268 100644
--- a/compiler/optimizing/dead_code_elimination.cc
+++ b/compiler/optimizing/dead_code_elimination.cc
@@ -16,7 +16,7 @@
 
 #include "dead_code_elimination.h"
 
-#include "utils/array_ref.h"
+#include "base/array_ref.h"
 #include "base/bit_vector-inl.h"
 #include "ssa_phi_elimination.h"
 
diff --git a/compiler/optimizing/induction_var_range.cc b/compiler/optimizing/induction_var_range.cc
index 5e587e0..18e6f5c 100644
--- a/compiler/optimizing/induction_var_range.cc
+++ b/compiler/optimizing/induction_var_range.cc
@@ -143,42 +143,129 @@
   // Find range.
   chase_hint_ = chase_hint;
   bool in_body = context->GetBlock() != loop->GetHeader();
+  int64_t stride_value = 0;
   *min_val = GetVal(info, trip, in_body, /* is_min */ true);
   *max_val = SimplifyMax(GetVal(info, trip, in_body, /* is_min */ false));
-  *needs_finite_test = NeedsTripCount(info) && IsUnsafeTripCount(trip);
+  *needs_finite_test = NeedsTripCount(info, &stride_value) && IsUnsafeTripCount(trip);
   return true;
 }
 
-bool InductionVarRange::CanGenerateCode(HInstruction* context,
-                                        HInstruction* instruction,
-                                        /*out*/bool* needs_finite_test,
-                                        /*out*/bool* needs_taken_test) {
+bool InductionVarRange::CanGenerateRange(HInstruction* context,
+                                         HInstruction* instruction,
+                                         /*out*/bool* needs_finite_test,
+                                         /*out*/bool* needs_taken_test) {
+  bool is_last_value = false;
+  int64_t stride_value = 0;
   return GenerateCode(context,
                       instruction,
-                      nullptr, nullptr, nullptr, nullptr, nullptr,  // nothing generated yet
+                      is_last_value,
+                      nullptr,
+                      nullptr,
+                      nullptr,
+                      nullptr,
+                      nullptr,  // nothing generated yet
+                      &stride_value,
                       needs_finite_test,
-                      needs_taken_test);
+                      needs_taken_test)
+      && (stride_value == -1 ||
+          stride_value == 0 ||
+          stride_value == 1);  // avoid wrap-around anomalies.
 }
 
-void InductionVarRange::GenerateRangeCode(HInstruction* context,
-                                          HInstruction* instruction,
-                                          HGraph* graph,
-                                          HBasicBlock* block,
-                                          /*out*/HInstruction** lower,
-                                          /*out*/HInstruction** upper) {
+void InductionVarRange::GenerateRange(HInstruction* context,
+                                      HInstruction* instruction,
+                                      HGraph* graph,
+                                      HBasicBlock* block,
+                                      /*out*/HInstruction** lower,
+                                      /*out*/HInstruction** upper) {
+  bool is_last_value = false;
+  int64_t s = 0;
   bool b1, b2;  // unused
-  if (!GenerateCode(context, instruction, graph, block, lower, upper, nullptr, &b1, &b2)) {
-    LOG(FATAL) << "Failed precondition: GenerateCode()";
+  if (!GenerateCode(context,
+                    instruction,
+                    is_last_value,
+                    graph,
+                    block,
+                    lower,
+                    upper,
+                    nullptr,
+                    &s,
+                    &b1,
+                    &b2)) {
+    LOG(FATAL) << "Failed precondition: CanGenerateRange()";
   }
 }
 
-void InductionVarRange::GenerateTakenTest(HInstruction* context,
-                                          HGraph* graph,
-                                          HBasicBlock* block,
-                                          /*out*/HInstruction** taken_test) {
+HInstruction* InductionVarRange::GenerateTakenTest(HInstruction* context,
+                                                   HGraph* graph,
+                                                   HBasicBlock* block) {
+  HInstruction* taken_test = nullptr;
+  bool is_last_value = false;
+  int64_t stride_value = 0;
   bool b1, b2;  // unused
-  if (!GenerateCode(context, context, graph, block, nullptr, nullptr, taken_test, &b1, &b2)) {
-    LOG(FATAL) << "Failed precondition: GenerateCode()";
+  if (!GenerateCode(context,
+                    context,
+                    is_last_value,
+                    graph,
+                    block,
+                    nullptr,
+                    nullptr,
+                    &taken_test,
+                    &stride_value,
+                    &b1,
+                    &b2)) {
+    LOG(FATAL) << "Failed precondition: CanGenerateRange()";
+  }
+  return taken_test;
+}
+
+bool InductionVarRange::CanGenerateLastValue(HInstruction* instruction) {
+  bool is_last_value = true;
+  int64_t stride_value = 0;
+  bool needs_finite_test = false;
+  bool needs_taken_test = false;
+  return GenerateCode(instruction,
+                      instruction,
+                      is_last_value,
+                      nullptr,
+                      nullptr,
+                      nullptr,
+                      nullptr,
+                      nullptr,  // nothing generated yet
+                      &stride_value, &needs_finite_test, &needs_taken_test)
+      && !needs_finite_test && !needs_taken_test;
+}
+
+HInstruction* InductionVarRange::GenerateLastValue(HInstruction* instruction,
+                                                   HGraph* graph,
+                                                   HBasicBlock* block) {
+  HInstruction* last_value = nullptr;
+  bool is_last_value = true;
+  int64_t stride_value = 0;
+  bool b1, b2;  // unused
+  if (!GenerateCode(instruction,
+                    instruction,
+                    is_last_value,
+                    graph,
+                    block,
+                    &last_value,
+                    &last_value,
+                    nullptr,
+                    &stride_value,
+                    &b1,
+                    &b2)) {
+    LOG(FATAL) << "Failed precondition: CanGenerateLastValue()";
+  }
+  return last_value;
+}
+
+void InductionVarRange::Replace(HInstruction* instruction,
+                                HInstruction* fetch,
+                                HInstruction* replacement) {
+  for (HLoopInformation* lp = instruction->GetBlock()->GetLoopInformation();  // closest enveloping loop
+       lp != nullptr;
+       lp = lp->GetPreHeader()->GetLoopInformation()) {
+    ReplaceInduction(induction_analysis_->LookupInfo(lp, instruction), fetch, replacement);
   }
 }
 
@@ -260,12 +347,13 @@
   return false;
 }
 
-bool InductionVarRange::NeedsTripCount(HInductionVarAnalysis::InductionInfo* info) const {
+bool InductionVarRange::NeedsTripCount(HInductionVarAnalysis::InductionInfo* info,
+                                       int64_t* stride_value) const {
   if (info != nullptr) {
     if (info->induction_class == HInductionVarAnalysis::kLinear) {
-      return true;
+      return IsConstant(info->op_a, kExact, stride_value);
     } else if (info->induction_class == HInductionVarAnalysis::kWrapAround) {
-      return NeedsTripCount(info->op_b);
+      return NeedsTripCount(info->op_b, stride_value);
     }
   }
   return false;
@@ -618,11 +706,13 @@
 
 bool InductionVarRange::GenerateCode(HInstruction* context,
                                      HInstruction* instruction,
+                                     bool is_last_value,
                                      HGraph* graph,
                                      HBasicBlock* block,
                                      /*out*/HInstruction** lower,
                                      /*out*/HInstruction** upper,
                                      /*out*/HInstruction** taken_test,
+                                     /*out*/int64_t* stride_value,
                                      /*out*/bool* needs_finite_test,
                                      /*out*/bool* needs_taken_test) const {
   HLoopInformation* loop = nullptr;
@@ -637,8 +727,19 @@
   // code does not use the trip-count explicitly (since there could be an implicit relation
   // between e.g. an invariant subscript and a not-taken condition).
   bool in_body = context->GetBlock() != loop->GetHeader();
-  *needs_finite_test = NeedsTripCount(info) && IsUnsafeTripCount(trip);
+  *stride_value = 0;
+  *needs_finite_test = NeedsTripCount(info, stride_value) && IsUnsafeTripCount(trip);
   *needs_taken_test = IsBodyTripCount(trip);
+  // Handle last value request.
+  if (is_last_value) {
+    if (info->induction_class != HInductionVarAnalysis::kLinear) {
+      return false;
+    } else if (*stride_value > 0) {
+      lower = nullptr;
+    } else {
+      upper = nullptr;
+    }
+  }
   // Code generation for taken test: generate the code when requested or otherwise analyze
   // if code generation is feasible when taken test is needed.
   if (taken_test != nullptr) {
@@ -666,6 +767,10 @@
                                      bool in_body,
                                      bool is_min) const {
   if (info != nullptr) {
+    // If during codegen, the result is not needed (nullptr), simply return success.
+    if (graph != nullptr && result == nullptr) {
+      return true;
+    }
     // Verify type safety.
     Primitive::Type type = Primitive::kPrimInt;
     if (info->type != type) {
@@ -757,25 +862,28 @@
         }
         break;
       case HInductionVarAnalysis::kLinear: {
-        // Linear induction a * i + b, for normalized 0 <= i < TC. Restrict to unit stride only
-        // to avoid arithmetic wrap-around situations that are hard to guard against.
+        // Linear induction a * i + b, for normalized 0 <= i < TC. For ranges, this should
+        // be restricted to a unit stride to avoid arithmetic wrap-around situations that
+        // are harder to guard against. For a last value, requesting min/max based on any
+        // stride yields right value.
         int64_t stride_value = 0;
         if (IsConstant(info->op_a, kExact, &stride_value)) {
-          if (stride_value == 1 || stride_value == -1) {
-            const bool is_min_a = stride_value == 1 ? is_min : !is_min;
-            if (GenerateCode(trip,       trip, graph, block, &opa, in_body, is_min_a) &&
-                GenerateCode(info->op_b, trip, graph, block, &opb, in_body, is_min)) {
-              if (graph != nullptr) {
-                HInstruction* oper;
-                if (stride_value == 1) {
-                  oper = new (graph->GetArena()) HAdd(type, opa, opb);
-                } else {
-                  oper = new (graph->GetArena()) HSub(type, opb, opa);
-                }
-                *result = Insert(block, oper);
+          const bool is_min_a = stride_value >= 0 ? is_min : !is_min;
+          if (GenerateCode(trip,       trip, graph, block, &opa, in_body, is_min_a) &&
+              GenerateCode(info->op_b, trip, graph, block, &opb, in_body, is_min)) {
+            if (graph != nullptr) {
+              HInstruction* oper;
+              if (stride_value == 1) {
+                oper = new (graph->GetArena()) HAdd(type, opa, opb);
+              } else if (stride_value == -1) {
+                oper = new (graph->GetArena()) HSub(type, opb, opa);
+              } else {
+                HInstruction* mul = new (graph->GetArena()) HMul(type, graph->GetIntConstant(stride_value), opa);
+                oper = new (graph->GetArena()) HAdd(type, Insert(block, mul), opb);
               }
-              return true;
+              *result = Insert(block, oper);
             }
+            return true;
           }
         }
         break;
@@ -800,4 +908,18 @@
   return false;
 }
 
+void InductionVarRange::ReplaceInduction(HInductionVarAnalysis::InductionInfo* info,
+                                         HInstruction* fetch,
+                                         HInstruction* replacement) {
+  if (info != nullptr) {
+    if (info->induction_class == HInductionVarAnalysis::kInvariant &&
+        info->operation == HInductionVarAnalysis::kFetch &&
+        info->fetch == fetch) {
+      info->fetch = replacement;
+    }
+    ReplaceInduction(info->op_a, fetch, replacement);
+    ReplaceInduction(info->op_b, fetch, replacement);
+  }
+}
+
 }  // namespace art
diff --git a/compiler/optimizing/induction_var_range.h b/compiler/optimizing/induction_var_range.h
index 00aaa16..63850b3 100644
--- a/compiler/optimizing/induction_var_range.h
+++ b/compiler/optimizing/induction_var_range.h
@@ -76,10 +76,10 @@
    * and need_taken test flags denote if an additional finite-test and/or taken-test
    * are needed to protect the range evaluation inside its loop.
    */
-  bool CanGenerateCode(HInstruction* context,
-                       HInstruction* instruction,
-                       /*out*/ bool* needs_finite_test,
-                       /*out*/ bool* needs_taken_test);
+  bool CanGenerateRange(HInstruction* context,
+                        HInstruction* instruction,
+                        /*out*/ bool* needs_finite_test,
+                        /*out*/ bool* needs_taken_test);
 
   /**
    * Generates the actual code in the HIR for the lower and upper bound expressions on the
@@ -94,25 +94,42 @@
    *   lower: add x, 0
    *   upper: add x, 5
    *
-   * Precondition: CanGenerateCode() returns true.
+   * Precondition: CanGenerateRange() returns true.
    */
-  void GenerateRangeCode(HInstruction* context,
-                         HInstruction* instruction,
-                         HGraph* graph,
-                         HBasicBlock* block,
-                         /*out*/ HInstruction** lower,
-                         /*out*/ HInstruction** upper);
+  void GenerateRange(HInstruction* context,
+                     HInstruction* instruction,
+                     HGraph* graph,
+                     HBasicBlock* block,
+                     /*out*/ HInstruction** lower,
+                     /*out*/ HInstruction** upper);
 
   /**
    * Generates explicit taken-test for the loop in the given context. Code is generated in
-   * given block and graph. The taken-test is returned in parameter test.
+   * given block and graph. Returns generated taken-test.
    *
-   * Precondition: CanGenerateCode() returns true and needs_taken_test is set.
+   * Precondition: CanGenerateRange() returns true and needs_taken_test is set.
    */
-  void GenerateTakenTest(HInstruction* context,
-                         HGraph* graph,
-                         HBasicBlock* block,
-                         /*out*/ HInstruction** taken_test);
+  HInstruction* GenerateTakenTest(HInstruction* context, HGraph* graph, HBasicBlock* block);
+
+  /**
+   * Returns true if induction analysis is able to generate code for last value of
+   * the given instruction inside the closest enveloping loop.
+   */
+  bool CanGenerateLastValue(HInstruction* instruction);
+
+  /**
+   * Generates last value of the given instruction in the closest enveloping loop.
+   * Code is generated in given block and graph. Returns generated last value.
+   *
+   * Precondition: CanGenerateLastValue() returns true.
+   */
+  HInstruction* GenerateLastValue(HInstruction* instruction, HGraph* graph, HBasicBlock* block);
+
+  /**
+   * Updates all matching fetches with the given replacement in all induction information
+   * that is associated with the given instruction.
+   */
+  void Replace(HInstruction* instruction, HInstruction* fetch, HInstruction* replacement);
 
  private:
   /*
@@ -140,7 +157,8 @@
                         /*out*/ HInductionVarAnalysis::InductionInfo** trip) const;
 
   bool HasFetchInLoop(HInductionVarAnalysis::InductionInfo* info) const;
-  bool NeedsTripCount(HInductionVarAnalysis::InductionInfo* info) const;
+  bool NeedsTripCount(HInductionVarAnalysis::InductionInfo* info,
+                      /*out*/ int64_t* stride_value) const;
   bool IsBodyTripCount(HInductionVarAnalysis::InductionInfo* trip) const;
   bool IsUnsafeTripCount(HInductionVarAnalysis::InductionInfo* trip) const;
   bool IsWellBehavedTripCount(HInductionVarAnalysis::InductionInfo* trip) const;
@@ -186,17 +204,19 @@
   Value MergeVal(Value v1, Value v2, bool is_min) const;
 
   /**
-   * Generates code for lower/upper/taken-test in the HIR. Returns true on success.
-   * With values nullptr, the method can be used to determine if code generation
+   * Generates code for lower/upper/taken-test or last value in the HIR. Returns true on
+   * success. With values nullptr, the method can be used to determine if code generation
    * would be successful without generating actual code yet.
    */
   bool GenerateCode(HInstruction* context,
                     HInstruction* instruction,
+                    bool is_last_val,
                     HGraph* graph,
                     HBasicBlock* block,
                     /*out*/ HInstruction** lower,
                     /*out*/ HInstruction** upper,
                     /*out*/ HInstruction** taken_test,
+                    /*out*/ int64_t* stride_value,
                     /*out*/ bool* needs_finite_test,
                     /*out*/ bool* needs_taken_test) const;
 
@@ -208,6 +228,10 @@
                     bool in_body,
                     bool is_min) const;
 
+  void ReplaceInduction(HInductionVarAnalysis::InductionInfo* info,
+                        HInstruction* fetch,
+                        HInstruction* replacement);
+
   /** Results of prior induction variable analysis. */
   HInductionVarAnalysis* induction_analysis_;
 
diff --git a/compiler/optimizing/induction_var_range_test.cc b/compiler/optimizing/induction_var_range_test.cc
index 4ea170f..8bbdd4a 100644
--- a/compiler/optimizing/induction_var_range_test.cc
+++ b/compiler/optimizing/induction_var_range_test.cc
@@ -75,34 +75,34 @@
     // Control flow.
     loop_preheader_ = new (&allocator_) HBasicBlock(graph_);
     graph_->AddBlock(loop_preheader_);
-    HBasicBlock* loop_header = new (&allocator_) HBasicBlock(graph_);
-    graph_->AddBlock(loop_header);
-    HBasicBlock* loop_body = new (&allocator_) HBasicBlock(graph_);
-    graph_->AddBlock(loop_body);
+    loop_header_ = new (&allocator_) HBasicBlock(graph_);
+    graph_->AddBlock(loop_header_);
+    loop_body_ = new (&allocator_) HBasicBlock(graph_);
+    graph_->AddBlock(loop_body_);
     HBasicBlock* return_block = new (&allocator_) HBasicBlock(graph_);
     graph_->AddBlock(return_block);
     entry_block_->AddSuccessor(loop_preheader_);
-    loop_preheader_->AddSuccessor(loop_header);
-    loop_header->AddSuccessor(loop_body);
-    loop_header->AddSuccessor(return_block);
-    loop_body->AddSuccessor(loop_header);
+    loop_preheader_->AddSuccessor(loop_header_);
+    loop_header_->AddSuccessor(loop_body_);
+    loop_header_->AddSuccessor(return_block);
+    loop_body_->AddSuccessor(loop_header_);
     return_block->AddSuccessor(exit_block_);
     // Instructions.
     loop_preheader_->AddInstruction(new (&allocator_) HGoto());
     HPhi* phi = new (&allocator_) HPhi(&allocator_, 0, 0, Primitive::kPrimInt);
-    loop_header->AddPhi(phi);
+    loop_header_->AddPhi(phi);
     phi->AddInput(graph_->GetIntConstant(lower));  // i = l
     if (stride > 0) {
       condition_ = new (&allocator_) HLessThan(phi, upper);  // i < u
     } else {
       condition_ = new (&allocator_) HGreaterThan(phi, upper);  // i > u
     }
-    loop_header->AddInstruction(condition_);
-    loop_header->AddInstruction(new (&allocator_) HIf(condition_));
+    loop_header_->AddInstruction(condition_);
+    loop_header_->AddInstruction(new (&allocator_) HIf(condition_));
     increment_ = new (&allocator_) HAdd(Primitive::kPrimInt, phi, graph_->GetIntConstant(stride));
-    loop_body->AddInstruction(increment_);  // i += s
+    loop_body_->AddInstruction(increment_);  // i += s
     phi->AddInput(increment_);
-    loop_body->AddInstruction(new (&allocator_) HGoto());
+    loop_body_->AddInstruction(new (&allocator_) HGoto());
     return_block->AddInstruction(new (&allocator_) HReturnVoid());
     exit_block_->AddInstruction(new (&allocator_) HExit());
   }
@@ -192,7 +192,8 @@
   //
 
   bool NeedsTripCount(HInductionVarAnalysis::InductionInfo* info) {
-    return range_.NeedsTripCount(info);
+    int64_t s = 0;
+    return range_.NeedsTripCount(info, &s);
   }
 
   bool IsBodyTripCount(HInductionVarAnalysis::InductionInfo* trip) {
@@ -251,6 +252,8 @@
   HBasicBlock* entry_block_;
   HBasicBlock* exit_block_;
   HBasicBlock* loop_preheader_;
+  HBasicBlock* loop_header_;
+  HBasicBlock* loop_body_;
   HInductionVarAnalysis* iva_;
   InductionVarRange range_;
 
@@ -600,15 +603,19 @@
 
   Value v1, v2;
   bool needs_finite_test = true;
+  bool needs_taken_test = true;
+
+  HInstruction* phi = condition_->InputAt(0);
+  HInstruction* exit = exit_block_->GetLastInstruction();
 
   // In context of header: known.
-  range_.GetInductionRange(condition_, condition_->InputAt(0), x_, &v1, &v2, &needs_finite_test);
+  range_.GetInductionRange(condition_, phi, x_, &v1, &v2, &needs_finite_test);
   EXPECT_FALSE(needs_finite_test);
   ExpectEqual(Value(0), v1);
   ExpectEqual(Value(1000), v2);
 
   // In context of loop-body: known.
-  range_.GetInductionRange(increment_, condition_->InputAt(0), x_, &v1, &v2, &needs_finite_test);
+  range_.GetInductionRange(increment_, phi, x_, &v1, &v2, &needs_finite_test);
   EXPECT_FALSE(needs_finite_test);
   ExpectEqual(Value(0), v1);
   ExpectEqual(Value(999), v2);
@@ -616,6 +623,20 @@
   EXPECT_FALSE(needs_finite_test);
   ExpectEqual(Value(1), v1);
   ExpectEqual(Value(1000), v2);
+
+  // Induction vs. no-induction.
+  EXPECT_TRUE(range_.CanGenerateRange(increment_, phi, &needs_finite_test, &needs_taken_test));
+  EXPECT_TRUE(range_.CanGenerateLastValue(phi));
+  EXPECT_FALSE(range_.CanGenerateRange(exit, exit, &needs_finite_test, &needs_taken_test));
+  EXPECT_FALSE(range_.CanGenerateLastValue(exit));
+
+  // Last value (unsimplified).
+  HInstruction* last = range_.GenerateLastValue(phi, graph_, loop_preheader_);
+  ASSERT_TRUE(last->IsAdd());
+  ASSERT_TRUE(last->InputAt(0)->IsIntConstant());
+  EXPECT_EQ(1000, last->InputAt(0)->AsIntConstant()->GetValue());
+  ASSERT_TRUE(last->InputAt(1)->IsIntConstant());
+  EXPECT_EQ(0, last->InputAt(1)->AsIntConstant()->GetValue());
 }
 
 TEST_F(InductionVarRangeTest, ConstantTripCountDown) {
@@ -624,15 +645,19 @@
 
   Value v1, v2;
   bool needs_finite_test = true;
+  bool needs_taken_test = true;
+
+  HInstruction* phi = condition_->InputAt(0);
+  HInstruction* exit = exit_block_->GetLastInstruction();
 
   // In context of header: known.
-  range_.GetInductionRange(condition_, condition_->InputAt(0), x_, &v1, &v2, &needs_finite_test);
+  range_.GetInductionRange(condition_, phi, x_, &v1, &v2, &needs_finite_test);
   EXPECT_FALSE(needs_finite_test);
   ExpectEqual(Value(0), v1);
   ExpectEqual(Value(1000), v2);
 
   // In context of loop-body: known.
-  range_.GetInductionRange(increment_, condition_->InputAt(0), x_, &v1, &v2, &needs_finite_test);
+  range_.GetInductionRange(increment_, phi, x_, &v1, &v2, &needs_finite_test);
   EXPECT_FALSE(needs_finite_test);
   ExpectEqual(Value(1), v1);
   ExpectEqual(Value(1000), v2);
@@ -640,6 +665,25 @@
   EXPECT_FALSE(needs_finite_test);
   ExpectEqual(Value(0), v1);
   ExpectEqual(Value(999), v2);
+
+  // Induction vs. no-induction.
+  EXPECT_TRUE(range_.CanGenerateRange(increment_, phi, &needs_finite_test, &needs_taken_test));
+  EXPECT_TRUE(range_.CanGenerateLastValue(phi));
+  EXPECT_FALSE(range_.CanGenerateRange(exit, exit, &needs_finite_test, &needs_taken_test));
+  EXPECT_FALSE(range_.CanGenerateLastValue(exit));
+
+  // Last value (unsimplified).
+  HInstruction* last = range_.GenerateLastValue(phi, graph_, loop_preheader_);
+  ASSERT_TRUE(last->IsSub());
+  ASSERT_TRUE(last->InputAt(0)->IsIntConstant());
+  EXPECT_EQ(1000, last->InputAt(0)->AsIntConstant()->GetValue());
+  ASSERT_TRUE(last->InputAt(1)->IsNeg());
+  last = last->InputAt(1)->InputAt(0);
+  ASSERT_TRUE(last->IsSub());
+  ASSERT_TRUE(last->InputAt(0)->IsIntConstant());
+  EXPECT_EQ(0, last->InputAt(0)->AsIntConstant()->GetValue());
+  ASSERT_TRUE(last->InputAt(1)->IsIntConstant());
+  EXPECT_EQ(1000, last->InputAt(1)->AsIntConstant()->GetValue());
 }
 
 TEST_F(InductionVarRangeTest, SymbolicTripCountUp) {
@@ -650,14 +694,16 @@
   bool needs_finite_test = true;
   bool needs_taken_test = true;
 
+  HInstruction* phi = condition_->InputAt(0);
+
   // In context of header: upper unknown.
-  range_.GetInductionRange(condition_, condition_->InputAt(0), x_, &v1, &v2, &needs_finite_test);
+  range_.GetInductionRange(condition_, phi, x_, &v1, &v2, &needs_finite_test);
   EXPECT_FALSE(needs_finite_test);
   ExpectEqual(Value(0), v1);
   ExpectEqual(Value(), v2);
 
   // In context of loop-body: known.
-  range_.GetInductionRange(increment_, condition_->InputAt(0), x_, &v1, &v2, &needs_finite_test);
+  range_.GetInductionRange(increment_, phi, x_, &v1, &v2, &needs_finite_test);
   EXPECT_FALSE(needs_finite_test);
   ExpectEqual(Value(0), v1);
   ExpectEqual(Value(x_, 1, -1), v2);
@@ -668,19 +714,15 @@
 
   HInstruction* lower = nullptr;
   HInstruction* upper = nullptr;
-  HInstruction* taken = nullptr;
 
   // Can generate code in context of loop-body only.
-  EXPECT_FALSE(range_.CanGenerateCode(
-      condition_, condition_->InputAt(0), &needs_finite_test, &needs_taken_test));
-  ASSERT_TRUE(range_.CanGenerateCode(
-      increment_, condition_->InputAt(0), &needs_finite_test, &needs_taken_test));
+  EXPECT_FALSE(range_.CanGenerateRange(condition_, phi, &needs_finite_test, &needs_taken_test));
+  ASSERT_TRUE(range_.CanGenerateRange(increment_, phi, &needs_finite_test, &needs_taken_test));
   EXPECT_FALSE(needs_finite_test);
   EXPECT_TRUE(needs_taken_test);
 
-  // Generates code.
-  range_.GenerateRangeCode(
-      increment_, condition_->InputAt(0), graph_, loop_preheader_, &lower, &upper);
+  // Generates code (unsimplified).
+  range_.GenerateRange(increment_, phi, graph_, loop_preheader_, &lower, &upper);
 
   // Verify lower is 0+0.
   ASSERT_TRUE(lower != nullptr);
@@ -701,12 +743,19 @@
   EXPECT_EQ(0, upper->InputAt(1)->AsIntConstant()->GetValue());
 
   // Verify taken-test is 0<V.
-  range_.GenerateTakenTest(increment_, graph_, loop_preheader_, &taken);
+  HInstruction* taken = range_.GenerateTakenTest(increment_, graph_, loop_preheader_);
   ASSERT_TRUE(taken != nullptr);
   ASSERT_TRUE(taken->IsLessThan());
   ASSERT_TRUE(taken->InputAt(0)->IsIntConstant());
   EXPECT_EQ(0, taken->InputAt(0)->AsIntConstant()->GetValue());
   EXPECT_TRUE(taken->InputAt(1)->IsParameterValue());
+
+  // Replacement.
+  range_.Replace(loop_header_->GetLastInstruction(), x_, y_);
+  range_.GetInductionRange(increment_, increment_, x_, &v1, &v2, &needs_finite_test);
+  EXPECT_FALSE(needs_finite_test);
+  ExpectEqual(Value(1), v1);
+  ExpectEqual(Value(y_, 1, 0), v2);
 }
 
 TEST_F(InductionVarRangeTest, SymbolicTripCountDown) {
@@ -717,14 +766,16 @@
   bool needs_finite_test = true;
   bool needs_taken_test = true;
 
+  HInstruction* phi = condition_->InputAt(0);
+
   // In context of header: lower unknown.
-  range_.GetInductionRange(condition_, condition_->InputAt(0), x_, &v1, &v2, &needs_finite_test);
+  range_.GetInductionRange(condition_, phi, x_, &v1, &v2, &needs_finite_test);
   EXPECT_FALSE(needs_finite_test);
   ExpectEqual(Value(), v1);
   ExpectEqual(Value(1000), v2);
 
   // In context of loop-body: known.
-  range_.GetInductionRange(increment_, condition_->InputAt(0), x_, &v1, &v2, &needs_finite_test);
+  range_.GetInductionRange(increment_, phi, x_, &v1, &v2, &needs_finite_test);
   EXPECT_FALSE(needs_finite_test);
   ExpectEqual(Value(x_, 1, 1), v1);
   ExpectEqual(Value(1000), v2);
@@ -735,19 +786,15 @@
 
   HInstruction* lower = nullptr;
   HInstruction* upper = nullptr;
-  HInstruction* taken = nullptr;
 
   // Can generate code in context of loop-body only.
-  EXPECT_FALSE(range_.CanGenerateCode(
-      condition_, condition_->InputAt(0), &needs_finite_test, &needs_taken_test));
-  ASSERT_TRUE(range_.CanGenerateCode(
-      increment_, condition_->InputAt(0), &needs_finite_test, &needs_taken_test));
+  EXPECT_FALSE(range_.CanGenerateRange(condition_, phi, &needs_finite_test, &needs_taken_test));
+  ASSERT_TRUE(range_.CanGenerateRange(increment_, phi, &needs_finite_test, &needs_taken_test));
   EXPECT_FALSE(needs_finite_test);
   EXPECT_TRUE(needs_taken_test);
 
-  // Generates code.
-  range_.GenerateRangeCode(
-      increment_, condition_->InputAt(0), graph_, loop_preheader_, &lower, &upper);
+  // Generates code (unsimplified).
+  range_.GenerateRange(increment_, phi, graph_, loop_preheader_, &lower, &upper);
 
   // Verify lower is 1000-((1000-V)-1).
   ASSERT_TRUE(lower != nullptr);
@@ -773,12 +820,19 @@
   EXPECT_EQ(0, upper->InputAt(1)->AsIntConstant()->GetValue());
 
   // Verify taken-test is 1000>V.
-  range_.GenerateTakenTest(increment_, graph_, loop_preheader_, &taken);
+  HInstruction* taken = range_.GenerateTakenTest(increment_, graph_, loop_preheader_);
   ASSERT_TRUE(taken != nullptr);
   ASSERT_TRUE(taken->IsGreaterThan());
   ASSERT_TRUE(taken->InputAt(0)->IsIntConstant());
   EXPECT_EQ(1000, taken->InputAt(0)->AsIntConstant()->GetValue());
   EXPECT_TRUE(taken->InputAt(1)->IsParameterValue());
+
+  // Replacement.
+  range_.Replace(loop_header_->GetLastInstruction(), x_, y_);
+  range_.GetInductionRange(increment_, increment_, x_, &v1, &v2, &needs_finite_test);
+  EXPECT_FALSE(needs_finite_test);
+  ExpectEqual(Value(y_, 1, 0), v1);
+  ExpectEqual(Value(999), v2);
 }
 
 }  // namespace art
diff --git a/compiler/optimizing/instruction_simplifier.h b/compiler/optimizing/instruction_simplifier.h
index 7905104..7fe1067 100644
--- a/compiler/optimizing/instruction_simplifier.h
+++ b/compiler/optimizing/instruction_simplifier.h
@@ -35,9 +35,9 @@
  */
 class InstructionSimplifier : public HOptimization {
  public:
-  InstructionSimplifier(HGraph* graph,
-                        OptimizingCompilerStats* stats = nullptr,
-                        const char* name = kInstructionSimplifierPassName)
+  explicit InstructionSimplifier(HGraph* graph,
+                                 OptimizingCompilerStats* stats = nullptr,
+                                 const char* name = kInstructionSimplifierPassName)
       : HOptimization(graph, name, stats) {}
 
   static constexpr const char* kInstructionSimplifierPassName = "instruction_simplifier";
diff --git a/compiler/optimizing/locations.h b/compiler/optimizing/locations.h
index 4384042..c97c4a6 100644
--- a/compiler/optimizing/locations.h
+++ b/compiler/optimizing/locations.h
@@ -488,9 +488,9 @@
     kCallOnMainOnly
   };
 
-  LocationSummary(HInstruction* instruction,
-                  CallKind call_kind = kNoCall,
-                  bool intrinsified = false);
+  explicit LocationSummary(HInstruction* instruction,
+                           CallKind call_kind = kNoCall,
+                           bool intrinsified = false);
 
   void SetInAt(uint32_t at, Location location) {
     inputs_[at] = location;
diff --git a/compiler/optimizing/nodes.cc b/compiler/optimizing/nodes.cc
index 8f37236..9cfa89b 100644
--- a/compiler/optimizing/nodes.cc
+++ b/compiler/optimizing/nodes.cc
@@ -460,6 +460,113 @@
   return kAnalysisSuccess;
 }
 
+static bool InSameLoop(HLoopInformation* first_loop, HLoopInformation* second_loop) {
+  return first_loop == second_loop;
+}
+
+static bool IsLoop(HLoopInformation* info) {
+  return info != nullptr;
+}
+
+static bool IsInnerLoop(HLoopInformation* outer, HLoopInformation* inner) {
+  return (inner != outer)
+      && (inner != nullptr)
+      && (outer != nullptr)
+      && inner->IsIn(*outer);
+}
+
+// Helper method to update work list for linear order.
+static void AddToListForLinearization(ArenaVector<HBasicBlock*>* worklist, HBasicBlock* block) {
+  HLoopInformation* block_loop = block->GetLoopInformation();
+  auto insert_pos = worklist->rbegin();  // insert_pos.base() will be the actual position.
+  for (auto end = worklist->rend(); insert_pos != end; ++insert_pos) {
+    HBasicBlock* current = *insert_pos;
+    HLoopInformation* current_loop = current->GetLoopInformation();
+    if (InSameLoop(block_loop, current_loop)
+        || !IsLoop(current_loop)
+        || IsInnerLoop(current_loop, block_loop)) {
+      // The block can be processed immediately.
+      break;
+    }
+  }
+  worklist->insert(insert_pos.base(), block);
+}
+
+// Helper method to validate linear order.
+static bool IsLinearOrderWellFormed(const HGraph& graph) {
+  for (HBasicBlock* header : graph.GetBlocks()) {
+    if (header == nullptr || !header->IsLoopHeader()) {
+      continue;
+    }
+    HLoopInformation* loop = header->GetLoopInformation();
+    size_t num_blocks = loop->GetBlocks().NumSetBits();
+    size_t found_blocks = 0u;
+    for (HLinearOrderIterator it(graph); !it.Done(); it.Advance()) {
+      HBasicBlock* current = it.Current();
+      if (loop->Contains(*current)) {
+        found_blocks++;
+        if (found_blocks == 1u && current != header) {
+          // First block is not the header.
+          return false;
+        } else if (found_blocks == num_blocks && !loop->IsBackEdge(*current)) {
+          // Last block is not a back edge.
+          return false;
+        }
+      } else if (found_blocks != 0u && found_blocks != num_blocks) {
+        // Blocks are not adjacent.
+        return false;
+      }
+    }
+    DCHECK_EQ(found_blocks, num_blocks);
+  }
+  return true;
+}
+
+void HGraph::Linearize() {
+  // Create a reverse post ordering with the following properties:
+  // - Blocks in a loop are consecutive,
+  // - Back-edge is the last block before loop exits.
+
+  // (1): Record the number of forward predecessors for each block. This is to
+  //      ensure the resulting order is reverse post order. We could use the
+  //      current reverse post order in the graph, but it would require making
+  //      order queries to a GrowableArray, which is not the best data structure
+  //      for it.
+  ArenaVector<uint32_t> forward_predecessors(blocks_.size(),
+                                             arena_->Adapter(kArenaAllocSsaLiveness));
+  for (HReversePostOrderIterator it(*this); !it.Done(); it.Advance()) {
+    HBasicBlock* block = it.Current();
+    size_t number_of_forward_predecessors = block->GetPredecessors().size();
+    if (block->IsLoopHeader()) {
+      number_of_forward_predecessors -= block->GetLoopInformation()->NumberOfBackEdges();
+    }
+    forward_predecessors[block->GetBlockId()] = number_of_forward_predecessors;
+  }
+
+  // (2): Following a worklist approach, first start with the entry block, and
+  //      iterate over the successors. When all non-back edge predecessors of a
+  //      successor block are visited, the successor block is added in the worklist
+  //      following an order that satisfies the requirements to build our linear graph.
+  linear_order_.reserve(GetReversePostOrder().size());
+  ArenaVector<HBasicBlock*> worklist(arena_->Adapter(kArenaAllocSsaLiveness));
+  worklist.push_back(GetEntryBlock());
+  do {
+    HBasicBlock* current = worklist.back();
+    worklist.pop_back();
+    linear_order_.push_back(current);
+    for (HBasicBlock* successor : current->GetSuccessors()) {
+      int block_id = successor->GetBlockId();
+      size_t number_of_remaining_predecessors = forward_predecessors[block_id];
+      if (number_of_remaining_predecessors == 1) {
+        AddToListForLinearization(&worklist, successor);
+      }
+      forward_predecessors[block_id] = number_of_remaining_predecessors - 1;
+    }
+  } while (!worklist.empty());
+
+  DCHECK(HasIrreducibleLoops() || IsLinearOrderWellFormed(*this));
+}
+
 void HLoopInformation::Dump(std::ostream& os) {
   os << "header: " << header_->GetBlockId() << std::endl;
   os << "pre header: " << GetPreHeader()->GetBlockId() << std::endl;
diff --git a/compiler/optimizing/nodes.h b/compiler/optimizing/nodes.h
index 149a71d..caecc57 100644
--- a/compiler/optimizing/nodes.h
+++ b/compiler/optimizing/nodes.h
@@ -24,7 +24,9 @@
 #include "base/arena_bit_vector.h"
 #include "base/arena_containers.h"
 #include "base/arena_object.h"
+#include "base/array_ref.h"
 #include "base/stl_util.h"
+#include "base/transform_array_ref.h"
 #include "dex_file.h"
 #include "entrypoints/quick/quick_entrypoints_enum.h"
 #include "handle.h"
@@ -35,9 +37,7 @@
 #include "mirror/class.h"
 #include "offsets.h"
 #include "primitive.h"
-#include "utils/array_ref.h"
 #include "utils/intrusive_forward_list.h"
-#include "utils/transform_array_ref.h"
 
 namespace art {
 
@@ -109,6 +109,9 @@
   kCondBE,  // <=
   kCondA,   // >
   kCondAE,  // >=
+  // First and last aliases.
+  kCondFirst = kCondEQ,
+  kCondLast = kCondAE,
 };
 
 enum GraphAnalysisResult {
@@ -362,6 +365,13 @@
   // is a throw-catch loop, i.e. the header is a catch block.
   GraphAnalysisResult AnalyzeLoops() const;
 
+  // Computes the linear order (should be called before using HLinearOrderIterator).
+  // Linearizes the graph such that:
+  // (1): a block is always after its dominator,
+  // (2): blocks of loops are contiguous.
+  // This creates a natural and efficient ordering when visualizing live ranges.
+  void Linearize();
+
   // Iterate over blocks to compute try block membership. Needs reverse post
   // order and loop information.
   void ComputeTryBlockInformation();
@@ -827,7 +837,7 @@
 
 class HBasicBlock : public ArenaObject<kArenaAllocBasicBlock> {
  public:
-  HBasicBlock(HGraph* graph, uint32_t dex_pc = kNoDexPc)
+  explicit HBasicBlock(HGraph* graph, uint32_t dex_pc = kNoDexPc)
       : graph_(graph),
         predecessors_(graph->GetArena()->Adapter(kArenaAllocPredecessors)),
         successors_(graph->GetArena()->Adapter(kArenaAllocSuccessors)),
@@ -1311,7 +1321,8 @@
 #else
 #define FOR_EACH_CONCRETE_INSTRUCTION_MIPS(M)                           \
   M(MipsComputeBaseMethodAddress, Instruction)                          \
-  M(MipsDexCacheArraysBase, Instruction)
+  M(MipsDexCacheArraysBase, Instruction)                                \
+  M(MipsPackedSwitch, Instruction)
 #endif
 
 #define FOR_EACH_CONCRETE_INSTRUCTION_MIPS64(M)
@@ -6271,7 +6282,7 @@
 
 class HBoundType FINAL : public HExpression<1> {
  public:
-  HBoundType(HInstruction* input, uint32_t dex_pc = kNoDexPc)
+  explicit HBoundType(HInstruction* input, uint32_t dex_pc = kNoDexPc)
       : HExpression(Primitive::kPrimNot, SideEffects::None(), dex_pc),
         upper_bound_(ReferenceTypeInfo::CreateInvalid()) {
     SetPackedFlag<kFlagUpperCanBeNull>(true);
diff --git a/compiler/optimizing/nodes_mips.h b/compiler/optimizing/nodes_mips.h
index de77245..36431c1 100644
--- a/compiler/optimizing/nodes_mips.h
+++ b/compiler/optimizing/nodes_mips.h
@@ -66,6 +66,41 @@
   DISALLOW_COPY_AND_ASSIGN(HMipsDexCacheArraysBase);
 };
 
+// Mips version of HPackedSwitch that holds a pointer to the base method address.
+class HMipsPackedSwitch FINAL : public HTemplateInstruction<2> {
+ public:
+  HMipsPackedSwitch(int32_t start_value,
+                    int32_t num_entries,
+                    HInstruction* input,
+                    HMipsComputeBaseMethodAddress* method_base,
+                    uint32_t dex_pc)
+    : HTemplateInstruction(SideEffects::None(), dex_pc),
+      start_value_(start_value),
+      num_entries_(num_entries) {
+    SetRawInputAt(0, input);
+    SetRawInputAt(1, method_base);
+  }
+
+  bool IsControlFlow() const OVERRIDE { return true; }
+
+  int32_t GetStartValue() const { return start_value_; }
+
+  int32_t GetNumEntries() const { return num_entries_; }
+
+  HBasicBlock* GetDefaultBlock() const {
+    // Last entry is the default block.
+    return GetBlock()->GetSuccessors()[num_entries_];
+  }
+
+  DECLARE_INSTRUCTION(MipsPackedSwitch);
+
+ private:
+  const int32_t start_value_;
+  const int32_t num_entries_;
+
+  DISALLOW_COPY_AND_ASSIGN(HMipsPackedSwitch);
+};
+
 }  // namespace art
 
 #endif  // ART_COMPILER_OPTIMIZING_NODES_MIPS_H_
diff --git a/compiler/optimizing/pc_relative_fixups_mips.cc b/compiler/optimizing/pc_relative_fixups_mips.cc
index c6d297d..6006e6c 100644
--- a/compiler/optimizing/pc_relative_fixups_mips.cc
+++ b/compiler/optimizing/pc_relative_fixups_mips.cc
@@ -92,6 +92,25 @@
     }
   }
 
+  void VisitPackedSwitch(HPackedSwitch* switch_insn) OVERRIDE {
+    if (switch_insn->GetNumEntries() <=
+        InstructionCodeGeneratorMIPS::kPackedSwitchJumpTableThreshold) {
+      return;
+    }
+    // We need to replace the HPackedSwitch with a HMipsPackedSwitch in order to
+    // address the constant area.
+    InitializePCRelativeBasePointer();
+    HGraph* graph = GetGraph();
+    HBasicBlock* block = switch_insn->GetBlock();
+    HMipsPackedSwitch* mips_switch = new (graph->GetArena()) HMipsPackedSwitch(
+        switch_insn->GetStartValue(),
+        switch_insn->GetNumEntries(),
+        switch_insn->InputAt(0),
+        base_,
+        switch_insn->GetDexPc());
+    block->ReplaceAndRemoveInstructionWith(switch_insn, mips_switch);
+  }
+
   void HandleInvoke(HInvoke* invoke) {
     // If this is an invoke-static/-direct with PC-relative dex cache array
     // addressing, we need the PC-relative address base.
diff --git a/compiler/optimizing/register_allocation_resolver.h b/compiler/optimizing/register_allocation_resolver.h
index a70ceae..d48b1a0 100644
--- a/compiler/optimizing/register_allocation_resolver.h
+++ b/compiler/optimizing/register_allocation_resolver.h
@@ -18,9 +18,9 @@
 #define ART_COMPILER_OPTIMIZING_REGISTER_ALLOCATION_RESOLVER_H_
 
 #include "base/arena_containers.h"
+#include "base/array_ref.h"
 #include "base/value_object.h"
 #include "primitive.h"
-#include "utils/array_ref.h"
 
 namespace art {
 
diff --git a/compiler/optimizing/ssa_liveness_analysis.cc b/compiler/optimizing/ssa_liveness_analysis.cc
index a4d52d7..9ce34aa 100644
--- a/compiler/optimizing/ssa_liveness_analysis.cc
+++ b/compiler/optimizing/ssa_liveness_analysis.cc
@@ -23,119 +23,11 @@
 namespace art {
 
 void SsaLivenessAnalysis::Analyze() {
-  LinearizeGraph();
+  graph_->Linearize();
   NumberInstructions();
   ComputeLiveness();
 }
 
-static bool IsLoop(HLoopInformation* info) {
-  return info != nullptr;
-}
-
-static bool InSameLoop(HLoopInformation* first_loop, HLoopInformation* second_loop) {
-  return first_loop == second_loop;
-}
-
-static bool IsInnerLoop(HLoopInformation* outer, HLoopInformation* inner) {
-  return (inner != outer)
-      && (inner != nullptr)
-      && (outer != nullptr)
-      && inner->IsIn(*outer);
-}
-
-static void AddToListForLinearization(ArenaVector<HBasicBlock*>* worklist, HBasicBlock* block) {
-  HLoopInformation* block_loop = block->GetLoopInformation();
-  auto insert_pos = worklist->rbegin();  // insert_pos.base() will be the actual position.
-  for (auto end = worklist->rend(); insert_pos != end; ++insert_pos) {
-    HBasicBlock* current = *insert_pos;
-    HLoopInformation* current_loop = current->GetLoopInformation();
-    if (InSameLoop(block_loop, current_loop)
-        || !IsLoop(current_loop)
-        || IsInnerLoop(current_loop, block_loop)) {
-      // The block can be processed immediately.
-      break;
-    }
-  }
-  worklist->insert(insert_pos.base(), block);
-}
-
-static bool IsLinearOrderWellFormed(const HGraph& graph) {
-  for (HBasicBlock* header : graph.GetBlocks()) {
-    if (header == nullptr || !header->IsLoopHeader()) {
-      continue;
-    }
-
-    HLoopInformation* loop = header->GetLoopInformation();
-    size_t num_blocks = loop->GetBlocks().NumSetBits();
-    size_t found_blocks = 0u;
-
-    for (HLinearOrderIterator it(graph); !it.Done(); it.Advance()) {
-      HBasicBlock* current = it.Current();
-      if (loop->Contains(*current)) {
-        found_blocks++;
-        if (found_blocks == 1u && current != header) {
-          // First block is not the header.
-          return false;
-        } else if (found_blocks == num_blocks && !loop->IsBackEdge(*current)) {
-          // Last block is not a back edge.
-          return false;
-        }
-      } else if (found_blocks != 0u && found_blocks != num_blocks) {
-        // Blocks are not adjacent.
-        return false;
-      }
-    }
-    DCHECK_EQ(found_blocks, num_blocks);
-  }
-
-  return true;
-}
-
-void SsaLivenessAnalysis::LinearizeGraph() {
-  // Create a reverse post ordering with the following properties:
-  // - Blocks in a loop are consecutive,
-  // - Back-edge is the last block before loop exits.
-
-  // (1): Record the number of forward predecessors for each block. This is to
-  //      ensure the resulting order is reverse post order. We could use the
-  //      current reverse post order in the graph, but it would require making
-  //      order queries to a GrowableArray, which is not the best data structure
-  //      for it.
-  ArenaVector<uint32_t> forward_predecessors(graph_->GetBlocks().size(),
-                                             graph_->GetArena()->Adapter(kArenaAllocSsaLiveness));
-  for (HReversePostOrderIterator it(*graph_); !it.Done(); it.Advance()) {
-    HBasicBlock* block = it.Current();
-    size_t number_of_forward_predecessors = block->GetPredecessors().size();
-    if (block->IsLoopHeader()) {
-      number_of_forward_predecessors -= block->GetLoopInformation()->NumberOfBackEdges();
-    }
-    forward_predecessors[block->GetBlockId()] = number_of_forward_predecessors;
-  }
-
-  // (2): Following a worklist approach, first start with the entry block, and
-  //      iterate over the successors. When all non-back edge predecessors of a
-  //      successor block are visited, the successor block is added in the worklist
-  //      following an order that satisfies the requirements to build our linear graph.
-  graph_->linear_order_.reserve(graph_->GetReversePostOrder().size());
-  ArenaVector<HBasicBlock*> worklist(graph_->GetArena()->Adapter(kArenaAllocSsaLiveness));
-  worklist.push_back(graph_->GetEntryBlock());
-  do {
-    HBasicBlock* current = worklist.back();
-    worklist.pop_back();
-    graph_->linear_order_.push_back(current);
-    for (HBasicBlock* successor : current->GetSuccessors()) {
-      int block_id = successor->GetBlockId();
-      size_t number_of_remaining_predecessors = forward_predecessors[block_id];
-      if (number_of_remaining_predecessors == 1) {
-        AddToListForLinearization(&worklist, successor);
-      }
-      forward_predecessors[block_id] = number_of_remaining_predecessors - 1;
-    }
-  } while (!worklist.empty());
-
-  DCHECK(graph_->HasIrreducibleLoops() || IsLinearOrderWellFormed(*graph_));
-}
-
 void SsaLivenessAnalysis::NumberInstructions() {
   int ssa_index = 0;
   size_t lifetime_position = 0;
diff --git a/compiler/optimizing/ssa_liveness_analysis.h b/compiler/optimizing/ssa_liveness_analysis.h
index 0be1611..b62bf4e 100644
--- a/compiler/optimizing/ssa_liveness_analysis.h
+++ b/compiler/optimizing/ssa_liveness_analysis.h
@@ -1186,12 +1186,6 @@
   static constexpr const char* kLivenessPassName = "liveness";
 
  private:
-  // Linearize the graph so that:
-  // (1): a block is always after its dominator,
-  // (2): blocks of loops are contiguous.
-  // This creates a natural and efficient ordering when visualizing live ranges.
-  void LinearizeGraph();
-
   // Give an SSA number to each instruction that defines a value used by another instruction,
   // and setup the lifetime information of each instruction and block.
   void NumberInstructions();
diff --git a/compiler/utils/arm/assembler_arm.h b/compiler/utils/arm/assembler_arm.h
index 3084e6e..aefbf26 100644
--- a/compiler/utils/arm/assembler_arm.h
+++ b/compiler/utils/arm/assembler_arm.h
@@ -246,7 +246,7 @@
     NegPostIndex = (0|0|0) << 21   // negative post-indexed with writeback
   };
 
-  Address(Register rn, int32_t offset = 0, Mode am = Offset) : rn_(rn), rm_(R0),
+  explicit Address(Register rn, int32_t offset = 0, Mode am = Offset) : rn_(rn), rm_(R0),
       offset_(offset),
       am_(am), is_immed_offset_(true), shift_(LSL) {
   }
diff --git a/compiler/utils/arm/assembler_thumb2.cc b/compiler/utils/arm/assembler_thumb2.cc
index ebdfc98..f5ccf40 100644
--- a/compiler/utils/arm/assembler_thumb2.cc
+++ b/compiler/utils/arm/assembler_thumb2.cc
@@ -2018,6 +2018,45 @@
   return adjustment;
 }
 
+bool Thumb2Assembler::Fixup::IsCandidateForEmitEarly() const {
+  DCHECK(size_ == original_size_);
+  if (target_ == kUnresolved) {
+    return false;
+  }
+  // GetOffset() does not depend on current_code_size for branches, only for literals.
+  constexpr uint32_t current_code_size = 0u;
+  switch (GetSize()) {
+    case kBranch16Bit:
+      return IsInt(cond_ != AL ? 9 : 12, GetOffset(current_code_size));
+    case kBranch32Bit:
+      // We don't support conditional branches beyond +-1MiB
+      // or unconditional branches beyond +-16MiB.
+      return true;
+
+    case kCbxz16Bit:
+      return IsUint<7>(GetOffset(current_code_size));
+    case kCbxz32Bit:
+      return IsInt<9>(GetOffset(current_code_size));
+    case kCbxz48Bit:
+      // We don't support conditional branches beyond +-1MiB.
+      return true;
+
+    case kLiteral1KiB:
+    case kLiteral4KiB:
+    case kLiteral64KiB:
+    case kLiteral1MiB:
+    case kLiteralFar:
+    case kLiteralAddr1KiB:
+    case kLiteralAddr4KiB:
+    case kLiteralAddr64KiB:
+    case kLiteralAddrFar:
+    case kLongOrFPLiteral1KiB:
+    case kLongOrFPLiteral64KiB:
+    case kLongOrFPLiteralFar:
+      return false;
+  }
+}
+
 uint32_t Thumb2Assembler::Fixup::AdjustSizeIfNeeded(uint32_t current_code_size) {
   uint32_t old_code_size = current_code_size;
   switch (GetSize()) {
@@ -3343,6 +3382,30 @@
 
 void Thumb2Assembler::Bind(Label* label) {
   BindLabel(label, buffer_.Size());
+
+  // Try to emit some Fixups now to reduce the memory needed during the branch fixup later.
+  while (!fixups_.empty() && fixups_.back().IsCandidateForEmitEarly()) {
+    const Fixup& last_fixup = fixups_.back();
+    // Fixups are ordered by location, so the candidate can surely be emitted if it is
+    // a forward branch. If it's a backward branch, it may go over any number of other
+    // fixups. We could check for any number of emit early candidates but we want this
+    // heuristics to be quick, so check just one.
+    uint32_t target = last_fixup.GetTarget();
+    if (target < last_fixup.GetLocation() &&
+        fixups_.size() >= 2u &&
+        fixups_[fixups_.size() - 2u].GetLocation() >= target) {
+      const Fixup& prev_fixup = fixups_[fixups_.size() - 2u];
+      if (!prev_fixup.IsCandidateForEmitEarly()) {
+        break;
+      }
+      uint32_t min_target = std::min(target, prev_fixup.GetTarget());
+      if (fixups_.size() >= 3u && fixups_[fixups_.size() - 3u].GetLocation() >= min_target) {
+        break;
+      }
+    }
+    last_fixup.Emit(&buffer_, buffer_.Size());
+    fixups_.pop_back();
+  }
 }
 
 
diff --git a/compiler/utils/arm/assembler_thumb2.h b/compiler/utils/arm/assembler_thumb2.h
index 13f3bec..917c947 100644
--- a/compiler/utils/arm/assembler_thumb2.h
+++ b/compiler/utils/arm/assembler_thumb2.h
@@ -22,11 +22,11 @@
 #include <vector>
 
 #include "base/arena_containers.h"
+#include "base/array_ref.h"
 #include "base/logging.h"
 #include "constants_arm.h"
 #include "utils/arm/managed_register_arm.h"
 #include "utils/arm/assembler_arm.h"
-#include "utils/array_ref.h"
 #include "offsets.h"
 
 namespace art {
@@ -573,6 +573,10 @@
       return location_;
     }
 
+    uint32_t GetTarget() const {
+      return target_;
+    }
+
     uint32_t GetAdjustment() const {
       return adjustment_;
     }
@@ -592,6 +596,11 @@
       target_ = target;
     }
 
+    // Branches with bound targets that are in range can be emitted early.
+    // However, the caller still needs to check if the branch doesn't go over
+    // another Fixup that's not ready to be emitted.
+    bool IsCandidateForEmitEarly() const;
+
     // Check if the current size is OK for current location_, target_ and adjustment_.
     // If not, increase the size. Return the size increase, 0 if unchanged.
     // If the target if after this Fixup, also add the difference to adjustment_,
diff --git a/compiler/utils/arm/jni_macro_assembler_arm_vixl.cc b/compiler/utils/arm/jni_macro_assembler_arm_vixl.cc
index a03dd74..14d29c4 100644
--- a/compiler/utils/arm/jni_macro_assembler_arm_vixl.cc
+++ b/compiler/utils/arm/jni_macro_assembler_arm_vixl.cc
@@ -314,11 +314,21 @@
       CHECK(src.IsCoreRegister()) << src;
       ___ Mov(dst.AsVIXLRegister(), src.AsVIXLRegister());
     } else if (dst.IsDRegister()) {
-      CHECK(src.IsDRegister()) << src;
-      ___ Vmov(F64, dst.AsVIXLDRegister(), src.AsVIXLDRegister());
+      if (src.IsDRegister()) {
+        ___ Vmov(F64, dst.AsVIXLDRegister(), src.AsVIXLDRegister());
+      } else {
+        // VMOV Dn, Rlo, Rhi (Dn = {Rlo, Rhi})
+        CHECK(src.IsRegisterPair()) << src;
+        ___ Vmov(dst.AsVIXLDRegister(), src.AsVIXLRegisterPairLow(), src.AsVIXLRegisterPairHigh());
+      }
     } else if (dst.IsSRegister()) {
-      CHECK(src.IsSRegister()) << src;
-      ___ Vmov(F32, dst.AsVIXLSRegister(), src.AsVIXLSRegister());
+      if (src.IsSRegister()) {
+        ___ Vmov(F32, dst.AsVIXLSRegister(), src.AsVIXLSRegister());
+      } else {
+        // VMOV Sn, Rn  (Sn = Rn)
+        CHECK(src.IsCoreRegister()) << src;
+        ___ Vmov(dst.AsVIXLSRegister(), src.AsVIXLRegister());
+      }
     } else {
       CHECK(dst.IsRegisterPair()) << dst;
       CHECK(src.IsRegisterPair()) << src;
diff --git a/compiler/utils/assembler.h b/compiler/utils/assembler.h
index b616057..314ff8c 100644
--- a/compiler/utils/assembler.h
+++ b/compiler/utils/assembler.h
@@ -24,6 +24,7 @@
 #include "arm/constants_arm.h"
 #include "base/arena_allocator.h"
 #include "base/arena_object.h"
+#include "base/array_ref.h"
 #include "base/enums.h"
 #include "base/logging.h"
 #include "base/macros.h"
@@ -33,7 +34,6 @@
 #include "memory_region.h"
 #include "mips/constants_mips.h"
 #include "offsets.h"
-#include "utils/array_ref.h"
 #include "x86/constants_x86.h"
 #include "x86_64/constants_x86_64.h"
 
diff --git a/compiler/utils/dedupe_set_test.cc b/compiler/utils/dedupe_set_test.cc
index 60a891d..4c0979e 100644
--- a/compiler/utils/dedupe_set_test.cc
+++ b/compiler/utils/dedupe_set_test.cc
@@ -20,10 +20,10 @@
 #include <cstdio>
 #include <vector>
 
+#include "base/array_ref.h"
 #include "dedupe_set-inl.h"
 #include "gtest/gtest.h"
 #include "thread-inl.h"
-#include "utils/array_ref.h"
 
 namespace art {
 
diff --git a/compiler/utils/intrusive_forward_list.h b/compiler/utils/intrusive_forward_list.h
index ec2c087..b5fc2f2 100644
--- a/compiler/utils/intrusive_forward_list.h
+++ b/compiler/utils/intrusive_forward_list.h
@@ -59,7 +59,7 @@
   // Conversion from iterator to const_iterator.
   template <typename OtherT,
             typename = typename std::enable_if<std::is_same<T, const OtherT>::value>::type>
-  IntrusiveForwardListIterator(const IntrusiveForwardListIterator<OtherT, HookTraits>& src)
+  IntrusiveForwardListIterator(const IntrusiveForwardListIterator<OtherT, HookTraits>& src)  // NOLINT, implicit
       : hook_(src.hook_) { }
 
   // Iteration.
diff --git a/compiler/utils/jni_macro_assembler.h b/compiler/utils/jni_macro_assembler.h
index 6f45bd6..0119ae9 100644
--- a/compiler/utils/jni_macro_assembler.h
+++ b/compiler/utils/jni_macro_assembler.h
@@ -22,12 +22,12 @@
 #include "arch/instruction_set.h"
 #include "base/arena_allocator.h"
 #include "base/arena_object.h"
+#include "base/array_ref.h"
 #include "base/enums.h"
 #include "base/logging.h"
 #include "base/macros.h"
 #include "managed_register.h"
 #include "offsets.h"
-#include "utils/array_ref.h"
 
 namespace art {
 
diff --git a/compiler/utils/mips/assembler_mips.cc b/compiler/utils/mips/assembler_mips.cc
index 4b580b6..b972c70 100644
--- a/compiler/utils/mips/assembler_mips.cc
+++ b/compiler/utils/mips/assembler_mips.cc
@@ -230,12 +230,14 @@
   DsFsmCommitLabel();
   SetReorder(false);
   EmitLiterals();
+  ReserveJumpTableSpace();
   PromoteBranches();
 }
 
 void MipsAssembler::FinalizeInstructions(const MemoryRegion& region) {
   size_t number_of_delayed_adjust_pcs = cfi().NumberOfDelayedAdvancePCs();
   EmitBranches();
+  EmitJumpTables();
   Assembler::FinalizeInstructions(region);
   PatchCFI(number_of_delayed_adjust_pcs);
 }
@@ -1724,47 +1726,68 @@
   type_ = (offset_size <= branch_info_[short_type].offset_size) ? short_type : long_type;
 }
 
-void MipsAssembler::Branch::InitializeType(bool is_call, bool is_literal, bool is_r6) {
-  CHECK_EQ(is_call && is_literal, false);
+void MipsAssembler::Branch::InitializeType(Type initial_type, bool is_r6) {
   OffsetBits offset_size = GetOffsetSizeNeeded(location_, target_);
   if (is_r6) {
     // R6
-    if (is_literal) {
-      CHECK(!IsResolved());
-      type_ = kR6Literal;
-    } else if (is_call) {
-      InitShortOrLong(offset_size, kR6Call, kR6LongCall);
-    } else {
-      switch (condition_) {
-        case kUncond:
-          InitShortOrLong(offset_size, kR6UncondBranch, kR6LongUncondBranch);
-          break;
-        case kCondEQZ:
-        case kCondNEZ:
-          // Special case for beqzc/bnezc with longer offset than in other b<cond>c instructions.
-          type_ = (offset_size <= kOffset23) ? kR6CondBranch : kR6LongCondBranch;
-          break;
-        default:
-          InitShortOrLong(offset_size, kR6CondBranch, kR6LongCondBranch);
-          break;
-      }
+    switch (initial_type) {
+      case kLabel:
+        CHECK(!IsResolved());
+        type_ = kR6Label;
+        break;
+      case kLiteral:
+        CHECK(!IsResolved());
+        type_ = kR6Literal;
+        break;
+      case kCall:
+        InitShortOrLong(offset_size, kR6Call, kR6LongCall);
+        break;
+      case kCondBranch:
+        switch (condition_) {
+          case kUncond:
+            InitShortOrLong(offset_size, kR6UncondBranch, kR6LongUncondBranch);
+            break;
+          case kCondEQZ:
+          case kCondNEZ:
+            // Special case for beqzc/bnezc with longer offset than in other b<cond>c instructions.
+            type_ = (offset_size <= kOffset23) ? kR6CondBranch : kR6LongCondBranch;
+            break;
+          default:
+            InitShortOrLong(offset_size, kR6CondBranch, kR6LongCondBranch);
+            break;
+        }
+        break;
+      default:
+        LOG(FATAL) << "Unexpected branch type " << initial_type;
+        UNREACHABLE();
     }
   } else {
     // R2
-    if (is_literal) {
-      CHECK(!IsResolved());
-      type_ = kLiteral;
-    } else if (is_call) {
-      InitShortOrLong(offset_size, kCall, kLongCall);
-    } else {
-      switch (condition_) {
-        case kUncond:
-          InitShortOrLong(offset_size, kUncondBranch, kLongUncondBranch);
-          break;
-        default:
-          InitShortOrLong(offset_size, kCondBranch, kLongCondBranch);
-          break;
-      }
+    switch (initial_type) {
+      case kLabel:
+        CHECK(!IsResolved());
+        type_ = kLabel;
+        break;
+      case kLiteral:
+        CHECK(!IsResolved());
+        type_ = kLiteral;
+        break;
+      case kCall:
+        InitShortOrLong(offset_size, kCall, kLongCall);
+        break;
+      case kCondBranch:
+        switch (condition_) {
+          case kUncond:
+            InitShortOrLong(offset_size, kUncondBranch, kLongUncondBranch);
+            break;
+          default:
+            InitShortOrLong(offset_size, kCondBranch, kLongCondBranch);
+            break;
+        }
+        break;
+      default:
+        LOG(FATAL) << "Unexpected branch type " << initial_type;
+        UNREACHABLE();
     }
   }
   old_type_ = type_;
@@ -1804,7 +1827,7 @@
       rhs_reg_(0),
       condition_(kUncond),
       delayed_instruction_(kUnfilledDelaySlot) {
-  InitializeType(is_call, /* is_literal */ false, is_r6);
+  InitializeType((is_call ? kCall : kCondBranch), is_r6);
 }
 
 MipsAssembler::Branch::Branch(bool is_r6,
@@ -1862,10 +1885,14 @@
     // Branch condition is always true, make the branch unconditional.
     condition_ = kUncond;
   }
-  InitializeType(/* is_call */ false, /* is_literal */ false, is_r6);
+  InitializeType(kCondBranch, is_r6);
 }
 
-MipsAssembler::Branch::Branch(bool is_r6, uint32_t location, Register dest_reg, Register base_reg)
+MipsAssembler::Branch::Branch(bool is_r6,
+                              uint32_t location,
+                              Register dest_reg,
+                              Register base_reg,
+                              Type label_or_literal_type)
     : old_location_(location),
       location_(location),
       target_(kUnresolved),
@@ -1879,7 +1906,7 @@
   } else {
     CHECK_NE(base_reg, ZERO);
   }
-  InitializeType(/* is_call */ false, /* is_literal */ true, is_r6);
+  InitializeType(label_or_literal_type, is_r6);
 }
 
 MipsAssembler::BranchCondition MipsAssembler::Branch::OppositeCondition(
@@ -2007,12 +2034,16 @@
     case kUncondBranch:
     case kCondBranch:
     case kCall:
+    // R2 near label.
+    case kLabel:
     // R2 near literal.
     case kLiteral:
     // R6 short branches.
     case kR6UncondBranch:
     case kR6CondBranch:
     case kR6Call:
+    // R6 near label.
+    case kR6Label:
     // R6 near literal.
     case kR6Literal:
       return false;
@@ -2020,12 +2051,16 @@
     case kLongUncondBranch:
     case kLongCondBranch:
     case kLongCall:
+    // R2 far label.
+    case kFarLabel:
     // R2 far literal.
     case kFarLiteral:
     // R6 long branches.
     case kR6LongUncondBranch:
     case kR6LongCondBranch:
     case kR6LongCall:
+    // R6 far label.
+    case kR6FarLabel:
     // R6 far literal.
     case kR6FarLiteral:
       return true;
@@ -2096,6 +2131,10 @@
     case kCall:
       type_ = kLongCall;
       break;
+    // R2 near label.
+    case kLabel:
+      type_ = kFarLabel;
+      break;
     // R2 near literal.
     case kLiteral:
       type_ = kFarLiteral;
@@ -2110,6 +2149,10 @@
     case kR6Call:
       type_ = kR6LongCall;
       break;
+    // R6 near label.
+    case kR6Label:
+      type_ = kR6FarLabel;
+      break;
     // R6 near literal.
     case kR6Literal:
       type_ = kR6FarLiteral;
@@ -2123,6 +2166,8 @@
 
 uint32_t MipsAssembler::GetBranchLocationOrPcRelBase(const MipsAssembler::Branch* branch) const {
   switch (branch->GetType()) {
+    case Branch::kLabel:
+    case Branch::kFarLabel:
     case Branch::kLiteral:
     case Branch::kFarLiteral:
       return GetLabelLocation(&pc_rel_base_label_);
@@ -2132,7 +2177,7 @@
 }
 
 uint32_t MipsAssembler::Branch::PromoteIfNeeded(uint32_t location, uint32_t max_short_distance) {
-  // `location` is either `GetLabelLocation(&pc_rel_base_label_)` for R2 literals or
+  // `location` is either `GetLabelLocation(&pc_rel_base_label_)` for R2 labels/literals or
   // `this->GetLocation()` for everything else.
   // If the branch is still unresolved or already long, nothing to do.
   if (IsLong() || !IsResolved()) {
@@ -2170,6 +2215,8 @@
 
 uint32_t MipsAssembler::GetBranchOrPcRelBaseForEncoding(const MipsAssembler::Branch* branch) const {
   switch (branch->GetType()) {
+    case Branch::kLabel:
+    case Branch::kFarLabel:
     case Branch::kLiteral:
     case Branch::kFarLiteral:
       return GetLabelLocation(&pc_rel_base_label_);
@@ -2180,7 +2227,7 @@
 }
 
 uint32_t MipsAssembler::Branch::GetOffset(uint32_t location) const {
-  // `location` is either `GetLabelLocation(&pc_rel_base_label_)` for R2 literals or
+  // `location` is either `GetLabelLocation(&pc_rel_base_label_)` for R2 labels/literals or
   // `this->GetOffsetLocation() + branch_info_[this->GetType()].pc_org * sizeof(uint32_t)`
   // for everything else.
   CHECK(IsResolved());
@@ -2457,6 +2504,13 @@
   FinalizeLabeledBranch(label);
 }
 
+void MipsAssembler::LoadLabelAddress(Register dest_reg, Register base_reg, MipsLabel* label) {
+  // Label address loads are treated as pseudo branches since they require very similar handling.
+  DCHECK(!label->IsBound());
+  branches_.emplace_back(IsR6(), buffer_.Size(), dest_reg, base_reg, Branch::kLabel);
+  FinalizeLabeledBranch(label);
+}
+
 Literal* MipsAssembler::NewLiteral(size_t size, const uint8_t* data) {
   DCHECK(size == 4u || size == 8u) << size;
   literals_.emplace_back(size, data);
@@ -2468,13 +2522,17 @@
   DCHECK_EQ(literal->GetSize(), 4u);
   MipsLabel* label = literal->GetLabel();
   DCHECK(!label->IsBound());
-  branches_.emplace_back(IsR6(),
-                         buffer_.Size(),
-                         dest_reg,
-                         base_reg);
+  branches_.emplace_back(IsR6(), buffer_.Size(), dest_reg, base_reg, Branch::kLiteral);
   FinalizeLabeledBranch(label);
 }
 
+JumpTable* MipsAssembler::CreateJumpTable(std::vector<MipsLabel*>&& labels) {
+  jump_tables_.emplace_back(std::move(labels));
+  JumpTable* table = &jump_tables_.back();
+  DCHECK(!table->GetLabel()->IsBound());
+  return table;
+}
+
 void MipsAssembler::EmitLiterals() {
   if (!literals_.empty()) {
     // We don't support byte and half-word literals.
@@ -2491,6 +2549,60 @@
   }
 }
 
+void MipsAssembler::ReserveJumpTableSpace() {
+  if (!jump_tables_.empty()) {
+    for (JumpTable& table : jump_tables_) {
+      MipsLabel* label = table.GetLabel();
+      Bind(label);
+
+      // Bulk ensure capacity, as this may be large.
+      size_t orig_size = buffer_.Size();
+      size_t required_capacity = orig_size + table.GetSize();
+      if (required_capacity > buffer_.Capacity()) {
+        buffer_.ExtendCapacity(required_capacity);
+      }
+#ifndef NDEBUG
+      buffer_.has_ensured_capacity_ = true;
+#endif
+
+      // Fill the space with dummy data as the data is not final
+      // until the branches have been promoted. And we shouldn't
+      // be moving uninitialized data during branch promotion.
+      for (size_t cnt = table.GetData().size(), i = 0; i < cnt; i++) {
+        buffer_.Emit<uint32_t>(0x1abe1234u);
+      }
+
+#ifndef NDEBUG
+      buffer_.has_ensured_capacity_ = false;
+#endif
+    }
+  }
+}
+
+void MipsAssembler::EmitJumpTables() {
+  if (!jump_tables_.empty()) {
+    CHECK(!overwriting_);
+    // Switch from appending instructions at the end of the buffer to overwriting
+    // existing instructions (here, jump tables) in the buffer.
+    overwriting_ = true;
+
+    for (JumpTable& table : jump_tables_) {
+      MipsLabel* table_label = table.GetLabel();
+      uint32_t start = GetLabelLocation(table_label);
+      overwrite_location_ = start;
+
+      for (MipsLabel* target : table.GetData()) {
+        CHECK_EQ(buffer_.Load<uint32_t>(overwrite_location_), 0x1abe1234u);
+        // The table will contain target addresses relative to the table start.
+        uint32_t offset = GetLabelLocation(target) - start;
+        Emit(offset);
+      }
+    }
+
+    overwriting_ = false;
+  }
+}
+
 void MipsAssembler::PromoteBranches() {
   // Promote short branches to long as necessary.
   bool changed;
@@ -2539,12 +2651,16 @@
   {  2, 0, 1, MipsAssembler::Branch::kOffset18, 2 },  // kUncondBranch
   {  2, 0, 1, MipsAssembler::Branch::kOffset18, 2 },  // kCondBranch
   {  2, 0, 1, MipsAssembler::Branch::kOffset18, 2 },  // kCall
+  // R2 near label.
+  {  1, 0, 0, MipsAssembler::Branch::kOffset16, 0 },  // kLabel
   // R2 near literal.
   {  1, 0, 0, MipsAssembler::Branch::kOffset16, 0 },  // kLiteral
   // R2 long branches.
   {  9, 3, 1, MipsAssembler::Branch::kOffset32, 0 },  // kLongUncondBranch
   { 10, 4, 1, MipsAssembler::Branch::kOffset32, 0 },  // kLongCondBranch
   {  6, 1, 1, MipsAssembler::Branch::kOffset32, 0 },  // kLongCall
+  // R2 far label.
+  {  3, 0, 0, MipsAssembler::Branch::kOffset32, 0 },  // kFarLabel
   // R2 far literal.
   {  3, 0, 0, MipsAssembler::Branch::kOffset32, 0 },  // kFarLiteral
   // R6 short branches.
@@ -2552,12 +2668,16 @@
   {  2, 0, 1, MipsAssembler::Branch::kOffset18, 2 },  // kR6CondBranch
                                                       // Exception: kOffset23 for beqzc/bnezc.
   {  1, 0, 1, MipsAssembler::Branch::kOffset28, 2 },  // kR6Call
+  // R6 near label.
+  {  1, 0, 0, MipsAssembler::Branch::kOffset21, 2 },  // kR6Label
   // R6 near literal.
   {  1, 0, 0, MipsAssembler::Branch::kOffset21, 2 },  // kR6Literal
   // R6 long branches.
   {  2, 0, 0, MipsAssembler::Branch::kOffset32, 0 },  // kR6LongUncondBranch
   {  3, 1, 0, MipsAssembler::Branch::kOffset32, 0 },  // kR6LongCondBranch
   {  2, 0, 0, MipsAssembler::Branch::kOffset32, 0 },  // kR6LongCall
+  // R6 far label.
+  {  2, 0, 0, MipsAssembler::Branch::kOffset32, 0 },  // kR6FarLabel
   // R6 far literal.
   {  2, 0, 0, MipsAssembler::Branch::kOffset32, 0 },  // kR6FarLiteral
 };
@@ -2614,6 +2734,12 @@
       Emit(delayed_instruction);
       break;
 
+    // R2 near label.
+    case Branch::kLabel:
+      DCHECK_EQ(delayed_instruction, Branch::kUnfilledDelaySlot);
+      CHECK_EQ(overwrite_location_, branch->GetOffsetLocation());
+      Addiu(lhs, rhs, offset);
+      break;
     // R2 near literal.
     case Branch::kLiteral:
       DCHECK_EQ(delayed_instruction, Branch::kUnfilledDelaySlot);
@@ -2691,6 +2817,14 @@
       Nop();
       break;
 
+    // R2 far label.
+    case Branch::kFarLabel:
+      DCHECK_EQ(delayed_instruction, Branch::kUnfilledDelaySlot);
+      CHECK_EQ(overwrite_location_, branch->GetOffsetLocation());
+      Lui(AT, High16Bits(offset));
+      Ori(AT, AT, Low16Bits(offset));
+      Addu(lhs, AT, rhs);
+      break;
     // R2 far literal.
     case Branch::kFarLiteral:
       DCHECK_EQ(delayed_instruction, Branch::kUnfilledDelaySlot);
@@ -2725,6 +2859,12 @@
       Balc(offset);
       break;
 
+    // R6 near label.
+    case Branch::kR6Label:
+      DCHECK_EQ(delayed_instruction, Branch::kUnfilledDelaySlot);
+      CHECK_EQ(overwrite_location_, branch->GetOffsetLocation());
+      Addiupc(lhs, offset);
+      break;
     // R6 near literal.
     case Branch::kR6Literal:
       DCHECK_EQ(delayed_instruction, Branch::kUnfilledDelaySlot);
@@ -2759,6 +2899,14 @@
       Jialc(AT, Low16Bits(offset));
       break;
 
+    // R6 far label.
+    case Branch::kR6FarLabel:
+      DCHECK_EQ(delayed_instruction, Branch::kUnfilledDelaySlot);
+      offset += (offset & 0x8000) << 1;  // Account for sign extension in addiu.
+      CHECK_EQ(overwrite_location_, branch->GetOffsetLocation());
+      Auipc(AT, High16Bits(offset));
+      Addiu(lhs, AT, Low16Bits(offset));
+      break;
     // R6 far literal.
     case Branch::kR6FarLiteral:
       DCHECK_EQ(delayed_instruction, Branch::kUnfilledDelaySlot);
diff --git a/compiler/utils/mips/assembler_mips.h b/compiler/utils/mips/assembler_mips.h
index d50c439..099620c 100644
--- a/compiler/utils/mips/assembler_mips.h
+++ b/compiler/utils/mips/assembler_mips.h
@@ -126,6 +126,36 @@
   DISALLOW_COPY_AND_ASSIGN(Literal);
 };
 
+// Jump table: table of labels emitted after the literals. Similar to literals.
+class JumpTable {
+ public:
+  explicit JumpTable(std::vector<MipsLabel*>&& labels)
+      : label_(), labels_(std::move(labels)) {
+  }
+
+  uint32_t GetSize() const {
+    return static_cast<uint32_t>(labels_.size()) * sizeof(uint32_t);
+  }
+
+  const std::vector<MipsLabel*>& GetData() const {
+    return labels_;
+  }
+
+  MipsLabel* GetLabel() {
+    return &label_;
+  }
+
+  const MipsLabel* GetLabel() const {
+    return &label_;
+  }
+
+ private:
+  MipsLabel label_;
+  std::vector<MipsLabel*> labels_;
+
+  DISALLOW_COPY_AND_ASSIGN(JumpTable);
+};
+
 // Slowpath entered when Thread::Current()->_exception is non-null.
 class MipsExceptionSlowPath {
  public:
@@ -158,6 +188,7 @@
         ds_fsm_state_(kExpectingLabel),
         ds_fsm_target_pc_(0),
         literals_(arena->Adapter(kArenaAllocAssembler)),
+        jump_tables_(arena->Adapter(kArenaAllocAssembler)),
         last_position_adjustment_(0),
         last_old_position_(0),
         last_branch_id_(0),
@@ -685,6 +716,11 @@
     return NewLiteral(sizeof(value), reinterpret_cast<const uint8_t*>(&value));
   }
 
+  // Load label address using the base register (for R2 only) or using PC-relative loads
+  // (for R6 only; base_reg must be ZERO). To be used with data labels in the literal /
+  // jump table area only and not with regular code labels.
+  void LoadLabelAddress(Register dest_reg, Register base_reg, MipsLabel* label);
+
   // Create a new literal with the given data.
   Literal* NewLiteral(size_t size, const uint8_t* data);
 
@@ -692,6 +728,12 @@
   // (for R6 only; base_reg must be ZERO).
   void LoadLiteral(Register dest_reg, Register base_reg, Literal* literal);
 
+  // Create a jump table for the given labels that will be emitted when finalizing.
+  // When the table is emitted, offsets will be relative to the location of the table.
+  // The table location is determined by the location of its label (the label precedes
+  // the table data) and should be loaded using LoadLabelAddress().
+  JumpTable* CreateJumpTable(std::vector<MipsLabel*>&& labels);
+
   //
   // Overridden common assembler high-level functionality.
   //
@@ -935,24 +977,32 @@
       kUncondBranch,
       kCondBranch,
       kCall,
+      // R2 near label.
+      kLabel,
       // R2 near literal.
       kLiteral,
       // R2 long branches.
       kLongUncondBranch,
       kLongCondBranch,
       kLongCall,
+      // R2 far label.
+      kFarLabel,
       // R2 far literal.
       kFarLiteral,
       // R6 short branches.
       kR6UncondBranch,
       kR6CondBranch,
       kR6Call,
+      // R6 near label.
+      kR6Label,
       // R6 near literal.
       kR6Literal,
       // R6 long branches.
       kR6LongUncondBranch,
       kR6LongCondBranch,
       kR6LongCall,
+      // R6 far label.
+      kR6FarLabel,
       // R6 far literal.
       kR6FarLiteral,
     };
@@ -1009,8 +1059,12 @@
            BranchCondition condition,
            Register lhs_reg,
            Register rhs_reg);
-    // Literal.
-    Branch(bool is_r6, uint32_t location, Register dest_reg, Register base_reg);
+    // Label address (in literal area) or literal.
+    Branch(bool is_r6,
+           uint32_t location,
+           Register dest_reg,
+           Register base_reg,
+           Type label_or_literal_type);
 
     // Some conditional branches with lhs = rhs are effectively NOPs, while some
     // others are effectively unconditional. MIPSR6 conditional branches require lhs != rhs.
@@ -1105,7 +1159,7 @@
 
    private:
     // Completes branch construction by determining and recording its type.
-    void InitializeType(bool is_call, bool is_literal, bool is_r6);
+    void InitializeType(Type initial_type, bool is_r6);
     // Helper for the above.
     void InitShortOrLong(OffsetBits ofs_size, Type short_type, Type long_type);
 
@@ -1178,6 +1232,8 @@
   uint32_t GetBranchOrPcRelBaseForEncoding(const MipsAssembler::Branch* branch) const;
 
   void EmitLiterals();
+  void ReserveJumpTableSpace();
+  void EmitJumpTables();
   void PromoteBranches();
   void EmitBranch(Branch* branch);
   void EmitBranches();
@@ -1227,6 +1283,9 @@
   // without invalidating pointers and references to existing elements.
   ArenaDeque<Literal> literals_;
 
+  // Jump table list.
+  ArenaDeque<JumpTable> jump_tables_;
+
   // There's no PC-relative addressing on MIPS32R2. So, in order to access literals relative to PC
   // we get PC using the NAL instruction. This label marks the position within the assembler buffer
   // that PC (from NAL) points to.
diff --git a/compiler/utils/mips/assembler_mips32r6_test.cc b/compiler/utils/mips/assembler_mips32r6_test.cc
index fabb096..750a94d 100644
--- a/compiler/utils/mips/assembler_mips32r6_test.cc
+++ b/compiler/utils/mips/assembler_mips32r6_test.cc
@@ -309,6 +309,12 @@
   DriverStr(RepeatRIb(&mips::MipsAssembler::Lwpc, 19, code), "Lwpc");
 }
 
+TEST_F(AssemblerMIPS32r6Test, Addiupc) {
+  // The comment from the Lwpc() test applies to this Addiupc() test as well.
+  const char* code = ".set imm, {imm}\naddiupc ${reg}, (imm - ((imm & 0x40000) << 1)) << 2";
+  DriverStr(RepeatRIb(&mips::MipsAssembler::Addiupc, 19, code), "Addiupc");
+}
+
 TEST_F(AssemblerMIPS32r6Test, Bitswap) {
   DriverStr(RepeatRR(&mips::MipsAssembler::Bitswap, "bitswap ${reg1}, ${reg2}"), "bitswap");
 }
@@ -635,6 +641,40 @@
   DriverStr(expected, "StoreDToOffset");
 }
 
+TEST_F(AssemblerMIPS32r6Test, LoadFarthestNearLabelAddress) {
+  mips::MipsLabel label;
+  __ LoadLabelAddress(mips::V0, mips::ZERO, &label);
+  constexpr size_t kAdduCount = 0x3FFDE;
+  for (size_t i = 0; i != kAdduCount; ++i) {
+    __ Addu(mips::ZERO, mips::ZERO, mips::ZERO);
+  }
+  __ Bind(&label);
+
+  std::string expected =
+      "lapc $v0, 1f\n" +
+      RepeatInsn(kAdduCount, "addu $zero, $zero, $zero\n") +
+      "1:\n";
+  DriverStr(expected, "LoadFarthestNearLabelAddress");
+}
+
+TEST_F(AssemblerMIPS32r6Test, LoadNearestFarLabelAddress) {
+  mips::MipsLabel label;
+  __ LoadLabelAddress(mips::V0, mips::ZERO, &label);
+  constexpr size_t kAdduCount = 0x3FFDF;
+  for (size_t i = 0; i != kAdduCount; ++i) {
+    __ Addu(mips::ZERO, mips::ZERO, mips::ZERO);
+  }
+  __ Bind(&label);
+
+  std::string expected =
+      "1:\n"
+      "auipc $at, %hi(2f - 1b)\n"
+      "addiu $v0, $at, %lo(2f - 1b)\n" +
+      RepeatInsn(kAdduCount, "addu $zero, $zero, $zero\n") +
+      "2:\n";
+  DriverStr(expected, "LoadNearestFarLabelAddress");
+}
+
 TEST_F(AssemblerMIPS32r6Test, LoadFarthestNearLiteral) {
   mips::Literal* literal = __ NewLiteral<uint32_t>(0x12345678);
   __ LoadLiteral(mips::V0, mips::ZERO, literal);
@@ -811,8 +851,7 @@
   DriverStr(expected, "LongBeqc");
 }
 
-// TODO: MipsAssembler::Addiupc
-//       MipsAssembler::Bc
+// TODO: MipsAssembler::Bc
 //       MipsAssembler::Jic
 //       MipsAssembler::Jialc
 //       MipsAssembler::Bltc
diff --git a/compiler/utils/mips/assembler_mips_test.cc b/compiler/utils/mips/assembler_mips_test.cc
index 708bc3d..a92455f 100644
--- a/compiler/utils/mips/assembler_mips_test.cc
+++ b/compiler/utils/mips/assembler_mips_test.cc
@@ -2307,6 +2307,44 @@
   DriverStr(expected, "LoadConst32");
 }
 
+TEST_F(AssemblerMIPSTest, LoadFarthestNearLabelAddress) {
+  mips::MipsLabel label;
+  __ BindPcRelBaseLabel();
+  __ LoadLabelAddress(mips::V0, mips::V1, &label);
+  constexpr size_t kAddiuCount = 0x1FDE;
+  for (size_t i = 0; i != kAddiuCount; ++i) {
+    __ Addiu(mips::A0, mips::A1, 0);
+  }
+  __ Bind(&label);
+
+  std::string expected =
+      "1:\n"
+      "addiu $v0, $v1, %lo(2f - 1b)\n" +
+      RepeatInsn(kAddiuCount, "addiu $a0, $a1, %hi(2f - 1b)\n") +
+      "2:\n";
+  DriverStr(expected, "LoadFarthestNearLabelAddress");
+}
+
+TEST_F(AssemblerMIPSTest, LoadNearestFarLabelAddress) {
+  mips::MipsLabel label;
+  __ BindPcRelBaseLabel();
+  __ LoadLabelAddress(mips::V0, mips::V1, &label);
+  constexpr size_t kAdduCount = 0x1FDF;
+  for (size_t i = 0; i != kAdduCount; ++i) {
+    __ Addu(mips::ZERO, mips::ZERO, mips::ZERO);
+  }
+  __ Bind(&label);
+
+  std::string expected =
+      "1:\n"
+      "lui $at, %hi(2f - 1b)\n"
+      "ori $at, $at, %lo(2f - 1b)\n"
+      "addu $v0, $at, $v1\n" +
+      RepeatInsn(kAdduCount, "addu $zero, $zero, $zero\n") +
+      "2:\n";
+  DriverStr(expected, "LoadNearestFarLabelAddress");
+}
+
 TEST_F(AssemblerMIPSTest, LoadFarthestNearLiteral) {
   mips::Literal* literal = __ NewLiteral<uint32_t>(0x12345678);
   __ BindPcRelBaseLabel();
diff --git a/compiler/utils/swap_space.h b/compiler/utils/swap_space.h
index bf06675..9600907 100644
--- a/compiler/utils/swap_space.h
+++ b/compiler/utils/swap_space.h
@@ -114,7 +114,8 @@
   explicit SwapAllocator(SwapSpace* swap_space) : swap_space_(swap_space) {}
 
   template <typename U>
-  SwapAllocator(const SwapAllocator<U>& other) : swap_space_(other.swap_space_) {}
+  SwapAllocator(const SwapAllocator<U>& other)  // NOLINT, implicit
+      : swap_space_(other.swap_space_) {}
 
   SwapAllocator(const SwapAllocator& other) = default;
   SwapAllocator& operator=(const SwapAllocator& other) = default;
@@ -149,7 +150,8 @@
   explicit SwapAllocator(SwapSpace* swap_space) : swap_space_(swap_space) {}
 
   template <typename U>
-  SwapAllocator(const SwapAllocator<U>& other) : swap_space_(other.swap_space_) {}
+  SwapAllocator(const SwapAllocator<U>& other)  // NOLINT, implicit
+      : swap_space_(other.swap_space_) {}
 
   SwapAllocator(const SwapAllocator& other) = default;
   SwapAllocator& operator=(const SwapAllocator& other) = default;
diff --git a/compiler/utils/x86/assembler_x86.h b/compiler/utils/x86/assembler_x86.h
index 9738784..114986b 100644
--- a/compiler/utils/x86/assembler_x86.h
+++ b/compiler/utils/x86/assembler_x86.h
@@ -20,6 +20,7 @@
 #include <vector>
 
 #include "base/arena_containers.h"
+#include "base/array_ref.h"
 #include "base/bit_utils.h"
 #include "base/enums.h"
 #include "base/macros.h"
@@ -27,7 +28,6 @@
 #include "globals.h"
 #include "managed_register_x86.h"
 #include "offsets.h"
-#include "utils/array_ref.h"
 #include "utils/assembler.h"
 
 namespace art {
diff --git a/compiler/utils/x86/jni_macro_assembler_x86.h b/compiler/utils/x86/jni_macro_assembler_x86.h
index 3f07ede..015584c 100644
--- a/compiler/utils/x86/jni_macro_assembler_x86.h
+++ b/compiler/utils/x86/jni_macro_assembler_x86.h
@@ -21,10 +21,10 @@
 
 #include "assembler_x86.h"
 #include "base/arena_containers.h"
+#include "base/array_ref.h"
 #include "base/enums.h"
 #include "base/macros.h"
 #include "offsets.h"
-#include "utils/array_ref.h"
 #include "utils/jni_macro_assembler.h"
 
 namespace art {
diff --git a/compiler/utils/x86_64/assembler_x86_64.h b/compiler/utils/x86_64/assembler_x86_64.h
index fdd3aa9..acad86d 100644
--- a/compiler/utils/x86_64/assembler_x86_64.h
+++ b/compiler/utils/x86_64/assembler_x86_64.h
@@ -20,13 +20,13 @@
 #include <vector>
 
 #include "base/arena_containers.h"
+#include "base/array_ref.h"
 #include "base/bit_utils.h"
 #include "base/macros.h"
 #include "constants_x86_64.h"
 #include "globals.h"
 #include "managed_register_x86_64.h"
 #include "offsets.h"
-#include "utils/array_ref.h"
 #include "utils/assembler.h"
 #include "utils/jni_macro_assembler.h"
 
diff --git a/compiler/utils/x86_64/jni_macro_assembler_x86_64.h b/compiler/utils/x86_64/jni_macro_assembler_x86_64.h
index cc4e57c..9107f3c 100644
--- a/compiler/utils/x86_64/jni_macro_assembler_x86_64.h
+++ b/compiler/utils/x86_64/jni_macro_assembler_x86_64.h
@@ -21,10 +21,10 @@
 
 #include "assembler_x86_64.h"
 #include "base/arena_containers.h"
+#include "base/array_ref.h"
 #include "base/enums.h"
 #include "base/macros.h"
 #include "offsets.h"
-#include "utils/array_ref.h"
 #include "utils/assembler.h"
 #include "utils/jni_macro_assembler.h"
 
diff --git a/dex2oat/Android.bp b/dex2oat/Android.bp
new file mode 100644
index 0000000..d422734
--- /dev/null
+++ b/dex2oat/Android.bp
@@ -0,0 +1,130 @@
+//
+// 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.
+//
+
+cc_defaults {
+    name: "dex2oat-defaults",
+    host_supported: true,
+    defaults: ["art_defaults"],
+    srcs: ["dex2oat.cc"],
+
+    target: {
+        android: {
+            // Use the 32-bit version of dex2oat on devices
+            compile_multilib: "prefer32",
+
+            sanitize: {
+                // ASan slows down dex2oat by ~3.5x, which translates into
+                // extremely slow first boot. Disabled to help speed up
+                // SANITIZE_TARGET mode.
+                // Bug: 22233158
+                address: false,
+            },
+        },
+    },
+
+
+    include_dirs: [
+        "art/cmdline",
+    ],
+}
+
+art_cc_binary {
+    name: "dex2oat",
+    defaults: [
+        "dex2oat-defaults",
+    ],
+    shared_libs: [
+        "libart",
+        "libart-compiler",
+        "libsigchain",
+    ],
+}
+
+art_cc_binary {
+    name: "dex2oatd",
+    defaults: [
+        "art_debug_defaults",
+        "dex2oat-defaults",
+    ],
+    shared_libs: [
+        "libartd",
+        "libartd-compiler",
+        "libsigchain",
+    ],
+}
+
+art_cc_binary {
+    name: "dex2oats",
+    device_supported: false,
+    static_executable: true,
+    defaults: ["dex2oat-defaults"],
+    target: {
+        darwin: {
+            enabled: false,
+        },
+    },
+    ldflags: [
+        // We need this because GC stress mode makes use of
+        // _Unwind_GetIP and _Unwind_Backtrace and the symbols are also
+        // defined in libgcc_eh.a(unwind-dw2.o)
+        // TODO: Having this is not ideal as it might obscure errors.
+        // Try to get rid of it.
+        "-z muldefs",
+    ],
+    static_libs: [
+        "libart-compiler",
+        "libart",
+        "libvixl-arm",
+        "libvixl-arm64",
+    ] + art_static_dependencies,
+}
+
+art_cc_binary {
+    name: "dex2oatds",
+    device_supported: false,
+    static_executable: true,
+    defaults: [
+        "art_debug_defaults",
+        "dex2oat-defaults",
+    ],
+    target: {
+        darwin: {
+            enabled: false,
+        },
+    },
+    ldflags: [
+        // We need this because GC stress mode makes use of
+        // _Unwind_GetIP and _Unwind_Backtrace and the symbols are also
+        // defined in libgcc_eh.a(unwind-dw2.o)
+        // TODO: Having this is not ideal as it might obscure errors.
+        // Try to get rid of it.
+        "-z muldefs",
+    ],
+    static_libs: [
+        "libartd-compiler",
+        "libartd",
+        "libvixld-arm",
+        "libvixld-arm64",
+    ] + art_static_dependencies,
+}
+
+art_cc_test {
+    name: "art_dex2oat_tests",
+    defaults: [
+        "art_test_defaults",
+    ],
+    srcs: ["dex2oat_test.cc"],
+}
diff --git a/dex2oat/Android.mk b/dex2oat/Android.mk
deleted file mode 100644
index 32424ca..0000000
--- a/dex2oat/Android.mk
+++ /dev/null
@@ -1,78 +0,0 @@
-#
-# 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.
-#
-
-# ASan slows down dex2oat by ~3.5x, which translates into extremely slow first
-# boot. Disabled to help speed up SANITIZE_TARGET mode.
-# The supported way of using SANITIZE_TARGET is by first running a normal build,
-# followed by a SANITIZE_TARGET=address build on top of it (in the same build
-# tree). By disabling this module in SANITIZE_TARGET build, we keep the regular,
-# uninstrumented version of it.
-# Bug: 22233158
-ifeq (,$(filter address, $(SANITIZE_TARGET)))
-
-LOCAL_PATH := $(call my-dir)
-
-include art/build/Android.executable.mk
-
-DEX2OAT_SRC_FILES := \
-	dex2oat.cc
-
-# TODO: Remove this when the framework (installd) supports pushing the
-# right instruction-set parameter for the primary architecture.
-ifneq ($(filter ro.zygote=zygote64,$(PRODUCT_DEFAULT_PROPERTY_OVERRIDES)),)
-  dex2oat_target_arch := 64
-else
-  dex2oat_target_arch := 32
-endif
-
-ifeq ($(HOST_PREFER_32_BIT),true)
-  # We need to explicitly restrict the host arch to 32-bit only, as
-  # giving 'both' would make build-art-executable generate a build
-  # rule for a 64-bit dex2oat executable too.
-  dex2oat_host_arch := 32
-else
-  dex2oat_host_arch := both
-endif
-
-ifeq ($(ART_BUILD_TARGET_NDEBUG),true)
-  $(eval $(call build-art-executable,dex2oat,$(DEX2OAT_SRC_FILES),libcutils libart-compiler libsigchain,art/compiler,target,ndebug,$(dex2oat_target_arch)))
-endif
-
-ifeq ($(ART_BUILD_TARGET_DEBUG),true)
-  $(eval $(call build-art-executable,dex2oat,$(DEX2OAT_SRC_FILES),libcutils libartd-compiler libsigchain,art/compiler,target,debug,$(dex2oat_target_arch)))
-endif
-
-# We always build dex2oat and dependencies, even if the host build is
-# otherwise disabled, since they are used to cross compile for the target.
-ifeq ($(ART_BUILD_HOST_NDEBUG),true)
-  $(eval $(call build-art-executable,dex2oat,$(DEX2OAT_SRC_FILES),libcutils libart-compiler libsigchain libziparchive liblz4,art/compiler,host,ndebug,$(dex2oat_host_arch)))
-  ifeq ($(ART_BUILD_HOST_STATIC),true)
-    $(eval $(call build-art-executable,dex2oat,$(DEX2OAT_SRC_FILES),libart libart-compiler libart libvixl-arm libvixl-arm64 $(ART_STATIC_DEPENDENCIES),art/compiler,host,ndebug,$(dex2oat_host_arch),static))
-  endif
-endif
-
-ifeq ($(ART_BUILD_HOST_DEBUG),true)
-  $(eval $(call build-art-executable,dex2oat,$(DEX2OAT_SRC_FILES),libcutils libartd-compiler libsigchain libziparchive liblz4,art/compiler,host,debug,$(dex2oat_host_arch)))
-  ifeq ($(ART_BUILD_HOST_STATIC),true)
-    $(eval $(call build-art-executable,dex2oat,$(DEX2OAT_SRC_FILES),libartd libartd-compiler libartd libvixld-arm libvixld-arm64 $(ART_STATIC_DEPENDENCIES),art/compiler,host,debug,$(dex2oat_host_arch),static))
-  endif
-endif
-
-# Clear locals now they've served their purpose.
-dex2oat_target_arch :=
-dex2oat_host_arch :=
-
-endif
diff --git a/dex2oat/dex2oat.cc b/dex2oat/dex2oat.cc
index febfb63..1296bcf 100644
--- a/dex2oat/dex2oat.cc
+++ b/dex2oat/dex2oat.cc
@@ -507,6 +507,7 @@
       thread_count_(sysconf(_SC_NPROCESSORS_CONF)),
       start_ns_(NanoTime()),
       oat_fd_(-1),
+      vdex_fd_(-1),
       zip_fd_(-1),
       image_base_(0U),
       image_classes_zip_filename_(nullptr),
@@ -557,6 +558,9 @@
       for (std::unique_ptr<MemMap>& map : opened_dex_files_maps_) {
         map.release();
       }
+      for (std::unique_ptr<File>& vdex_file : vdex_files_) {
+        vdex_file.release();
+      }
       for (std::unique_ptr<File>& oat_file : oat_files_) {
         oat_file.release();
       }
@@ -578,6 +582,10 @@
     ParseUintOption(option, "--zip-fd", &zip_fd_, Usage);
   }
 
+  void ParseVdexFd(const StringPiece& option) {
+    ParseUintOption(option, "--vdex-fd", &vdex_fd_, Usage);
+  }
+
   void ParseOatFd(const StringPiece& option) {
     ParseUintOption(option, "--oat-fd", &oat_fd_, Usage);
   }
@@ -693,6 +701,11 @@
       Usage("--oat-file should not be used with --oat-fd");
     }
 
+    if ((vdex_fd_ == -1) != (oat_fd_ == -1)) {
+      Usage("VDEX and OAT output must be specified either with one --oat-filename "
+            "or with --oat-fd and --vdex-fd file descriptors");
+    }
+
     if (!parser_options->oat_symbols.empty() && oat_fd_ != -1) {
       Usage("--oat-symbols should not be used with --oat-fd");
     }
@@ -701,6 +714,10 @@
       Usage("--oat-symbols should not be used with --host");
     }
 
+    if (vdex_fd_ != -1 && !image_filenames_.empty()) {
+      Usage("--vdex-fd should not be used with --image");
+    }
+
     if (oat_fd_ != -1 && !image_filenames_.empty()) {
       Usage("--oat-fd should not be used with --image");
     }
@@ -1074,20 +1091,22 @@
         ParseZipFd(option);
       } else if (option.starts_with("--zip-location=")) {
         zip_location_ = option.substr(strlen("--zip-location=")).data();
+      } else if (option.starts_with("--vdex-fd=")) {
+        ParseVdexFd(option);
       } else if (option.starts_with("--oat-file=")) {
         oat_filenames_.push_back(option.substr(strlen("--oat-file=")).data());
       } else if (option.starts_with("--oat-symbols=")) {
         parser_options->oat_symbols.push_back(option.substr(strlen("--oat-symbols=")).data());
       } else if (option.starts_with("--oat-fd=")) {
         ParseOatFd(option);
+      } else if (option.starts_with("--oat-location=")) {
+        oat_location_ = option.substr(strlen("--oat-location=")).data();
       } else if (option == "--watch-dog") {
         parser_options->watch_dog_enabled = true;
       } else if (option == "--no-watch-dog") {
         parser_options->watch_dog_enabled = false;
       } else if (option.starts_with("-j")) {
         ParseJ(option);
-      } else if (option.starts_with("--oat-location=")) {
-        oat_location_ = option.substr(strlen("--oat-location=")).data();
       } else if (option.starts_with("--image=")) {
         image_filenames_.push_back(option.substr(strlen("--image=")).data());
       } else if (option.starts_with("--image-classes=")) {
@@ -1199,41 +1218,66 @@
       ExpandOatAndImageFilenames();
     }
 
-    bool create_file = oat_fd_ == -1;  // as opposed to using open file descriptor
-    if (create_file) {
+    // OAT and VDEX file handling
+
+    if (oat_fd_ == -1) {
+      DCHECK(!oat_filenames_.empty());
       for (const char* oat_filename : oat_filenames_) {
         std::unique_ptr<File> oat_file(OS::CreateEmptyFile(oat_filename));
         if (oat_file.get() == nullptr) {
           PLOG(ERROR) << "Failed to create oat file: " << oat_filename;
           return false;
         }
-        if (create_file && fchmod(oat_file->Fd(), 0644) != 0) {
+        if (fchmod(oat_file->Fd(), 0644) != 0) {
           PLOG(ERROR) << "Failed to make oat file world readable: " << oat_filename;
           oat_file->Erase();
           return false;
         }
         oat_files_.push_back(std::move(oat_file));
+
+        DCHECK_EQ(vdex_fd_, -1);
+        std::string vdex_filename = ReplaceFileExtension(oat_filename, "vdex");
+        std::unique_ptr<File> vdex_file(OS::CreateEmptyFile(vdex_filename.c_str()));
+        if (vdex_file.get() == nullptr) {
+          PLOG(ERROR) << "Failed to open vdex file: " << vdex_filename;
+          return false;
+        }
+        if (fchmod(vdex_file->Fd(), 0644) != 0) {
+          PLOG(ERROR) << "Failed to make vdex file world readable: " << vdex_filename;
+          vdex_file->Erase();
+          return false;
+        }
+        vdex_files_.push_back(std::move(vdex_file));
       }
     } else {
-      std::unique_ptr<File> oat_file(new File(oat_fd_, oat_location_, true));
-      oat_file->DisableAutoClose();
-      if (oat_file->SetLength(0) != 0) {
-        PLOG(WARNING) << "Truncating oat file " << oat_location_ << " failed.";
-      }
+      std::unique_ptr<File> oat_file(new File(oat_fd_, oat_location_, /* check_usage */ true));
       if (oat_file.get() == nullptr) {
         PLOG(ERROR) << "Failed to create oat file: " << oat_location_;
         return false;
       }
-      if (create_file && fchmod(oat_file->Fd(), 0644) != 0) {
-        PLOG(ERROR) << "Failed to make oat file world readable: " << oat_location_;
-        oat_file->Erase();
+      oat_file->DisableAutoClose();
+      if (oat_file->SetLength(0) != 0) {
+        PLOG(WARNING) << "Truncating oat file " << oat_location_ << " failed.";
+      }
+      oat_files_.push_back(std::move(oat_file));
+
+      DCHECK_NE(vdex_fd_, -1);
+      std::string vdex_location = ReplaceFileExtension(oat_location_, "vdex");
+      std::unique_ptr<File> vdex_file(new File(vdex_fd_, vdex_location, /* check_usage */ true));
+      if (vdex_file.get() == nullptr) {
+        PLOG(ERROR) << "Failed to create vdex file: " << vdex_location;
         return false;
       }
+      vdex_file->DisableAutoClose();
+      if (vdex_file->SetLength(0) != 0) {
+        PLOG(WARNING) << "Truncating vdex file " << vdex_location << " failed.";
+      }
+      vdex_files_.push_back(std::move(vdex_file));
+
       oat_filenames_.push_back(oat_location_.c_str());
-      oat_files_.push_back(std::move(oat_file));
     }
 
-    // Swap file handling.
+    // Swap file handling
     //
     // If the swap fd is not -1, we assume this is the file descriptor of an open but unlinked file
     // that we can use for swap.
@@ -1256,11 +1300,14 @@
     return true;
   }
 
-  void EraseOatFiles() {
-    for (size_t i = 0; i < oat_files_.size(); ++i) {
-      DCHECK(oat_files_[i].get() != nullptr);
-      oat_files_[i]->Erase();
-      oat_files_[i].reset();
+  void EraseOutputFiles() {
+    for (auto& files : { &vdex_files_, &oat_files_ }) {
+      for (size_t i = 0; i < files->size(); ++i) {
+        if ((*files)[i].get() != nullptr) {
+          (*files)[i]->Erase();
+          (*files)[i].reset();
+        }
+      }
     }
   }
 
@@ -1399,14 +1446,15 @@
         // Unzip or copy dex files straight to the oat file.
         std::unique_ptr<MemMap> opened_dex_files_map;
         std::vector<std::unique_ptr<const DexFile>> opened_dex_files;
-        if (!oat_writers_[i]->WriteAndOpenDexFiles(rodata_.back(),
-                                                   oat_files_[i].get(),
-                                                   instruction_set_,
-                                                   instruction_set_features_.get(),
-                                                   key_value_store_.get(),
-                                                   /* verify */ true,
-                                                   &opened_dex_files_map,
-                                                   &opened_dex_files)) {
+        if (!oat_writers_[i]->WriteAndOpenDexFiles(
+            kIsVdexEnabled ? vdex_files_[i].get() : oat_files_[i].get(),
+            rodata_.back(),
+            instruction_set_,
+            instruction_set_features_.get(),
+            key_value_store_.get(),
+            /* verify */ true,
+            &opened_dex_files_map,
+            &opened_dex_files)) {
           return false;
         }
         dex_files_per_oat_file_.push_back(MakeNonOwningPointerVector(opened_dex_files));
@@ -1652,7 +1700,7 @@
   // ImageWriter, if necessary.
   // Note: Flushing (and closing) the file is the caller's responsibility, except for the failure
   //       case (when the file will be explicitly erased).
-  bool WriteOatFiles() {
+  bool WriteOutputFiles() {
     TimingLogger::ScopedTiming t("dex2oat Oat", timings_);
 
     // Sync the data to the file, in case we did dex2dex transformations.
@@ -1709,7 +1757,7 @@
         oat_writer->PrepareLayout(driver_.get(), image_writer_.get(), dex_files, &patcher);
 
         size_t rodata_size = oat_writer->GetOatHeader().GetExecutableOffset();
-        size_t text_size = oat_writer->GetSize() - rodata_size;
+        size_t text_size = oat_writer->GetOatSize() - rodata_size;
         elf_writer->SetLoadedSectionSizes(rodata_size, text_size, oat_writer->GetBssSize());
 
         if (IsImage()) {
@@ -1719,7 +1767,7 @@
           image_writer_->UpdateOatFileLayout(i,
                                              elf_writer->GetLoadedSize(),
                                              oat_writer->GetOatDataOffset(),
-                                             oat_writer->GetSize());
+                                             oat_writer->GetOatSize());
         }
       }
 
@@ -1774,12 +1822,8 @@
           return false;
         }
 
-        // Flush the oat file.
-        if (oat_files_[i] != nullptr) {
-          if (oat_files_[i]->Flush() != 0) {
-            PLOG(ERROR) << "Failed to flush oat file: " << oat_filenames_[i];
-            return false;
-          }
+        if (!FlushOutputFile(&vdex_files_[i]) || !FlushOutputFile(&oat_files_[i])) {
+          return false;
         }
 
         VLOG(compiler) << "Oat file written successfully: " << oat_filenames_[i];
@@ -1812,7 +1856,7 @@
       if (strcmp(oat_unstripped_[i], oat_filenames_[i]) != 0) {
         // If the oat file is still open, flush it.
         if (oat_files_[i].get() != nullptr && oat_files_[i]->IsOpened()) {
-          if (!FlushCloseOatFile(i)) {
+          if (!FlushCloseOutputFile(&oat_files_[i])) {
             return false;
           }
         }
@@ -1840,13 +1884,32 @@
     return true;
   }
 
-  bool FlushOatFiles() {
-    TimingLogger::ScopedTiming t2("dex2oat Flush ELF", timings_);
-    for (size_t i = 0; i < oat_files_.size(); ++i) {
-      if (oat_files_[i].get() != nullptr) {
-        if (oat_files_[i]->Flush() != 0) {
-          PLOG(ERROR) << "Failed to flush oat file: " << oat_filenames_[i];
-          oat_files_[i]->Erase();
+  bool FlushOutputFile(std::unique_ptr<File>* file) {
+    if (file->get() != nullptr) {
+      if (file->get()->Flush() != 0) {
+        PLOG(ERROR) << "Failed to flush output file: " << file->get()->GetPath();
+        return false;
+      }
+    }
+    return true;
+  }
+
+  bool FlushCloseOutputFile(std::unique_ptr<File>* file) {
+    if (file->get() != nullptr) {
+      std::unique_ptr<File> tmp(file->release());
+      if (tmp->FlushCloseOrErase() != 0) {
+        PLOG(ERROR) << "Failed to flush and close output file: " << tmp->GetPath();
+        return false;
+      }
+    }
+    return true;
+  }
+
+  bool FlushOutputFiles() {
+    TimingLogger::ScopedTiming t2("dex2oat Flush Output Files", timings_);
+    for (auto& files : { &vdex_files_, &oat_files_ }) {
+      for (size_t i = 0; i < files->size(); ++i) {
+        if (!FlushOutputFile(&(*files)[i])) {
           return false;
         }
       }
@@ -1854,21 +1917,12 @@
     return true;
   }
 
-  bool FlushCloseOatFile(size_t i) {
-    if (oat_files_[i].get() != nullptr) {
-      std::unique_ptr<File> tmp(oat_files_[i].release());
-      if (tmp->FlushCloseOrErase() != 0) {
-        PLOG(ERROR) << "Failed to flush and close oat file: " << oat_filenames_[i];
-        return false;
-      }
-    }
-    return true;
-  }
-
-  bool FlushCloseOatFiles() {
+  bool FlushCloseOutputFiles() {
     bool result = true;
-    for (size_t i = 0; i < oat_files_.size(); ++i) {
-      result &= FlushCloseOatFile(i);
+    for (auto& files : { &vdex_files_, &oat_files_ }) {
+      for (size_t i = 0; i < files->size(); ++i) {
+        result &= FlushCloseOutputFile(&(*files)[i]);
+      }
     }
     return result;
   }
@@ -2503,10 +2557,12 @@
   uint64_t start_ns_;
   std::unique_ptr<WatchDog> watchdog_;
   std::vector<std::unique_ptr<File>> oat_files_;
+  std::vector<std::unique_ptr<File>> vdex_files_;
   std::string oat_location_;
   std::vector<const char*> oat_filenames_;
   std::vector<const char*> oat_unstripped_;
   int oat_fd_;
+  int vdex_fd_;
   std::vector<const char*> dex_filenames_;
   std::vector<const char*> dex_locations_;
   int zip_fd_;
@@ -2603,8 +2659,8 @@
   dex2oat.LoadClassProfileDescriptors();
   dex2oat.Compile();
 
-  if (!dex2oat.WriteOatFiles()) {
-    dex2oat.EraseOatFiles();
+  if (!dex2oat.WriteOutputFiles()) {
+    dex2oat.EraseOutputFiles();
     return EXIT_FAILURE;
   }
 
@@ -2612,10 +2668,11 @@
   // unstripped name. Do not close the file if we are compiling the image with an oat fd since the
   // image writer will require this fd to generate the image.
   if (dex2oat.ShouldKeepOatFileOpen()) {
-    if (!dex2oat.FlushOatFiles()) {
+    if (!dex2oat.FlushOutputFiles()) {
+      dex2oat.EraseOutputFiles();
       return EXIT_FAILURE;
     }
-  } else if (!dex2oat.FlushCloseOatFiles()) {
+  } else if (!dex2oat.FlushCloseOutputFiles()) {
     return EXIT_FAILURE;
   }
 
@@ -2636,7 +2693,7 @@
   }
 
   // FlushClose again, as stripping might have re-opened the oat files.
-  if (!dex2oat.FlushCloseOatFiles()) {
+  if (!dex2oat.FlushCloseOutputFiles()) {
     return EXIT_FAILURE;
   }
 
@@ -2647,8 +2704,8 @@
 static int CompileApp(Dex2Oat& dex2oat) {
   dex2oat.Compile();
 
-  if (!dex2oat.WriteOatFiles()) {
-    dex2oat.EraseOatFiles();
+  if (!dex2oat.WriteOutputFiles()) {
+    dex2oat.EraseOutputFiles();
     return EXIT_FAILURE;
   }
 
@@ -2657,7 +2714,7 @@
 
   // When given --host, finish early without stripping.
   if (dex2oat.IsHost()) {
-    if (!dex2oat.FlushCloseOatFiles()) {
+    if (!dex2oat.FlushCloseOutputFiles()) {
       return EXIT_FAILURE;
     }
 
@@ -2672,7 +2729,7 @@
   }
 
   // Flush and close the files.
-  if (!dex2oat.FlushCloseOatFiles()) {
+  if (!dex2oat.FlushCloseOutputFiles()) {
     return EXIT_FAILURE;
   }
 
@@ -2721,10 +2778,12 @@
   }
 
   if (!dex2oat->Setup()) {
-    dex2oat->EraseOatFiles();
+    dex2oat->EraseOutputFiles();
     return EXIT_FAILURE;
   }
 
+  VLOG(compiler) << "Running dex2oat (parent PID = " << getppid() << ")";
+
   bool result;
   if (dex2oat->IsImage()) {
     result = CompileImage(*dex2oat);
diff --git a/dexdump/Android.bp b/dexdump/Android.bp
index e77f809..74f7578 100644
--- a/dexdump/Android.bp
+++ b/dexdump/Android.bp
@@ -24,3 +24,11 @@
     cflags: ["-Wall"],
     shared_libs: ["libart"],
 }
+
+art_cc_test {
+    name: "art_dexdump_tests",
+    defaults: [
+        "art_test_defaults",
+    ],
+    srcs: ["dexdump_test.cc"],
+}
diff --git a/dexlayout/Android.bp b/dexlayout/Android.bp
index 852f6c2..9c4499f 100644
--- a/dexlayout/Android.bp
+++ b/dexlayout/Android.bp
@@ -23,3 +23,11 @@
     cflags: ["-Wall"],
     shared_libs: ["libart"],
 }
+
+art_cc_test {
+    name: "art_dexlayout_tests",
+    defaults: [
+        "art_test_defaults",
+    ],
+    srcs: ["dexlayout_test.cc"],
+}
diff --git a/dexlist/Android.bp b/dexlist/Android.bp
index 8e3c91d..ddf01db 100644
--- a/dexlist/Android.bp
+++ b/dexlist/Android.bp
@@ -19,3 +19,11 @@
     cflags: ["-Wall"],
     shared_libs: ["libart"],
 }
+
+art_cc_test {
+    name: "art_dexlist_tests",
+    defaults: [
+        "art_test_defaults",
+    ],
+    srcs: ["dexlist_test.cc"],
+}
diff --git a/dexlist/dexlist_test.cc b/dexlist/dexlist_test.cc
index 9a65ba6..da1dd7f 100644
--- a/dexlist/dexlist_test.cc
+++ b/dexlist/dexlist_test.cc
@@ -43,11 +43,7 @@
   // Runs test with given arguments.
   bool Exec(const std::vector<std::string>& args, std::string* error_msg) {
     std::string file_path = GetTestAndroidRoot();
-    if (IsHost()) {
-      file_path += "/bin/dexlist";
-    } else {
-      file_path += "/xbin/dexlist";
-    }
+    file_path += "/bin/dexlist";
     EXPECT_TRUE(OS::FileExists(file_path.c_str())) << file_path << " should be a valid file path";
     std::vector<std::string> exec_argv = { file_path };
     exec_argv.insert(exec_argv.end(), args.begin(), args.end());
diff --git a/disassembler/Android.bp b/disassembler/Android.bp
index d06e4de..b074d9f 100644
--- a/disassembler/Android.bp
+++ b/disassembler/Android.bp
@@ -26,9 +26,9 @@
         "disassembler_mips.cc",
         "disassembler_x86.cc",
     ],
+    include_dirs: ["art/runtime"],
 
     shared_libs: [
-        "liblog",
         "libbase",
     ],
     export_include_dirs: ["."],
@@ -38,9 +38,8 @@
     name: "libart-disassembler",
     defaults: ["libart-disassembler-defaults"],
     shared_libs: [
-        "libart",
         // For disassembler_arm64.
-        "libvixld-arm64",
+        "libvixl-arm64",
     ],
 }
 
@@ -51,7 +50,6 @@
         "art_debug_defaults",
     ],
     shared_libs: [
-        "libartd",
         // For disassembler_arm64.
         "libvixld-arm64",
     ],
diff --git a/imgdiag/Android.bp b/imgdiag/Android.bp
new file mode 100644
index 0000000..639b8e8
--- /dev/null
+++ b/imgdiag/Android.bp
@@ -0,0 +1,79 @@
+//
+// 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.
+//
+
+// Build variants {target,host} x {debug,ndebug} x {32,64}
+
+cc_defaults {
+    name: "imgdiag-defaults",
+    host_supported: true,
+    srcs: ["imgdiag.cc"],
+    defaults: ["art_defaults"],
+
+    // Note that this tool needs to be built for both 32-bit and 64-bit since it requires
+    // that the image it's analyzing be the same ISA as the runtime ISA.
+    compile_multilib: "both",
+
+    shared_libs: ["libbacktrace"],
+    target: {
+        android: {
+            shared_libs: ["libcutils"],
+        },
+        host: {
+            shared_libs: ["libziparchive"],
+        },
+    },
+    include_dirs: [
+        "art/cmdline",
+    ],
+    multilib: {
+        lib32: {
+            suffix: "32",
+        },
+        lib64: {
+            suffix: "64",
+        },
+    },
+    symlink_preferred_arch: true,
+}
+
+art_cc_binary {
+    name: "imgdiag",
+    defaults: ["imgdiag-defaults"],
+    shared_libs: [
+        "libart",
+        "libart-compiler",
+    ],
+}
+
+art_cc_binary {
+    name: "imgdiagd",
+    defaults: [
+        "imgdiag-defaults",
+        "art_debug_defaults",
+    ],
+    shared_libs: [
+        "libartd",
+        "libartd-compiler",
+    ],
+}
+
+art_cc_test {
+    name: "art_imgdiag_tests",
+    defaults: [
+        "art_test_defaults",
+    ],
+    srcs: ["imgdiag_test.cc"],
+}
diff --git a/imgdiag/Android.mk b/imgdiag/Android.mk
deleted file mode 100644
index 278527f..0000000
--- a/imgdiag/Android.mk
+++ /dev/null
@@ -1,32 +0,0 @@
-#
-# 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.
-#
-
-LOCAL_PATH := $(call my-dir)
-
-include art/build/Android.executable.mk
-
-IMGDIAG_SRC_FILES := \
-	imgdiag.cc
-
-# Note that this tool needs to be built for both 32-bit and 64-bit since it requires
-# that the image it's analyzing be the same ISA as the runtime ISA.
-
-# Build variants {target,host} x {debug,ndebug} x {32,64}
-#
-# Honor HOST_PREFER_32_BIT, as building a 64-bit imgdiag executable
-# when HOST_PREFER_32_BIT is true would require an unmet dependency on
-# 64-bit libbacktrace.
-$(eval $(call build-art-multi-executable,imgdiag,$(IMGDIAG_SRC_FILES),libart-compiler libbacktrace,libcutils,libziparchive,art/compiler,both,$(HOST_PREFER_32_BIT)))
diff --git a/oatdump/Android.bp b/oatdump/Android.bp
index b01bf51..02a51a6 100644
--- a/oatdump/Android.bp
+++ b/oatdump/Android.bp
@@ -87,3 +87,10 @@
     ] + art_static_dependencies,
 }
 
+art_cc_test {
+    name: "art_oatdump_tests",
+    defaults: [
+        "art_test_defaults",
+    ],
+    srcs: ["oatdump_test.cc"],
+}
diff --git a/oatdump/Android.mk b/oatdump/Android.mk
index 7be8a8d..d80df70 100644
--- a/oatdump/Android.mk
+++ b/oatdump/Android.mk
@@ -16,6 +16,11 @@
 
 LOCAL_PATH := $(call my-dir)
 
+########################################################################
+# oatdump targets
+
+ART_DUMP_OAT_PATH ?= $(OUT_DIR)
+
 OATDUMP := $(HOST_OUT_EXECUTABLES)/oatdump$(HOST_EXECUTABLE_SUFFIX)
 OATDUMPD := $(HOST_OUT_EXECUTABLES)/oatdumpd$(HOST_EXECUTABLE_SUFFIX)
 # TODO: for now, override with debug version for better error reporting
diff --git a/oatdump/oatdump.cc b/oatdump/oatdump.cc
index c87a18b..db6a709 100644
--- a/oatdump/oatdump.cc
+++ b/oatdump/oatdump.cc
@@ -719,10 +719,12 @@
     os << StringPrintf("location: %s\n", oat_dex_file.GetDexFileLocation().c_str());
     os << StringPrintf("checksum: 0x%08x\n", oat_dex_file.GetDexFileLocationChecksum());
 
-    // Print embedded dex file data range.
     const uint8_t* const oat_file_begin = oat_dex_file.GetOatFile()->Begin();
+    const uint8_t* const vdex_file_begin = oat_dex_file.GetOatFile()->DexBegin();
+
+    // Print data range of the dex file embedded inside the corresponding vdex file.
     const uint8_t* const dex_file_pointer = oat_dex_file.GetDexFilePointer();
-    uint32_t dex_offset = dchecked_integral_cast<uint32_t>(dex_file_pointer - oat_file_begin);
+    uint32_t dex_offset = dchecked_integral_cast<uint32_t>(dex_file_pointer - vdex_file_begin);
     os << StringPrintf("dex-file: 0x%08x..0x%08x\n",
                        dex_offset,
                        dchecked_integral_cast<uint32_t>(dex_offset + oat_dex_file.FileSize() - 1));
diff --git a/patchoat/Android.bp b/patchoat/Android.bp
new file mode 100644
index 0000000..8d8d6d1
--- /dev/null
+++ b/patchoat/Android.bp
@@ -0,0 +1,46 @@
+//
+// 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.
+//
+
+cc_defaults {
+    name: "patchoat-defaults",
+    host_supported: true,
+    defaults: ["art_defaults"],
+    srcs: ["patchoat.cc"],
+    target: {
+        android: {
+            compile_multilib: "prefer32",
+        },
+    },
+}
+
+art_cc_binary {
+    name: "patchoat",
+    defaults: ["patchoat-defaults"],
+    shared_libs: [
+        "libart",
+    ],
+}
+
+art_cc_binary {
+    name: "patchoatd",
+    defaults: [
+        "patchoat-defaults",
+        "art_debug_defaults",
+    ],
+    shared_libs: [
+        "libartd",
+    ],
+}
diff --git a/patchoat/Android.mk b/patchoat/Android.mk
deleted file mode 100644
index 8f9ffca..0000000
--- a/patchoat/Android.mk
+++ /dev/null
@@ -1,45 +0,0 @@
-#
-# 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.
-#
-
-LOCAL_PATH := $(call my-dir)
-
-include art/build/Android.executable.mk
-
-PATCHOAT_SRC_FILES := \
-	patchoat.cc
-
-# TODO: Remove this when the framework (installd) supports pushing the
-# right instruction-set parameter for the primary architecture.
-ifneq ($(filter ro.zygote=zygote64,$(PRODUCT_DEFAULT_PROPERTY_OVERRIDES)),)
-  patchoat_arch := 64
-else
-  patchoat_arch := 32
-endif
-
-ifeq ($(ART_BUILD_TARGET_NDEBUG),true)
-  $(eval $(call build-art-executable,patchoat,$(PATCHOAT_SRC_FILES),libcutils libsigchain,art/compiler,target,ndebug,$(patchoat_arch)))
-endif
-ifeq ($(ART_BUILD_TARGET_DEBUG),true)
-  $(eval $(call build-art-executable,patchoat,$(PATCHOAT_SRC_FILES),libcutils libsigchain,art/compiler,target,debug,$(patchoat_arch)))
-endif
-
-# We always build patchoat and dependencies, even if the host build is otherwise disabled, since they are used to cross compile for the target.
-ifeq ($(ART_BUILD_HOST_NDEBUG),true)
-  $(eval $(call build-art-executable,patchoat,$(PATCHOAT_SRC_FILES),libcutils libsigchain,art/compiler,host,ndebug))
-endif
-ifeq ($(ART_BUILD_HOST_DEBUG),true)
-  $(eval $(call build-art-executable,patchoat,$(PATCHOAT_SRC_FILES),libcutils libsigchain,art/compiler,host,debug))
-endif
diff --git a/patchoat/patchoat.cc b/patchoat/patchoat.cc
index b7ce02c..5240011 100644
--- a/patchoat/patchoat.cc
+++ b/patchoat/patchoat.cc
@@ -31,6 +31,7 @@
 #include "base/stringpiece.h"
 #include "base/stringprintf.h"
 #include "base/unix_file/fd_file.h"
+#include "base/unix_file/random_access_file_utils.h"
 #include "elf_utils.h"
 #include "elf_file.h"
 #include "elf_file_impl.h"
@@ -151,6 +152,28 @@
   }
 }
 
+static bool SymlinkFile(const std::string& input_filename, const std::string& output_filename) {
+  if (input_filename == output_filename) {
+    // Input and output are the same, nothing to do.
+    return true;
+  }
+
+  // Unlink the original filename, since we are overwriting it.
+  unlink(output_filename.c_str());
+
+  // Create a symlink from the source file to the target path.
+  if (symlink(input_filename.c_str(), output_filename.c_str()) < 0) {
+    PLOG(ERROR) << "Failed to create symlink " << output_filename << " -> " << input_filename;
+    return false;
+  }
+
+  if (kIsDebugBuild) {
+    LOG(INFO) << "Created symlink " << output_filename << " -> " << input_filename;
+  }
+
+  return true;
+}
+
 bool PatchOat::Patch(const std::string& image_location,
                      off_t delta,
                      const std::string& output_directory,
@@ -230,9 +253,13 @@
     space_to_memmap_map.emplace(space, std::move(image));
   }
 
+  // Do a first pass over the image spaces. Symlink PIC oat and vdex files, and
+  // prepare PatchOat instances for the rest.
   for (size_t i = 0; i < spaces.size(); ++i) {
     gc::space::ImageSpace* space = spaces[i];
     std::string input_image_filename = space->GetImageFilename();
+    std::string input_vdex_filename =
+        ImageHeader::GetVdexLocationFromImageLocation(input_image_filename);
     std::string input_oat_filename =
         ImageHeader::GetOatLocationFromImageLocation(input_image_filename);
     std::unique_ptr<File> input_oat_file(OS::OpenFileForReading(input_oat_filename.c_str()));
@@ -261,13 +288,16 @@
       std::string output_image_filename = output_directory +
                                           (StartsWith(converted_image_filename, "/") ? "" : "/") +
                                           converted_image_filename;
+      std::string output_vdex_filename =
+          ImageHeader::GetVdexLocationFromImageLocation(output_image_filename);
       std::string output_oat_filename =
           ImageHeader::GetOatLocationFromImageLocation(output_image_filename);
 
       if (!ReplaceOatFileWithSymlink(input_oat_file->GetPath(),
                                      output_oat_filename,
                                      false,
-                                     true)) {
+                                     true) ||
+          !SymlinkFile(input_vdex_filename, output_vdex_filename)) {
         // Errors already logged by above call.
         return false;
       }
@@ -301,9 +331,13 @@
     space_to_skip_patching_map.emplace(space, skip_patching_oat);
   }
 
+  // Do a second pass over the image spaces. Patch image files, non-PIC oat files
+  // and symlink their corresponding vdex files.
   for (size_t i = 0; i < spaces.size(); ++i) {
     gc::space::ImageSpace* space = spaces[i];
     std::string input_image_filename = space->GetImageFilename();
+    std::string input_vdex_filename =
+        ImageHeader::GetVdexLocationFromImageLocation(input_image_filename);
 
     t.NewTiming("Writing files");
     std::string converted_image_filename = space->GetImageLocation();
@@ -329,8 +363,11 @@
 
     bool skip_patching_oat = space_to_skip_patching_map.find(space)->second;
     if (!skip_patching_oat) {
+      std::string output_vdex_filename =
+          ImageHeader::GetVdexLocationFromImageLocation(output_image_filename);
       std::string output_oat_filename =
           ImageHeader::GetOatLocationFromImageLocation(output_image_filename);
+
       std::unique_ptr<File>
           output_oat_file(CreateOrOpen(output_oat_filename.c_str(), &new_oat_out));
       if (output_oat_file.get() == nullptr) {
@@ -339,6 +376,9 @@
       }
       success = p.WriteElf(output_oat_file.get());
       success = FinishFile(output_oat_file.get(), success);
+      if (success) {
+        success = SymlinkFile(input_vdex_filename, output_vdex_filename);
+      }
       if (!success) {
         return false;
       }
@@ -921,6 +961,9 @@
   UsageError("  --input-oat-fd=<file-descriptor>: Specifies the file-descriptor of the oat file");
   UsageError("      to be patched.");
   UsageError("");
+  UsageError("  --input-vdex-fd=<file-descriptor>: Specifies the file-descriptor of the vdex file");
+  UsageError("      associated with the oat file.");
+  UsageError("");
   UsageError("  --input-oat-location=<file.oat>: Specifies the 'location' to read the patched");
   UsageError("      oat file from. If used one must also supply the --instruction-set");
   UsageError("");
@@ -932,7 +975,10 @@
   UsageError("      file to.");
   UsageError("");
   UsageError("  --output-oat-fd=<file-descriptor>: Specifies the file-descriptor to write the");
-  UsageError("      the patched oat file to.");
+  UsageError("      patched oat file to.");
+  UsageError("");
+  UsageError("  --output-vdex-fd=<file-descriptor>: Specifies the file-descriptor to copy the");
+  UsageError("      the vdex file associated with the patch oat file to.");
   UsageError("");
   UsageError("  --output-image-file=<file.art>: Specifies the exact file to write the patched");
   UsageError("      image file to.");
@@ -1029,10 +1075,12 @@
                         off_t base_delta,
                         bool base_delta_set,
                         int input_oat_fd,
+                        int input_vdex_fd,
                         const std::string& input_oat_location,
                         std::string input_oat_filename,
                         bool have_input_oat,
                         int output_oat_fd,
+                        int output_vdex_fd,
                         std::string output_oat_filename,
                         bool have_output_oat,
                         bool lock_output,
@@ -1062,6 +1110,12 @@
     }
   }
 
+  if ((input_oat_fd == -1) != (input_vdex_fd == -1)) {
+    Usage("Either both input oat and vdex have to be passed as file descriptors or none of them");
+  } else if ((output_oat_fd == -1) != (output_vdex_fd == -1)) {
+    Usage("Either both output oat and vdex have to be passed as file descriptors or none of them");
+  }
+
   bool match_delta = false;
   if (!patched_image_location.empty()) {
     std::string system_filename;
@@ -1102,8 +1156,24 @@
     Usage("Base offset/delta must be alligned to a pagesize (0x%08x) boundary.", kPageSize);
   }
 
+  // We can symlink VDEX only if we have both input and output specified as filenames.
+  // Store that piece of information before we possibly create bogus filenames for
+  // files passed as file descriptors.
+  bool symlink_vdex = !input_oat_filename.empty() && !output_oat_filename.empty();
+
+  // Infer names of VDEX files.
+  std::string input_vdex_filename;
+  std::string output_vdex_filename;
+  if (!input_oat_filename.empty()) {
+    input_vdex_filename = ReplaceFileExtension(input_oat_filename, "vdex");
+  }
+  if (!output_oat_filename.empty()) {
+    output_vdex_filename = ReplaceFileExtension(output_oat_filename, "vdex");
+  }
+
   // Do we need to cleanup output files if we fail?
   bool new_oat_out = false;
+  bool new_vdex_out = false;
 
   std::unique_ptr<File> input_oat;
   std::unique_ptr<File> output_oat;
@@ -1162,13 +1232,52 @@
     }
   }
 
+  // Open VDEX files if we are not symlinking them.
+  std::unique_ptr<File> input_vdex;
+  std::unique_ptr<File> output_vdex;
+  if (symlink_vdex) {
+    new_vdex_out = !OS::FileExists(output_vdex_filename.c_str());
+  } else {
+    if (input_vdex_fd != -1) {
+      input_vdex.reset(new File(input_vdex_fd, input_vdex_filename, true));
+      if (input_vdex == nullptr) {
+        // Unlikely, but ensure exhaustive logging in non-0 exit code case
+        LOG(ERROR) << "Failed to open input vdex file by its FD" << input_vdex_fd;
+      }
+    } else {
+      input_vdex.reset(OS::OpenFileForReading(input_vdex_filename.c_str()));
+      if (input_vdex == nullptr) {
+        PLOG(ERROR) << "Failed to open input vdex file " << input_vdex_filename;
+        return EXIT_FAILURE;
+      }
+    }
+    if (output_vdex_fd != -1) {
+      output_vdex.reset(new File(output_vdex_fd, output_vdex_filename, true));
+      if (output_vdex == nullptr) {
+        // Unlikely, but ensure exhaustive logging in non-0 exit code case
+        LOG(ERROR) << "Failed to open output vdex file by its FD" << output_vdex_fd;
+      }
+    } else {
+      output_vdex.reset(CreateOrOpen(output_vdex_filename.c_str(), &new_vdex_out));
+      if (output_vdex == nullptr) {
+        PLOG(ERROR) << "Failed to open output vdex file " << output_vdex_filename;
+        return EXIT_FAILURE;
+      }
+    }
+  }
+
   // TODO: get rid of this.
-  auto cleanup = [&output_oat_filename, &new_oat_out](bool success) {
+  auto cleanup = [&output_oat_filename, &output_vdex_filename, &new_oat_out, &new_vdex_out]
+                 (bool success) {
     if (!success) {
       if (new_oat_out) {
         CHECK(!output_oat_filename.empty());
         unlink(output_oat_filename.c_str());
       }
+      if (new_vdex_out) {
+        CHECK(!output_vdex_filename.empty());
+        unlink(output_vdex_filename.c_str());
+      }
     }
 
     if (kIsDebugBuild) {
@@ -1220,6 +1329,14 @@
                              new_oat_out);
   ret = FinishFile(output_oat.get(), ret);
 
+  if (ret) {
+    if (symlink_vdex) {
+      ret = SymlinkFile(input_vdex_filename, output_vdex_filename);
+    } else {
+      ret = unix_file::CopyFile(*input_vdex.get(), output_vdex.get());
+    }
+  }
+
   if (kIsDebugBuild) {
     LOG(INFO) << "Exiting with return ... " << ret;
   }
@@ -1227,6 +1344,18 @@
   return ret ? EXIT_SUCCESS : EXIT_FAILURE;
 }
 
+static int ParseFd(const StringPiece& option, const char* cmdline_arg) {
+  int fd;
+  const char* fd_str = option.substr(strlen(cmdline_arg)).data();
+  if (!ParseInt(fd_str, &fd)) {
+    Usage("Failed to parse %d argument '%s' as an integer", cmdline_arg, fd_str);
+  }
+  if (fd < 0) {
+    Usage("%s pass a negative value %d", cmdline_arg, fd);
+  }
+  return fd;
+}
+
 static int patchoat(int argc, char **argv) {
   InitLogging(argv);
   MemMap::Init();
@@ -1253,10 +1382,12 @@
   std::string input_oat_filename;
   std::string input_oat_location;
   int input_oat_fd = -1;
+  int input_vdex_fd = -1;
   bool have_input_oat = false;
   std::string input_image_location;
   std::string output_oat_filename;
   int output_oat_fd = -1;
+  int output_vdex_fd = -1;
   bool have_output_oat = false;
   std::string output_image_filename;
   off_t base_delta = 0;
@@ -1296,13 +1427,9 @@
         Usage("Only one of --input-oat-file, --input-oat-location and --input-oat-fd may be used.");
       }
       have_input_oat = true;
-      const char* oat_fd_str = option.substr(strlen("--input-oat-fd=")).data();
-      if (!ParseInt(oat_fd_str, &input_oat_fd)) {
-        Usage("Failed to parse --input-oat-fd argument '%s' as an integer", oat_fd_str);
-      }
-      if (input_oat_fd < 0) {
-        Usage("--input-oat-fd pass a negative value %d", input_oat_fd);
-      }
+      input_oat_fd = ParseFd(option, "--input-oat-fd=");
+    } else if (option.starts_with("--input-vdex-fd=")) {
+      input_vdex_fd = ParseFd(option, "--input-vdex-fd=");
     } else if (option.starts_with("--input-image-location=")) {
       input_image_location = option.substr(strlen("--input-image-location=")).data();
     } else if (option.starts_with("--output-oat-file=")) {
@@ -1316,13 +1443,9 @@
         Usage("Only one of --output-oat-file, --output-oat-fd may be used.");
       }
       have_output_oat = true;
-      const char* oat_fd_str = option.substr(strlen("--output-oat-fd=")).data();
-      if (!ParseInt(oat_fd_str, &output_oat_fd)) {
-        Usage("Failed to parse --output-oat-fd argument '%s' as an integer", oat_fd_str);
-      }
-      if (output_oat_fd < 0) {
-        Usage("--output-oat-fd pass a negative value %d", output_oat_fd);
-      }
+      output_oat_fd = ParseFd(option, "--output-oat-fd=");
+    } else if (option.starts_with("--output-vdex-fd=")) {
+      output_vdex_fd = ParseFd(option, "--output-vdex-fd=");
     } else if (option.starts_with("--output-image-file=")) {
       output_image_filename = option.substr(strlen("--output-image-file=")).data();
     } else if (option.starts_with("--base-offset-delta=")) {
@@ -1367,10 +1490,12 @@
                        base_delta,
                        base_delta_set,
                        input_oat_fd,
+                       input_vdex_fd,
                        input_oat_location,
                        input_oat_filename,
                        have_input_oat,
                        output_oat_fd,
+                       output_vdex_fd,
                        output_oat_filename,
                        have_output_oat,
                        lock_output,
diff --git a/profman/Android.bp b/profman/Android.bp
new file mode 100644
index 0000000..cd1aaab
--- /dev/null
+++ b/profman/Android.bp
@@ -0,0 +1,62 @@
+//
+// 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.
+//
+
+cc_defaults {
+    name: "profman-defaults",
+    host_supported: true,
+    defaults: ["art_defaults"],
+    srcs: [
+        "profman.cc",
+        "profile_assistant.cc",
+    ],
+
+    target: {
+        android: {
+            compile_multilib: "prefer32",
+        },
+    },
+
+    include_dirs: [
+        "art/cmdline",
+    ],
+}
+
+art_cc_binary {
+    name: "profman",
+    defaults: ["profman-defaults"],
+    shared_libs: [
+        "libart",
+    ],
+}
+
+art_cc_binary {
+    name: "profmand",
+    defaults: [
+        "profman-defaults",
+        "art_debug_defaults",
+    ],
+    shared_libs: [
+        "libartd",
+    ],
+}
+
+art_cc_test {
+    name: "art_profman_tests",
+    defaults: [
+        "art_test_defaults",
+    ],
+    srcs: ["profile_assistant_test.cc"],
+}
diff --git a/profman/Android.mk b/profman/Android.mk
deleted file mode 100644
index d38d107..0000000
--- a/profman/Android.mk
+++ /dev/null
@@ -1,45 +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 := $(call my-dir)
-
-include art/build/Android.executable.mk
-
-PROFMAN_SRC_FILES := \
-	profman.cc \
-	profile_assistant.cc
-
-# TODO: Remove this when the framework (installd) supports pushing the
-# right instruction-set parameter for the primary architecture.
-ifneq ($(filter ro.zygote=zygote64,$(PRODUCT_DEFAULT_PROPERTY_OVERRIDES)),)
-  profman_arch := 64
-else
-  profman_arch := 32
-endif
-
-ifeq ($(ART_BUILD_TARGET_NDEBUG),true)
-  $(eval $(call build-art-executable,profman,$(PROFMAN_SRC_FILES),libcutils,art/profman,target,ndebug,$(profman_arch)))
-endif
-ifeq ($(ART_BUILD_TARGET_DEBUG),true)
-  $(eval $(call build-art-executable,profman,$(PROFMAN_SRC_FILES),libcutils,art/profman,target,debug,$(profman_arch)))
-endif
-
-ifeq ($(ART_BUILD_HOST_NDEBUG),true)
-  $(eval $(call build-art-executable,profman,$(PROFMAN_SRC_FILES),libcutils,art/profman,host,ndebug))
-endif
-ifeq ($(ART_BUILD_HOST_DEBUG),true)
-  $(eval $(call build-art-executable,profman,$(PROFMAN_SRC_FILES),libcutils,art/profman,host,debug))
-endif
diff --git a/runtime/Android.bp b/runtime/Android.bp
index 59e4a15..6acc1d8 100644
--- a/runtime/Android.bp
+++ b/runtime/Android.bp
@@ -53,6 +53,7 @@
         "compiler_filter.cc",
         "debugger.cc",
         "dex_file.cc",
+        "dex_file_annotations.cc",
         "dex_file_verifier.cc",
         "dex_instruction.cc",
         "elf_file.cc",
@@ -155,6 +156,7 @@
         "native/java_lang_reflect_Constructor.cc",
         "native/java_lang_reflect_Field.cc",
         "native/java_lang_reflect_Method.cc",
+        "native/java_lang_reflect_Parameter.cc",
         "native/java_lang_reflect_Proxy.cc",
         "native/java_util_concurrent_atomic_AtomicLong.cc",
         "native/libcore_util_CharsetUtils.cc",
@@ -190,6 +192,7 @@
         "type_lookup_table.cc",
         "utf.cc",
         "utils.cc",
+        "vdex_file.cc",
         "verifier/instruction_flags.cc",
         "verifier/method_verifier.cc",
         "verifier/reg_type.cc",
@@ -459,6 +462,126 @@
     ],
 }
 
+art_cc_library {
+    name: "libart-runtime-gtest",
+    defaults: ["libart-gtest-defaults"],
+    srcs: ["common_runtime_test.cc"],
+    shared_libs: [
+        "libartd",
+    ],
+}
+
+art_cc_test {
+    name: "art_runtime_tests",
+    defaults: [
+        "art_test_defaults",
+    ],
+    srcs: [
+        "arch/arch_test.cc",
+        "arch/instruction_set_test.cc",
+        "arch/instruction_set_features_test.cc",
+        "arch/memcmp16_test.cc",
+        "arch/stub_test.cc",
+        "arch/arm/instruction_set_features_arm_test.cc",
+        "arch/arm64/instruction_set_features_arm64_test.cc",
+        "arch/mips/instruction_set_features_mips_test.cc",
+        "arch/mips64/instruction_set_features_mips64_test.cc",
+        "arch/x86/instruction_set_features_x86_test.cc",
+        "arch/x86_64/instruction_set_features_x86_64_test.cc",
+        "barrier_test.cc",
+        "base/arena_allocator_test.cc",
+        "base/bit_field_test.cc",
+        "base/bit_utils_test.cc",
+        "base/bit_vector_test.cc",
+        "base/hash_set_test.cc",
+        "base/hex_dump_test.cc",
+        "base/histogram_test.cc",
+        "base/mutex_test.cc",
+        "base/scoped_flock_test.cc",
+        "base/stringprintf_test.cc",
+        "base/time_utils_test.cc",
+        "base/timing_logger_test.cc",
+        "base/transform_array_ref_test.cc",
+        "base/transform_iterator_test.cc",
+        "base/variant_map_test.cc",
+        "base/unix_file/fd_file_test.cc",
+        "class_linker_test.cc",
+        "compiler_filter_test.cc",
+        "dex_file_test.cc",
+        "dex_file_verifier_test.cc",
+        "dex_instruction_test.cc",
+        "dex_instruction_visitor_test.cc",
+        "dex_method_iterator_test.cc",
+        "entrypoints/math_entrypoints_test.cc",
+        "entrypoints/quick/quick_trampoline_entrypoints_test.cc",
+        "entrypoints_order_test.cc",
+        "gc/accounting/card_table_test.cc",
+        "gc/accounting/mod_union_table_test.cc",
+        "gc/accounting/space_bitmap_test.cc",
+        "gc/collector/immune_spaces_test.cc",
+        "gc/heap_test.cc",
+        "gc/reference_queue_test.cc",
+        "gc/space/dlmalloc_space_static_test.cc",
+        "gc/space/dlmalloc_space_random_test.cc",
+        "gc/space/large_object_space_test.cc",
+        "gc/space/rosalloc_space_static_test.cc",
+        "gc/space/rosalloc_space_random_test.cc",
+        "gc/space/space_create_test.cc",
+        "gc/system_weak_test.cc",
+        "gc/task_processor_test.cc",
+        "gtest_test.cc",
+        "handle_scope_test.cc",
+        "indenter_test.cc",
+        "indirect_reference_table_test.cc",
+        "instrumentation_test.cc",
+        "intern_table_test.cc",
+        "interpreter/safe_math_test.cc",
+        "interpreter/unstarted_runtime_test.cc",
+        "java_vm_ext_test.cc",
+        "jit/profile_compilation_info_test.cc",
+        "leb128_test.cc",
+        "mem_map_test.cc",
+        "memory_region_test.cc",
+        "mirror/dex_cache_test.cc",
+        "mirror/object_test.cc",
+        "monitor_pool_test.cc",
+        "monitor_test.cc",
+        "oat_file_test.cc",
+        "oat_file_assistant_test.cc",
+        "parsed_options_test.cc",
+        "prebuilt_tools_test.cc",
+        "reference_table_test.cc",
+        "thread_pool_test.cc",
+        "transaction_test.cc",
+        "type_lookup_table_test.cc",
+        "utf_test.cc",
+        "utils_test.cc",
+        "verifier/method_verifier_test.cc",
+        "verifier/reg_type_test.cc",
+        "zip_archive_test.cc",
+    ],
+    shared_libs: [
+        "libbacktrace",
+    ],
+}
+
+art_cc_test {
+    name: "art_runtime_compiler_tests",
+    defaults: [
+        "art_test_defaults",
+    ],
+    srcs: [
+        "jni_internal_test.cc",
+        "proxy_test.cc",
+        "reflection_test.cc",
+    ],
+    shared_libs: [
+        "libartd-compiler",
+        "libvixld-arm",
+        "libvixld-arm64",
+    ],
+}
+
 subdirs = [
     "openjdkjvm",
     "openjdkjvmti",
diff --git a/runtime/arch/arm/fault_handler_arm.cc b/runtime/arch/arm/fault_handler_arm.cc
index befdd48..daa2dff 100644
--- a/runtime/arch/arm/fault_handler_arm.cc
+++ b/runtime/arch/arm/fault_handler_arm.cc
@@ -122,13 +122,16 @@
   struct ucontext *uc = reinterpret_cast<struct ucontext*>(context);
   struct sigcontext *sc = reinterpret_cast<struct sigcontext*>(&uc->uc_mcontext);
   uint8_t* ptr = reinterpret_cast<uint8_t*>(sc->arm_pc);
-
   uint32_t instr_size = GetInstructionSize(ptr);
-  sc->arm_lr = (sc->arm_pc + instr_size) | 1;      // LR needs to point to gc map location
+  uintptr_t gc_map_location = (sc->arm_pc + instr_size) | 1;
+
+  // Push the gc map location to the stack and pass the fault address in LR.
+  sc->arm_sp -= sizeof(uintptr_t);
+  *reinterpret_cast<uintptr_t*>(sc->arm_sp) = gc_map_location;
+  sc->arm_lr = reinterpret_cast<uintptr_t>(info->si_addr);
   sc->arm_pc = reinterpret_cast<uintptr_t>(art_quick_throw_null_pointer_exception_from_signal);
   // Pass the faulting address as the first argument of
   // art_quick_throw_null_pointer_exception_from_signal.
-  sc->arm_r0 = reinterpret_cast<uintptr_t>(info->si_addr);
   VLOG(signals) << "Generating null pointer exception";
   return true;
 }
diff --git a/runtime/arch/arm/quick_entrypoints_arm.S b/runtime/arch/arm/quick_entrypoints_arm.S
index a3f053b..0b04480 100644
--- a/runtime/arch/arm/quick_entrypoints_arm.S
+++ b/runtime/arch/arm/quick_entrypoints_arm.S
@@ -173,6 +173,29 @@
     /*
      * Macro that sets up the callee save frame to conform with
      * Runtime::CreateCalleeSaveMethod(kSaveEverything)
+     * when core registers are already saved.
+     */
+.macro SETUP_SAVE_EVERYTHING_FRAME_CORE_REGS_SAVED rTemp
+                                        @ 14 words of callee saves and args already saved.
+    vpush {d0-d15}                      @ 32 words, 2 for each of the 16 saved doubles.
+    .cfi_adjust_cfa_offset 128
+    sub sp, #8                          @ 2 words of space, alignment padding and Method*
+    .cfi_adjust_cfa_offset 8
+    RUNTIME_CURRENT1 \rTemp             @ Load Runtime::Current into rTemp.
+    @ Load kSaveEverything Method* into rTemp.
+    ldr \rTemp, [\rTemp, #RUNTIME_SAVE_EVERYTHING_METHOD_OFFSET]
+    str \rTemp, [sp, #0]                @ Place Method* at bottom of stack.
+    str sp, [r9, #THREAD_TOP_QUICK_FRAME_OFFSET]  @ Place sp in Thread::Current()->top_quick_frame.
+
+    // Ugly compile-time check, but we only have the preprocessor.
+#if (FRAME_SIZE_SAVE_EVERYTHING != 56 + 128 + 8)
+#error "FRAME_SIZE_SAVE_EVERYTHING(ARM) size not as expected."
+#endif
+.endm
+
+    /*
+     * Macro that sets up the callee save frame to conform with
+     * Runtime::CreateCalleeSaveMethod(kSaveEverything)
      */
 .macro SETUP_SAVE_EVERYTHING_FRAME rTemp
     push {r0-r12, lr}                   @ 14 words of callee saves and args.
@@ -191,20 +214,7 @@
     .cfi_rel_offset r11, 44
     .cfi_rel_offset ip, 48
     .cfi_rel_offset lr, 52
-    vpush {d0-d15}                      @ 32 words, 2 for each of the 16 saved doubles.
-    .cfi_adjust_cfa_offset 128
-    sub sp, #8                          @ 2 words of space, alignment padding and Method*
-    .cfi_adjust_cfa_offset 8
-    RUNTIME_CURRENT1 \rTemp             @ Load Runtime::Current into rTemp.
-    @ Load kSaveEverything Method* into rTemp.
-    ldr \rTemp, [\rTemp, #RUNTIME_SAVE_EVERYTHING_METHOD_OFFSET]
-    str \rTemp, [sp, #0]                @ Place Method* at bottom of stack.
-    str sp, [r9, #THREAD_TOP_QUICK_FRAME_OFFSET]  @ Place sp in Thread::Current()->top_quick_frame.
-
-    // Ugly compile-time check, but we only have the preprocessor.
-#if (FRAME_SIZE_SAVE_EVERYTHING != 56 + 128 + 8)
-#error "FRAME_SIZE_SAVE_EVERYTHING(ARM) size not as expected."
-#endif
+    SETUP_SAVE_EVERYTHING_FRAME_CORE_REGS_SAVED \rTemp
 .endm
 
 .macro RESTORE_SAVE_EVERYTHING_FRAME
@@ -250,7 +260,7 @@
     .fnstart
     SETUP_SAVE_ALL_CALLEE_SAVES_FRAME r0       @ save callee saves for throw
     mov    r0, r9                              @ pass Thread::Current
-    b      artDeliverPendingExceptionFromCode  @ artDeliverPendingExceptionFromCode(Thread*)
+    bl     artDeliverPendingExceptionFromCode  @ artDeliverPendingExceptionFromCode(Thread*)
 .endm
 
 .macro NO_ARG_RUNTIME_EXCEPTION c_name, cxx_name
@@ -258,7 +268,7 @@
 ENTRY \c_name
     SETUP_SAVE_ALL_CALLEE_SAVES_FRAME r0       @ save all registers as basis for long jump context
     mov r0, r9                      @ pass Thread::Current
-    b   \cxx_name                   @ \cxx_name(Thread*)
+    bl  \cxx_name                   @ \cxx_name(Thread*)
 END \c_name
 .endm
 
@@ -267,7 +277,7 @@
 ENTRY \c_name
     SETUP_SAVE_ALL_CALLEE_SAVES_FRAME r1       @ save all registers as basis for long jump context
     mov r1, r9                      @ pass Thread::Current
-    b   \cxx_name                   @ \cxx_name(Thread*)
+    bl  \cxx_name                   @ \cxx_name(Thread*)
 END \c_name
 .endm
 
@@ -276,7 +286,7 @@
 ENTRY \c_name
     SETUP_SAVE_ALL_CALLEE_SAVES_FRAME r2       @ save all registers as basis for long jump context
     mov r2, r9                      @ pass Thread::Current
-    b   \cxx_name                   @ \cxx_name(Thread*)
+    bl  \cxx_name                   @ \cxx_name(Thread*)
 END \c_name
 .endm
 
@@ -356,7 +366,34 @@
     /*
      * Call installed by a signal handler to create and deliver a NullPointerException.
      */
-ONE_ARG_RUNTIME_EXCEPTION art_quick_throw_null_pointer_exception_from_signal, artThrowNullPointerExceptionFromSignal
+    .extern art_quick_throw_null_pointer_exception_from_signal
+ENTRY art_quick_throw_null_pointer_exception_from_signal
+    // The fault handler pushes the gc map address, i.e. "return address", to stack
+    // and passes the fault address in LR. So we need to set up the CFI info accordingly.
+    .cfi_def_cfa_offset __SIZEOF_POINTER__
+    .cfi_rel_offset lr, 0
+    push {r0-r12}                   @ 13 words of callee saves and args; LR already saved.
+    .cfi_adjust_cfa_offset 52
+    .cfi_rel_offset r0, 0
+    .cfi_rel_offset r1, 4
+    .cfi_rel_offset r2, 8
+    .cfi_rel_offset r3, 12
+    .cfi_rel_offset r4, 16
+    .cfi_rel_offset r5, 20
+    .cfi_rel_offset r6, 24
+    .cfi_rel_offset r7, 28
+    .cfi_rel_offset r8, 32
+    .cfi_rel_offset r9, 36
+    .cfi_rel_offset r10, 40
+    .cfi_rel_offset r11, 44
+    .cfi_rel_offset ip, 48
+
+    @ save all registers as basis for long jump context
+    SETUP_SAVE_EVERYTHING_FRAME_CORE_REGS_SAVED r1
+    mov r0, lr                      @ pass the fault address stored in LR by the fault handler.
+    mov r1, r9                      @ pass Thread::Current
+    bl  artThrowNullPointerExceptionFromSignal  @ (Thread*)
+END art_quick_throw_null_pointer_exception_from_signal
 
     /*
      * Called by managed code to create and deliver an ArithmeticException.
@@ -381,11 +418,6 @@
 NO_ARG_RUNTIME_EXCEPTION art_quick_throw_stack_overflow, artThrowStackOverflowFromCode
 
     /*
-     * Called by managed code to create and deliver a NoSuchMethodError.
-     */
-ONE_ARG_RUNTIME_EXCEPTION art_quick_throw_no_such_method, artThrowNoSuchMethodFromCode
-
-    /*
      * All generated callsites for interface invokes and invocation slow paths will load arguments
      * as usual - except instead of loading arg0/r0 with the target Method*, arg0/r0 will contain
      * the method_idx.  This wrapper will save arg1-arg3, and call the appropriate C helper.
@@ -721,7 +753,7 @@
     .cfi_restore lr
     SETUP_SAVE_ALL_CALLEE_SAVES_FRAME r2       @ save all registers as basis for long jump context
     mov r2, r9                      @ pass Thread::Current
-    b   artThrowClassCastException  @ (Class*, Class*, Thread*)
+    bl  artThrowClassCastException  @ (Class*, Class*, Thread*)
     bkpt
 END art_quick_check_cast
 
@@ -864,7 +896,7 @@
     SETUP_SAVE_ALL_CALLEE_SAVES_FRAME r3
     mov r1, r2
     mov r2, r9                     @ pass Thread::Current
-    b artThrowArrayStoreException  @ (Class*, Class*, Thread*)
+    bl artThrowArrayStoreException @ (Class*, Class*, Thread*)
     bkpt                           @ unreached
 END art_quick_aput_obj
 
diff --git a/runtime/arch/arm64/fault_handler_arm64.cc b/runtime/arch/arm64/fault_handler_arm64.cc
index 6724d6d..c02be87 100644
--- a/runtime/arch/arm64/fault_handler_arm64.cc
+++ b/runtime/arch/arm64/fault_handler_arm64.cc
@@ -96,12 +96,12 @@
   struct ucontext *uc = reinterpret_cast<struct ucontext*>(context);
   struct sigcontext *sc = reinterpret_cast<struct sigcontext*>(&uc->uc_mcontext);
 
-  sc->regs[30] = sc->pc + 4;      // LR needs to point to gc map location
+  // Push the gc map location to the stack and pass the fault address in LR.
+  sc->sp -= sizeof(uintptr_t);
+  *reinterpret_cast<uintptr_t*>(sc->sp) = sc->pc + 4;
+  sc->regs[30] = reinterpret_cast<uintptr_t>(info->si_addr);
 
   sc->pc = reinterpret_cast<uintptr_t>(art_quick_throw_null_pointer_exception_from_signal);
-  // Pass the faulting address as the first argument of
-  // art_quick_throw_null_pointer_exception_from_signal.
-  sc->regs[0] = reinterpret_cast<uintptr_t>(info->si_addr);
   VLOG(signals) << "Generating null pointer exception";
   return true;
 }
diff --git a/runtime/arch/arm64/quick_entrypoints_arm64.S b/runtime/arch/arm64/quick_entrypoints_arm64.S
index 25aa8ce..e9d03d7 100644
--- a/runtime/arch/arm64/quick_entrypoints_arm64.S
+++ b/runtime/arch/arm64/quick_entrypoints_arm64.S
@@ -265,10 +265,10 @@
     /*
      * Macro that sets up the callee save frame to conform with
      * Runtime::CreateCalleeSaveMethod(kSaveEverything)
+     * when the SP has already been decremented by FRAME_SIZE_SAVE_EVERYTHING
+     * and saving registers x29 and LR is handled elsewhere.
      */
-.macro SETUP_SAVE_EVERYTHING_FRAME
-    INCREASE_FRAME 512
-
+.macro SETUP_SAVE_EVERYTHING_FRAME_DECREMENTED_SP_SKIP_X29_LR
     // Ugly compile-time check, but we only have the preprocessor.
 #if (FRAME_SIZE_SAVE_EVERYTHING != 512)
 #error "FRAME_SIZE_SAVE_EVERYTHING(ARM64) size not as expected."
@@ -310,7 +310,6 @@
     SAVE_TWO_REGS x23, x24, 448
     SAVE_TWO_REGS x25, x26, 464
     SAVE_TWO_REGS x27, x28, 480
-    SAVE_TWO_REGS x29, xLR, 496
 
     // art::Runtime** xIP0 = &art::Runtime::instance_
     adrp xIP0, :got:_ZN3art7Runtime9instance_E
@@ -328,6 +327,16 @@
     str xIP0, [xSELF, # THREAD_TOP_QUICK_FRAME_OFFSET]
 .endm
 
+    /*
+     * Macro that sets up the callee save frame to conform with
+     * Runtime::CreateCalleeSaveMethod(kSaveEverything)
+     */
+.macro SETUP_SAVE_EVERYTHING_FRAME
+    INCREASE_FRAME 512
+    SAVE_TWO_REGS x29, xLR, 496
+    SETUP_SAVE_EVERYTHING_FRAME_DECREMENTED_SP_SKIP_X29_LR
+.endm
+
 .macro RESTORE_SAVE_EVERYTHING_FRAME
     // Restore FP registers.
     // For better performance, load d0 and d31 separately, so that all LDPs are 16-byte aligned.
@@ -391,7 +400,7 @@
     mov x0, xSELF
 
     // Point of no return.
-    b artDeliverPendingExceptionFromCode  // artDeliverPendingExceptionFromCode(Thread*)
+    bl artDeliverPendingExceptionFromCode  // artDeliverPendingExceptionFromCode(Thread*)
     brk 0  // Unreached
 .endm
 
@@ -424,7 +433,7 @@
 ENTRY \c_name
     SETUP_SAVE_ALL_CALLEE_SAVES_FRAME // save all registers as basis for long jump context
     mov x0, xSELF                     // pass Thread::Current
-    b   \cxx_name                     // \cxx_name(Thread*)
+    bl  \cxx_name                     // \cxx_name(Thread*)
 END \c_name
 .endm
 
@@ -433,7 +442,7 @@
 ENTRY \c_name
     SETUP_SAVE_ALL_CALLEE_SAVES_FRAME // save all registers as basis for long jump context.
     mov x1, xSELF                     // pass Thread::Current.
-    b   \cxx_name                     // \cxx_name(arg, Thread*).
+    bl  \cxx_name                     // \cxx_name(arg, Thread*).
     brk 0
 END \c_name
 .endm
@@ -443,7 +452,7 @@
 ENTRY \c_name
     SETUP_SAVE_ALL_CALLEE_SAVES_FRAME // save all registers as basis for long jump context
     mov x2, xSELF                     // pass Thread::Current
-    b   \cxx_name                     // \cxx_name(arg1, arg2, Thread*)
+    bl  \cxx_name                     // \cxx_name(arg1, arg2, Thread*)
     brk 0
 END \c_name
 .endm
@@ -462,7 +471,21 @@
     /*
      * Call installed by a signal handler to create and deliver a NullPointerException.
      */
-ONE_ARG_RUNTIME_EXCEPTION art_quick_throw_null_pointer_exception_from_signal, artThrowNullPointerExceptionFromSignal
+    .extern art_quick_throw_null_pointer_exception_from_signal
+ENTRY art_quick_throw_null_pointer_exception_from_signal
+    // The fault handler pushes the gc map address, i.e. "return address", to stack
+    // and passes the fault address in LR. So we need to set up the CFI info accordingly.
+    .cfi_def_cfa_offset __SIZEOF_POINTER__
+    .cfi_rel_offset lr, 0
+    // Save all registers as basis for long jump context.
+    INCREASE_FRAME (FRAME_SIZE_SAVE_EVERYTHING - __SIZEOF_POINTER__)
+    SAVE_REG x29, (FRAME_SIZE_SAVE_EVERYTHING - 2 * __SIZEOF_POINTER__)  // LR already saved.
+    SETUP_SAVE_EVERYTHING_FRAME_DECREMENTED_SP_SKIP_X29_LR
+    mov x0, lr                        // pass the fault address stored in LR by the fault handler.
+    mov x1, xSELF                     // pass Thread::Current.
+    bl  artThrowNullPointerExceptionFromSignal  // (arg, Thread*).
+    brk 0
+END art_quick_throw_null_pointer_exception_from_signal
 
     /*
      * Called by managed code to create and deliver an ArithmeticException.
@@ -487,11 +510,6 @@
 NO_ARG_RUNTIME_EXCEPTION art_quick_throw_stack_overflow, artThrowStackOverflowFromCode
 
     /*
-     * Called by managed code to create and deliver a NoSuchMethodError.
-     */
-ONE_ARG_RUNTIME_EXCEPTION art_quick_throw_no_such_method, artThrowNoSuchMethodFromCode
-
-    /*
      * All generated callsites for interface invokes and invocation slow paths will load arguments
      * as usual - except instead of loading arg0/x0 with the target Method*, arg0/x0 will contain
      * the method_idx.  This wrapper will save arg1-arg3, and call the appropriate C helper.
@@ -1283,7 +1301,7 @@
 
     SETUP_SAVE_ALL_CALLEE_SAVES_FRAME // save all registers as basis for long jump context
     mov x2, xSELF                     // pass Thread::Current
-    b artThrowClassCastException      // (Class*, Class*, Thread*)
+    bl artThrowClassCastException     // (Class*, Class*, Thread*)
     brk 0                             // We should not return here...
 END art_quick_check_cast
 
@@ -1447,10 +1465,10 @@
     RESTORE_TWO_REGS_DECREASE_FRAME x0, x1, 32
 
     SETUP_SAVE_ALL_CALLEE_SAVES_FRAME
-    mov x1, x2                    // Pass value.
-    mov x2, xSELF                 // Pass Thread::Current.
-    b artThrowArrayStoreException // (Object*, Object*, Thread*).
-    brk 0                         // Unreached.
+    mov x1, x2                      // Pass value.
+    mov x2, xSELF                   // Pass Thread::Current.
+    bl artThrowArrayStoreException  // (Object*, Object*, Thread*).
+    brk 0                           // Unreached.
 END art_quick_aput_obj
 
 // Macro to facilitate adding new allocation entrypoints.
diff --git a/runtime/arch/mips/asm_support_mips.S b/runtime/arch/mips/asm_support_mips.S
index 801f708..7955b1d 100644
--- a/runtime/arch/mips/asm_support_mips.S
+++ b/runtime/arch/mips/asm_support_mips.S
@@ -43,7 +43,7 @@
 .endm
 
      // Declare a function called name, doesn't set up $gp.
-.macro ENTRY_NO_GP name
+.macro ENTRY_NO_GP_CUSTOM_CFA name, cfa_offset
     .type \name, %function
     .global \name
     // Cache alignment for function entry.
@@ -51,7 +51,12 @@
 \name:
     .cfi_startproc
      // Ensure we get a sane starting CFA.
-    .cfi_def_cfa $sp,0
+    .cfi_def_cfa $sp, \cfa_offset
+.endm
+
+     // Declare a function called name, doesn't set up $gp.
+.macro ENTRY_NO_GP name
+    ENTRY_NO_GP_CUSTOM_CFA \name, 0
 .endm
 
 .macro END name
diff --git a/runtime/arch/mips/entrypoints_init_mips.cc b/runtime/arch/mips/entrypoints_init_mips.cc
index 38aa67c..e10d4e6 100644
--- a/runtime/arch/mips/entrypoints_init_mips.cc
+++ b/runtime/arch/mips/entrypoints_init_mips.cc
@@ -264,8 +264,6 @@
   static_assert(!IsDirectEntrypoint(kQuickThrowArrayBounds), "Non-direct C stub marked direct.");
   qpoints->pThrowDivZero = art_quick_throw_div_zero;
   static_assert(!IsDirectEntrypoint(kQuickThrowDivZero), "Non-direct C stub marked direct.");
-  qpoints->pThrowNoSuchMethod = art_quick_throw_no_such_method;
-  static_assert(!IsDirectEntrypoint(kQuickThrowNoSuchMethod), "Non-direct C stub marked direct.");
   qpoints->pThrowNullPointer = art_quick_throw_null_pointer_exception;
   static_assert(!IsDirectEntrypoint(kQuickThrowNullPointer), "Non-direct C stub marked direct.");
   qpoints->pThrowStackOverflow = art_quick_throw_stack_overflow;
diff --git a/runtime/arch/mips/fault_handler_mips.cc b/runtime/arch/mips/fault_handler_mips.cc
index 7969a8f..b6a63ca 100644
--- a/runtime/arch/mips/fault_handler_mips.cc
+++ b/runtime/arch/mips/fault_handler_mips.cc
@@ -14,7 +14,7 @@
  * limitations under the License.
  */
 
-
+#include "arch/mips/quick_method_frame_info_mips.h"
 #include "fault_handler.h"
 #include <sys/ucontext.h>
 #include "art_method-inl.h"
@@ -82,12 +82,15 @@
   struct ucontext *uc = reinterpret_cast<struct ucontext*>(context);
   struct sigcontext *sc = reinterpret_cast<struct sigcontext*>(&uc->uc_mcontext);
 
+  // Decrement $sp by the frame size of the kSaveEverything method and store
+  // the fault address in the padding right after the ArtMethod*.
+  sc->sc_regs[mips::SP] -= mips::MipsCalleeSaveFrameSize(Runtime::kSaveEverything);
+  uintptr_t* padding = reinterpret_cast<uintptr_t*>(sc->sc_regs[mips::SP]) + /* ArtMethod* */ 1;
+  *padding = reinterpret_cast<uintptr_t>(info->si_addr);
+
   sc->sc_regs[mips::RA] = sc->sc_pc + 4;      // RA needs to point to gc map location
   sc->sc_pc = reinterpret_cast<uintptr_t>(art_quick_throw_null_pointer_exception_from_signal);
   sc->sc_regs[mips::T9] = sc->sc_pc;          // make sure T9 points to the function
-  // Pass the faulting address as the first argument of
-  // art_quick_throw_null_pointer_exception_from_signal.
-  sc->sc_regs[mips::A0] = reinterpret_cast<uintptr_t>(info->si_addr);
   VLOG(signals) << "Generating null pointer exception";
   return true;
 }
diff --git a/runtime/arch/mips/quick_entrypoints_mips.S b/runtime/arch/mips/quick_entrypoints_mips.S
index 4bd1314..4563004 100644
--- a/runtime/arch/mips/quick_entrypoints_mips.S
+++ b/runtime/arch/mips/quick_entrypoints_mips.S
@@ -279,6 +279,7 @@
     /*
      * Macro that sets up the callee save frame to conform with
      * Runtime::CreateCalleeSaveMethod(kSaveEverything).
+     * when the $sp has already been decremented by FRAME_SIZE_SAVE_EVERYTHING.
      * Callee-save: $at, $v0-$v1, $a0-$a3, $t0-$t7, $s0-$s7, $t8-$t9, $gp, $fp $ra, $f0-$f31;
      *              28(GPR)+ 32(FPR) + 3 words for padding and 1 word for Method*
      * Clobbers $t0 and $t1.
@@ -286,10 +287,7 @@
      * Reserves FRAME_SIZE_SAVE_EVERYTHING + ARG_SLOT_SIZE bytes on the stack.
      * This macro sets up $gp; entrypoints using it should start with ENTRY_NO_GP.
      */
-.macro SETUP_SAVE_EVERYTHING_FRAME
-    addiu  $sp, $sp, -256
-    .cfi_adjust_cfa_offset 256
-
+.macro SETUP_SAVE_EVERYTHING_FRAME_DECREMENTED_SP
      // Ugly compile-time check, but we only have the preprocessor.
 #if (FRAME_SIZE_SAVE_EVERYTHING != 256)
 #error "FRAME_SIZE_SAVE_EVERYTHING(MIPS) size not as expected."
@@ -388,6 +386,22 @@
     .cfi_adjust_cfa_offset ARG_SLOT_SIZE
 .endm
 
+    /*
+     * Macro that sets up the callee save frame to conform with
+     * Runtime::CreateCalleeSaveMethod(kSaveEverything).
+     * Callee-save: $at, $v0-$v1, $a0-$a3, $t0-$t7, $s0-$s7, $t8-$t9, $gp, $fp $ra, $f0-$f31;
+     *              28(GPR)+ 32(FPR) + 3 words for padding and 1 word for Method*
+     * Clobbers $t0 and $t1.
+     * Allocates ARG_SLOT_SIZE bytes at the bottom of the stack for arg slots.
+     * Reserves FRAME_SIZE_SAVE_EVERYTHING + ARG_SLOT_SIZE bytes on the stack.
+     * This macro sets up $gp; entrypoints using it should start with ENTRY_NO_GP.
+     */
+.macro SETUP_SAVE_EVERYTHING_FRAME
+    addiu  $sp, $sp, -(FRAME_SIZE_SAVE_EVERYTHING)
+    .cfi_adjust_cfa_offset (FRAME_SIZE_SAVE_EVERYTHING)
+    SETUP_SAVE_EVERYTHING_FRAME_DECREMENTED_SP
+.endm
+
 .macro RESTORE_SAVE_EVERYTHING_FRAME
     addiu  $sp, $sp, ARG_SLOT_SIZE                # remove argument slots on the stack
     .cfi_adjust_cfa_offset -ARG_SLOT_SIZE
@@ -708,8 +722,10 @@
      * Call installed by a signal handler to create and deliver a NullPointerException.
      */
     .extern artThrowNullPointerExceptionFromSignal
-ENTRY art_quick_throw_null_pointer_exception_from_signal
-    SETUP_SAVE_ALL_CALLEE_SAVES_FRAME
+ENTRY_NO_GP_CUSTOM_CFA art_quick_throw_null_pointer_exception_from_signal, FRAME_SIZE_SAVE_EVERYTHING
+    SETUP_SAVE_EVERYTHING_FRAME_DECREMENTED_SP
+    # Retrieve the fault address from the padding where the signal handler stores it.
+    lw   $a0, (ARG_SLOT_SIZE + __SIZEOF_POINTER__)($sp)
     la   $t9, artThrowNullPointerExceptionFromSignal
     jalr $zero, $t9                 # artThrowNullPointerExceptionFromSignal(uintptr_t, Thread*)
     move $a1, rSELF                 # pass Thread::Current
@@ -761,17 +777,6 @@
 END art_quick_throw_stack_overflow
 
     /*
-     * Called by managed code to create and deliver a NoSuchMethodError.
-     */
-    .extern artThrowNoSuchMethodFromCode
-ENTRY art_quick_throw_no_such_method
-    SETUP_SAVE_ALL_CALLEE_SAVES_FRAME
-    la   $t9, artThrowNoSuchMethodFromCode
-    jalr $zero, $t9                 # artThrowNoSuchMethodFromCode(method_idx, Thread*)
-    move $a1, rSELF                 # pass Thread::Current
-END art_quick_throw_no_such_method
-
-    /*
      * All generated callsites for interface invokes and invocation slow paths will load arguments
      * as usual - except instead of loading arg0/$a0 with the target Method*, arg0/$a0 will contain
      * the method_idx.  This wrapper will save arg1-arg3, and call the appropriate C helper.
diff --git a/runtime/arch/mips64/asm_support_mips64.S b/runtime/arch/mips64/asm_support_mips64.S
index 786e860..6c58fcf 100644
--- a/runtime/arch/mips64/asm_support_mips64.S
+++ b/runtime/arch/mips64/asm_support_mips64.S
@@ -45,8 +45,8 @@
 .L\name\()_gp_set:
 .endm
 
-     // Declare a function called name, doesn't set up $gp.
-.macro ENTRY_NO_GP name
+    // Declare a function called name, doesn't set up $gp.
+.macro ENTRY_NO_GP_CUSTOM_CFA name, cfa_offset
     .type \name, %function
     .global \name
     // Cache alignment for function entry.
@@ -54,7 +54,12 @@
 \name:
     .cfi_startproc
      // Ensure we get a sane starting CFA.
-    .cfi_def_cfa $sp,0
+    .cfi_def_cfa $sp, \cfa_offset
+.endm
+
+    // Declare a function called name, doesn't set up $gp.
+.macro ENTRY_NO_GP name
+    ENTRY_NO_GP_CUSTOM_CFA \name, 0
 .endm
 
 .macro END name
diff --git a/runtime/arch/mips64/fault_handler_mips64.cc b/runtime/arch/mips64/fault_handler_mips64.cc
index 0bbb6e1..e52dc73 100644
--- a/runtime/arch/mips64/fault_handler_mips64.cc
+++ b/runtime/arch/mips64/fault_handler_mips64.cc
@@ -14,7 +14,7 @@
  * limitations under the License.
  */
 
-
+#include "arch/mips64/quick_method_frame_info_mips64.h"
 #include "fault_handler.h"
 #include <sys/ucontext.h>
 #include "art_method-inl.h"
@@ -83,12 +83,15 @@
   struct ucontext *uc = reinterpret_cast<struct ucontext*>(context);
   struct sigcontext *sc = reinterpret_cast<struct sigcontext*>(&uc->uc_mcontext);
 
+  // Decrement $sp by the frame size of the kSaveEverything method and store
+  // the fault address in the padding right after the ArtMethod*.
+  sc->sc_regs[mips64::SP] -= mips64::Mips64CalleeSaveFrameSize(Runtime::kSaveEverything);
+  uintptr_t* padding = reinterpret_cast<uintptr_t*>(sc->sc_regs[mips64::SP]) + /* ArtMethod* */ 1;
+  *padding = reinterpret_cast<uintptr_t>(info->si_addr);
+
   sc->sc_regs[mips64::RA] = sc->sc_pc + 4;      // RA needs to point to gc map location
   sc->sc_pc = reinterpret_cast<uintptr_t>(art_quick_throw_null_pointer_exception_from_signal);
   sc->sc_regs[mips64::T9] = sc->sc_pc;          // make sure T9 points to the function
-  // Pass the faulting address as the first argument of
-  // art_quick_throw_null_pointer_exception_from_signal.
-  sc->sc_regs[mips64::A0] = reinterpret_cast<uintptr_t>(info->si_addr);
   VLOG(signals) << "Generating null pointer exception";
   return true;
 }
diff --git a/runtime/arch/mips64/quick_entrypoints_mips64.S b/runtime/arch/mips64/quick_entrypoints_mips64.S
index 0bf2a35..c16e855 100644
--- a/runtime/arch/mips64/quick_entrypoints_mips64.S
+++ b/runtime/arch/mips64/quick_entrypoints_mips64.S
@@ -316,14 +316,12 @@
     /*
      * Macro that sets up the callee save frame to conform with
      * Runtime::CreateCalleeSaveMethod(kSaveEverything).
+     * when the $sp has already been decremented by FRAME_SIZE_SAVE_EVERYTHING.
      * callee-save: $at + $v0-$v1 + $a0-$a7 + $t0-$t3 + $s0-$s7 + $t8-$t9 + $gp + $s8 + $ra + $s8,
      *              $f0-$f31; 28(GPR)+ 32(FPR) + 1x8 bytes padding + method*
      * This macro sets up $gp; entrypoints using it should start with ENTRY_NO_GP.
      */
-.macro SETUP_SAVE_EVERYTHING_FRAME
-    daddiu $sp, $sp, -496
-    .cfi_adjust_cfa_offset 496
-
+.macro SETUP_SAVE_EVERYTHING_FRAME_DECREMENTED_SP
      // Ugly compile-time check, but we only have the preprocessor.
 #if (FRAME_SIZE_SAVE_EVERYTHING != 496)
 #error "FRAME_SIZE_SAVE_EVERYTHING(MIPS64) size not as expected."
@@ -436,6 +434,19 @@
     sd      $sp, THREAD_TOP_QUICK_FRAME_OFFSET(rSELF)
 .endm
 
+    /*
+     * Macro that sets up the callee save frame to conform with
+     * Runtime::CreateCalleeSaveMethod(kSaveEverything).
+     * callee-save: $at + $v0-$v1 + $a0-$a7 + $t0-$t3 + $s0-$s7 + $t8-$t9 + $gp + $s8 + $ra + $s8,
+     *              $f0-$f31; 28(GPR)+ 32(FPR) + 1x8 bytes padding + method*
+     * This macro sets up $gp; entrypoints using it should start with ENTRY_NO_GP.
+     */
+.macro SETUP_SAVE_EVERYTHING_FRAME
+    daddiu $sp, $sp, -(FRAME_SIZE_SAVE_EVERYTHING)
+    .cfi_adjust_cfa_offset (FRAME_SIZE_SAVE_EVERYTHING)
+    SETUP_SAVE_EVERYTHING_FRAME_DECREMENTED_SP
+.endm
+
 .macro RESTORE_SAVE_EVERYTHING_FRAME
     // Restore FP registers.
     l.d    $f31, 264($sp)
@@ -818,8 +829,10 @@
      * Call installed by a signal handler to create and deliver a NullPointerException
      */
     .extern artThrowNullPointerExceptionFromSignal
-ENTRY art_quick_throw_null_pointer_exception_from_signal
-    SETUP_SAVE_ALL_CALLEE_SAVES_FRAME
+ENTRY_NO_GP_CUSTOM_CFA art_quick_throw_null_pointer_exception_from_signal, FRAME_SIZE_SAVE_EVERYTHING
+    SETUP_SAVE_EVERYTHING_FRAME_DECREMENTED_SP
+    # Retrieve the fault address from the padding where the signal handler stores it.
+    ld   $a0, (__SIZEOF_POINTER__)($sp)
     dla  $t9, artThrowNullPointerExceptionFromSignal
     jalr $zero, $t9                 # artThrowNullPointerExceptionFromSignal(uinptr_t, Thread*)
     move $a1, rSELF                 # pass Thread::Current
@@ -874,17 +887,6 @@
 END art_quick_throw_stack_overflow
 
     /*
-     * Called by managed code to create and deliver a NoSuchMethodError.
-     */
-    .extern artThrowNoSuchMethodFromCode
-ENTRY art_quick_throw_no_such_method
-    SETUP_SAVE_ALL_CALLEE_SAVES_FRAME
-    dla  $t9, artThrowNoSuchMethodFromCode
-    jalr $zero, $t9                 # artThrowNoSuchMethodFromCode(method_idx, Thread*)
-    move $a1, rSELF                 # pass Thread::Current
-END art_quick_throw_no_such_method
-
-    /*
      * All generated callsites for interface invokes and invocation slow paths will load arguments
      * as usual - except instead of loading arg0/$a0 with the target Method*, arg0/$a0 will contain
      * the method_idx.  This wrapper will save arg1-arg3, load the caller's Method*, align the
@@ -1487,6 +1489,7 @@
     ld     $a1, FRAME_SIZE_SAVE_REFS_ONLY($sp)  # pass referrer's Method*
     jal    artGet32StaticFromCode        # (uint32_t field_idx, const Method* referrer, Thread*)
     move   $a2, rSELF                    # pass Thread::Current
+    sll    $v0, $v0, 0                   # sign-extend result
     RETURN_IF_NO_EXCEPTION
 END art_quick_get32_static
 
@@ -1571,6 +1574,7 @@
     ld     $a2, FRAME_SIZE_SAVE_REFS_ONLY($sp)  # pass referrer's Method*
     jal    artGet32InstanceFromCode      # (field_idx, Object*, referrer, Thread*)
     move   $a3, rSELF                    # pass Thread::Current
+    sll    $v0, $v0, 0                   # sign-extend result
     RETURN_IF_NO_EXCEPTION
 END art_quick_get32_instance
 
diff --git a/runtime/arch/x86/asm_support_x86.S b/runtime/arch/x86/asm_support_x86.S
index 3e47209..14b01c5 100644
--- a/runtime/arch/x86/asm_support_x86.S
+++ b/runtime/arch/x86/asm_support_x86.S
@@ -114,7 +114,7 @@
     .balign 16
 END_MACRO
 
-MACRO1(DEFINE_FUNCTION, c_name)
+MACRO2(DEFINE_FUNCTION_CUSTOM_CFA, c_name, cfa_offset)
     FUNCTION_TYPE(SYMBOL(\c_name))
     ASM_HIDDEN CALLVAR(c_name)
     .globl CALLVAR(c_name)
@@ -122,7 +122,11 @@
 CALLVAR(c_name):
     CFI_STARTPROC
     // Ensure we get a sane starting CFA.
-    CFI_DEF_CFA(esp, 4)
+    CFI_DEF_CFA(esp, RAW_VAR(cfa_offset))
+END_MACRO
+
+MACRO1(DEFINE_FUNCTION, c_name)
+    DEFINE_FUNCTION_CUSTOM_CFA RAW_VAR(c_name), __SIZEOF_POINTER__
 END_MACRO
 
 MACRO1(END_FUNCTION, c_name)
diff --git a/runtime/arch/x86/fault_handler_x86.cc b/runtime/arch/x86/fault_handler_x86.cc
index c7af249..a4d6bb4 100644
--- a/runtime/arch/x86/fault_handler_x86.cc
+++ b/runtime/arch/x86/fault_handler_x86.cc
@@ -325,21 +325,15 @@
   // next instruction (this instruction + instruction size).  The return address
   // is on the stack at the top address of the current frame.
 
-  // Push the return address onto the stack.
+  // Push the return address and fault address onto the stack.
   uintptr_t retaddr = reinterpret_cast<uintptr_t>(pc + instr_size);
-  uintptr_t* next_sp = reinterpret_cast<uintptr_t*>(sp - sizeof(uintptr_t));
-  *next_sp = retaddr;
+  uintptr_t* next_sp = reinterpret_cast<uintptr_t*>(sp - 2 * sizeof(uintptr_t));
+  next_sp[1] = retaddr;
+  next_sp[0] = reinterpret_cast<uintptr_t>(sig->si_addr);
   uc->CTX_ESP = reinterpret_cast<uintptr_t>(next_sp);
 
   uc->CTX_EIP = reinterpret_cast<uintptr_t>(
       art_quick_throw_null_pointer_exception_from_signal);
-  // Pass the faulting address as the first argument of
-  // art_quick_throw_null_pointer_exception_from_signal.
-#if defined(__x86_64__)
-  uc->CTX_RDI = reinterpret_cast<uintptr_t>(sig->si_addr);
-#else
-  uc->CTX_EAX = reinterpret_cast<uintptr_t>(sig->si_addr);
-#endif
   VLOG(signals) << "Generating null pointer exception";
   return true;
 }
diff --git a/runtime/arch/x86/quick_entrypoints_x86.S b/runtime/arch/x86/quick_entrypoints_x86.S
index 646a80c..f3793e1 100644
--- a/runtime/arch/x86/quick_entrypoints_x86.S
+++ b/runtime/arch/x86/quick_entrypoints_x86.S
@@ -224,10 +224,11 @@
     /*
      * Macro that sets up the callee save frame to conform with
      * Runtime::CreateCalleeSaveMethod(kSaveEverything)
+     * when EDI is already saved.
      */
-MACRO2(SETUP_SAVE_EVERYTHING_FRAME, got_reg, temp_reg)
-    // Save core registers.
-    PUSH edi
+MACRO2(SETUP_SAVE_EVERYTHING_FRAME_EDI_SAVED, got_reg, temp_reg)
+    // Save core registers from highest to lowest to agree with core spills bitmap.
+    // EDI, or at least a placeholder for it, is already on the stack.
     PUSH esi
     PUSH ebp
     PUSH ebx
@@ -264,6 +265,15 @@
 #endif
 END_MACRO
 
+    /*
+     * Macro that sets up the callee save frame to conform with
+     * Runtime::CreateCalleeSaveMethod(kSaveEverything)
+     */
+MACRO2(SETUP_SAVE_EVERYTHING_FRAME, got_reg, temp_reg)
+    PUSH edi
+    SETUP_SAVE_EVERYTHING_FRAME_EDI_SAVED RAW_VAR(got_reg), RAW_VAR(temp_reg)
+END_MACRO
+
 MACRO0(RESTORE_SAVE_EVERYTHING_FRAME)
     // Restore FPRs. Method and padding is still on the stack.
     movsd 16(%esp), %xmm0
@@ -320,7 +330,6 @@
 MACRO2(ONE_ARG_RUNTIME_EXCEPTION, c_name, cxx_name)
     DEFINE_FUNCTION VAR(c_name)
     SETUP_SAVE_ALL_CALLEE_SAVES_FRAME ebx, ebx // save all registers as basis for long jump context
-    mov %esp, %ecx
     // Outgoing argument set up
     subl MACRO_LITERAL(8), %esp                // alignment padding
     CFI_ADJUST_CFA_OFFSET(8)
@@ -354,7 +363,23 @@
     /*
      * Call installed by a signal handler to create and deliver a NullPointerException.
      */
-ONE_ARG_RUNTIME_EXCEPTION art_quick_throw_null_pointer_exception_from_signal, artThrowNullPointerExceptionFromSignal
+DEFINE_FUNCTION_CUSTOM_CFA art_quick_throw_null_pointer_exception_from_signal, 2 * __SIZEOF_POINTER__
+    // Fault address and return address were saved by the fault handler.
+    // Save all registers as basis for long jump context; EDI will replace fault address later.
+    SETUP_SAVE_EVERYTHING_FRAME_EDI_SAVED ebx, ebx
+    // Retrieve fault address and save EDI.
+    movl (FRAME_SIZE_SAVE_EVERYTHING - 2 * __SIZEOF_POINTER__)(%esp), %eax
+    movl %edi, (FRAME_SIZE_SAVE_EVERYTHING - 2 * __SIZEOF_POINTER__)(%esp)
+    CFI_REL_OFFSET(%edi, (FRAME_SIZE_SAVE_EVERYTHING - 2 * __SIZEOF_POINTER__))
+    // Outgoing argument set up
+    subl MACRO_LITERAL(8), %esp                           // alignment padding
+    CFI_ADJUST_CFA_OFFSET(8)
+    pushl %fs:THREAD_SELF_OFFSET                          // pass Thread::Current()
+    CFI_ADJUST_CFA_OFFSET(4)
+    PUSH eax                                              // pass arg1
+    call SYMBOL(artThrowNullPointerExceptionFromSignal)   // (addr, self)
+    UNREACHABLE
+END_FUNCTION art_quick_throw_null_pointer_exception
 
     /*
      * Called by managed code to create and deliver an ArithmeticException.
@@ -373,11 +398,6 @@
 ONE_ARG_RUNTIME_EXCEPTION art_quick_deliver_exception, artDeliverExceptionFromCode
 
     /*
-     * Called by managed code to create and deliver a NoSuchMethodError.
-     */
-ONE_ARG_RUNTIME_EXCEPTION art_quick_throw_no_such_method, artThrowNoSuchMethodFromCode
-
-    /*
      * Called by managed code to create and deliver an ArrayIndexOutOfBoundsException. Arg1 holds
      * index, arg2 holds limit.
      */
diff --git a/runtime/arch/x86_64/asm_support_x86_64.S b/runtime/arch/x86_64/asm_support_x86_64.S
index 0728f99..af4a6c4 100644
--- a/runtime/arch/x86_64/asm_support_x86_64.S
+++ b/runtime/arch/x86_64/asm_support_x86_64.S
@@ -110,7 +110,7 @@
 
 // TODO: we might need to use SYMBOL() here to add the underscore prefix
 // for mac builds.
-MACRO1(DEFINE_FUNCTION, c_name)
+MACRO2(DEFINE_FUNCTION_CUSTOM_CFA, c_name, cfa_offset)
     FUNCTION_TYPE(SYMBOL(\c_name))
     ASM_HIDDEN CALLVAR(c_name)
     .globl CALLVAR(c_name)
@@ -118,7 +118,11 @@
 CALLVAR(c_name):
     CFI_STARTPROC
     // Ensure we get a sane starting CFA.
-    CFI_DEF_CFA(rsp, 8)
+    CFI_DEF_CFA(rsp, RAW_VAR(cfa_offset))
+END_MACRO
+
+MACRO1(DEFINE_FUNCTION, c_name)
+    DEFINE_FUNCTION_CUSTOM_CFA RAW_VAR(c_name), __SIZEOF_POINTER__
 END_MACRO
 
 MACRO1(END_FUNCTION, c_name)
diff --git a/runtime/arch/x86_64/quick_entrypoints_x86_64.S b/runtime/arch/x86_64/quick_entrypoints_x86_64.S
index 5ea58af..bfba543 100644
--- a/runtime/arch/x86_64/quick_entrypoints_x86_64.S
+++ b/runtime/arch/x86_64/quick_entrypoints_x86_64.S
@@ -263,14 +263,15 @@
     /*
      * Macro that sets up the callee save frame to conform with
      * Runtime::CreateCalleeSaveMethod(kSaveEverything)
+     * when R15 is already saved.
      */
-MACRO0(SETUP_SAVE_EVERYTHING_FRAME)
+MACRO0(SETUP_SAVE_EVERYTHING_FRAME_R15_SAVED)
 #if defined(__APPLE__)
     int3
     int3
 #else
     // Save core registers from highest to lowest to agree with core spills bitmap.
-    PUSH r15
+    // R15, or at least a placeholder for it, is already on the stack.
     PUSH r14
     PUSH r13
     PUSH r12
@@ -322,6 +323,15 @@
 #endif  // __APPLE__
 END_MACRO
 
+    /*
+     * Macro that sets up the callee save frame to conform with
+     * Runtime::CreateCalleeSaveMethod(kSaveEverything)
+     */
+MACRO0(SETUP_SAVE_EVERYTHING_FRAME)
+    PUSH r15
+    SETUP_SAVE_EVERYTHING_FRAME_R15_SAVED
+END_MACRO
+
 MACRO0(RESTORE_SAVE_EVERYTHING_FRAME)
     // Restore FPRs. Method and padding is still on the stack.
     movq 16(%rsp), %xmm0
@@ -413,7 +423,19 @@
     /*
      * Call installed by a signal handler to create and deliver a NullPointerException.
      */
-ONE_ARG_RUNTIME_EXCEPTION art_quick_throw_null_pointer_exception_from_signal, artThrowNullPointerExceptionFromSignal
+DEFINE_FUNCTION_CUSTOM_CFA art_quick_throw_null_pointer_exception_from_signal, 2 * __SIZEOF_POINTER__
+    // Fault address and return address were saved by the fault handler.
+    // Save all registers as basis for long jump context; R15 will replace fault address later.
+    SETUP_SAVE_EVERYTHING_FRAME_R15_SAVED
+    // Retrieve fault address and save R15.
+    movq (FRAME_SIZE_SAVE_EVERYTHING - 2 * __SIZEOF_POINTER__)(%rsp), %rdi
+    movq %r15, (FRAME_SIZE_SAVE_EVERYTHING - 2 * __SIZEOF_POINTER__)(%rsp)
+    CFI_REL_OFFSET(%r15, (FRAME_SIZE_SAVE_EVERYTHING - 2 * __SIZEOF_POINTER__))
+    // Outgoing argument set up; RDI already contains the fault address.
+    movq %gs:THREAD_SELF_OFFSET, %rsi  // pass Thread::Current()
+    call SYMBOL(artThrowNullPointerExceptionFromSignal)  // (addr, self)
+    UNREACHABLE
+END_FUNCTION art_quick_throw_null_pointer_exception_from_signal
 
     /*
      * Called by managed code to create and deliver an ArithmeticException.
@@ -432,11 +454,6 @@
 ONE_ARG_RUNTIME_EXCEPTION art_quick_deliver_exception, artDeliverExceptionFromCode
 
     /*
-     * Called by managed code to create and deliver a NoSuchMethodError.
-     */
-ONE_ARG_RUNTIME_EXCEPTION art_quick_throw_no_such_method, artThrowNoSuchMethodFromCode
-
-    /*
      * Called by managed code to create and deliver an ArrayIndexOutOfBoundsException. Arg1 holds
      * index, arg2 holds limit.
      */
diff --git a/runtime/art_method-inl.h b/runtime/art_method-inl.h
index 1659f33..9b4b38a 100644
--- a/runtime/art_method-inl.h
+++ b/runtime/art_method-inl.h
@@ -24,6 +24,7 @@
 #include "class_linker-inl.h"
 #include "common_throws.h"
 #include "dex_file.h"
+#include "dex_file_annotations.h"
 #include "dex_file-inl.h"
 #include "gc_root-inl.h"
 #include "jit/profiling_info.h"
@@ -347,7 +348,7 @@
   if (dex_pc == DexFile::kDexNoIndex) {
     return IsNative() ? -2 : -1;
   }
-  return GetDexFile()->GetLineNumFromPC(this, dex_pc);
+  return annotations::GetLineNumFromPC(GetDexFile(), this, dex_pc);
 }
 
 inline const DexFile::ProtoId& ArtMethod::GetPrototype() {
diff --git a/runtime/art_method.cc b/runtime/art_method.cc
index 1392399..fd6c37a 100644
--- a/runtime/art_method.cc
+++ b/runtime/art_method.cc
@@ -25,6 +25,7 @@
 #include "class_linker-inl.h"
 #include "debugger.h"
 #include "dex_file-inl.h"
+#include "dex_file_annotations.h"
 #include "dex_instruction.h"
 #include "entrypoints/runtime_asm_entrypoints.h"
 #include "gc/accounting/card_table-inl.h"
@@ -107,7 +108,7 @@
 }
 
 bool ArtMethod::HasSameNameAndSignature(ArtMethod* other) {
-  ScopedAssertNoThreadSuspension ants(Thread::Current(), "HasSameNameAndSignature");
+  ScopedAssertNoThreadSuspension ants("HasSameNameAndSignature");
   const DexFile* dex_file = GetDexFile();
   const DexFile::MethodId& mid = dex_file->GetMethodId(GetDexMethodIndex());
   if (GetDexCache() == other->GetDexCache()) {
@@ -349,8 +350,6 @@
   ScopedObjectAccess soa(self);
   StackHandleScope<1> shs(self);
 
-  const DexFile& dex_file = GetDeclaringClass()->GetDexFile();
-
   mirror::Class* annotation = soa.Decode<mirror::Class*>(klass);
   DCHECK(annotation->IsAnnotation());
   Handle<mirror::Class> annotation_handle(shs.NewHandle(annotation));
@@ -358,7 +357,7 @@
   // Note: Resolves any method annotations' classes as a side-effect.
   // -- This seems allowed by the spec since it says we can preload any classes
   //    referenced by another classes's constant pool table.
-  return dex_file.IsMethodAnnotationPresent(this, annotation_handle, visibility);
+  return annotations::IsMethodAnnotationPresent(this, annotation_handle, visibility);
 }
 
 bool ArtMethod::EqualParameters(Handle<mirror::ObjectArray<mirror::Class>> params) {
diff --git a/runtime/art_method.h b/runtime/art_method.h
index 8051a1f..b1baccd 100644
--- a/runtime/art_method.h
+++ b/runtime/art_method.h
@@ -33,6 +33,7 @@
 
 namespace art {
 
+template<class T> class Handle;
 union JValue;
 class OatQuickMethodHeader;
 class ProfilingInfo;
diff --git a/runtime/asm_support.h b/runtime/asm_support.h
index f4addf7..b8f7272 100644
--- a/runtime/asm_support.h
+++ b/runtime/asm_support.h
@@ -89,20 +89,20 @@
 ADD_TEST_EQ(THREAD_SELF_OFFSET,
             art::Thread::SelfOffset<POINTER_SIZE>().Int32Value())
 
-// Offset of field Thread::tlsPtr_.thread_local_objects.
-#define THREAD_LOCAL_OBJECTS_OFFSET (THREAD_CARD_TABLE_OFFSET + 199 * __SIZEOF_POINTER__)
-ADD_TEST_EQ(THREAD_LOCAL_OBJECTS_OFFSET,
-            art::Thread::ThreadLocalObjectsOffset<POINTER_SIZE>().Int32Value())
 // Offset of field Thread::tlsPtr_.thread_local_pos.
-#define THREAD_LOCAL_POS_OFFSET (THREAD_LOCAL_OBJECTS_OFFSET + __SIZEOF_SIZE_T__)
+#define THREAD_LOCAL_POS_OFFSET (THREAD_CARD_TABLE_OFFSET + 198 * __SIZEOF_POINTER__)
 ADD_TEST_EQ(THREAD_LOCAL_POS_OFFSET,
             art::Thread::ThreadLocalPosOffset<POINTER_SIZE>().Int32Value())
 // Offset of field Thread::tlsPtr_.thread_local_end.
 #define THREAD_LOCAL_END_OFFSET (THREAD_LOCAL_POS_OFFSET + __SIZEOF_POINTER__)
 ADD_TEST_EQ(THREAD_LOCAL_END_OFFSET,
             art::Thread::ThreadLocalEndOffset<POINTER_SIZE>().Int32Value())
+// Offset of field Thread::tlsPtr_.thread_local_objects.
+#define THREAD_LOCAL_OBJECTS_OFFSET (THREAD_LOCAL_END_OFFSET + __SIZEOF_POINTER__)
+ADD_TEST_EQ(THREAD_LOCAL_OBJECTS_OFFSET,
+            art::Thread::ThreadLocalObjectsOffset<POINTER_SIZE>().Int32Value())
 // Offset of field Thread::tlsPtr_.mterp_current_ibase.
-#define THREAD_CURRENT_IBASE_OFFSET (THREAD_LOCAL_END_OFFSET + __SIZEOF_POINTER__)
+#define THREAD_CURRENT_IBASE_OFFSET (THREAD_LOCAL_OBJECTS_OFFSET + __SIZEOF_SIZE_T__)
 ADD_TEST_EQ(THREAD_CURRENT_IBASE_OFFSET,
             art::Thread::MterpCurrentIBaseOffset<POINTER_SIZE>().Int32Value())
 // Offset of field Thread::tlsPtr_.mterp_default_ibase.
diff --git a/runtime/base/allocator.h b/runtime/base/allocator.h
index e48eca9..8d1c982 100644
--- a/runtime/base/allocator.h
+++ b/runtime/base/allocator.h
@@ -116,7 +116,8 @@
 
   // Used internally by STL data structures.
   template <class U>
-  TrackingAllocatorImpl(const TrackingAllocatorImpl<U, kTag>& alloc ATTRIBUTE_UNUSED) noexcept {}
+  TrackingAllocatorImpl( // NOLINT, implicit
+      const TrackingAllocatorImpl<U, kTag>& alloc ATTRIBUTE_UNUSED) noexcept {}
 
   // Used internally by STL data structures.
   TrackingAllocatorImpl() noexcept {
diff --git a/runtime/base/arena_allocator.h b/runtime/base/arena_allocator.h
index 3fad96b..31dbb36 100644
--- a/runtime/base/arena_allocator.h
+++ b/runtime/base/arena_allocator.h
@@ -258,9 +258,9 @@
 
 class ArenaPool {
  public:
-  ArenaPool(bool use_malloc = true,
-            bool low_4gb = false,
-            const char* name = "LinearAlloc");
+  explicit ArenaPool(bool use_malloc = true,
+                     bool low_4gb = false,
+                     const char* name = "LinearAlloc");
   ~ArenaPool();
   Arena* AllocArena(size_t size) REQUIRES(!lock_);
   void FreeArenaChain(Arena* first) REQUIRES(!lock_);
diff --git a/runtime/base/arena_containers.h b/runtime/base/arena_containers.h
index 68cacd5..2c8aa28 100644
--- a/runtime/base/arena_containers.h
+++ b/runtime/base/arena_containers.h
@@ -132,7 +132,7 @@
         arena_allocator_(arena_allocator) {
   }
   template <typename U>
-  ArenaAllocatorAdapter(const ArenaAllocatorAdapter<U>& other)
+  ArenaAllocatorAdapter(const ArenaAllocatorAdapter<U>& other)  // NOLINT, implicit
       : ArenaAllocatorAdapterKind(other),
         arena_allocator_(other.arena_allocator_) {
   }
@@ -168,7 +168,7 @@
         arena_allocator_(arena_allocator) {
   }
   template <typename U>
-  ArenaAllocatorAdapter(const ArenaAllocatorAdapter<U>& other)
+  ArenaAllocatorAdapter(const ArenaAllocatorAdapter<U>& other)  // NOLINT, implicit
       : ArenaAllocatorAdapterKind(other),
         arena_allocator_(other.arena_allocator_) {
   }
diff --git a/compiler/utils/array_ref.h b/runtime/base/array_ref.h
similarity index 97%
rename from compiler/utils/array_ref.h
rename to runtime/base/array_ref.h
index 8dc9ab4..00b9bad 100644
--- a/compiler/utils/array_ref.h
+++ b/runtime/base/array_ref.h
@@ -14,8 +14,8 @@
  * limitations under the License.
  */
 
-#ifndef ART_COMPILER_UTILS_ARRAY_REF_H_
-#define ART_COMPILER_UTILS_ARRAY_REF_H_
+#ifndef ART_RUNTIME_BASE_ARRAY_REF_H_
+#define ART_RUNTIME_BASE_ARRAY_REF_H_
 
 #include <type_traits>
 #include <vector>
@@ -197,4 +197,4 @@
 }  // namespace art
 
 
-#endif  // ART_COMPILER_UTILS_ARRAY_REF_H_
+#endif  // ART_RUNTIME_BASE_ARRAY_REF_H_
diff --git a/runtime/base/logging.cc b/runtime/base/logging.cc
index 529c391..e00e62d 100644
--- a/runtime/base/logging.cc
+++ b/runtime/base/logging.cc
@@ -187,7 +187,7 @@
 LogMessage::LogMessage(const char* file, unsigned int line, LogSeverity severity, int error)
   : data_(new LogMessageData(file, line, severity, error)) {
   if (PrintDirectly(severity)) {
-    static constexpr char kLogCharacters[] = { 'N', 'V', 'D', 'I', 'W', 'E', 'F', 'F' };
+    static constexpr char kLogCharacters[] = { 'V', 'D', 'I', 'W', 'E', 'F', 'F' };
     static_assert(arraysize(kLogCharacters) == static_cast<size_t>(INTERNAL_FATAL) + 1,
                   "Wrong character array size");
     stream() << ProgramInvocationShortName() << " " << kLogCharacters[static_cast<size_t>(severity)]
@@ -198,7 +198,7 @@
   if (PrintDirectly(data_->GetSeverity())) {
     // Add newline at the end to match the not printing directly behavior.
     std::cerr << '\n';
-  } else if (data_->GetSeverity() != LogSeverity::NONE) {
+  } else {
     if (data_->GetSeverity() < gMinimumLogSeverity) {
       return;  // No need to format something we're not going to output.
     }
@@ -242,7 +242,6 @@
 
 #ifdef ART_TARGET_ANDROID
 static const android_LogPriority kLogSeverityToAndroidLogPriority[] = {
-  ANDROID_LOG_VERBOSE,  // NONE, use verbose as stand-in, will never be printed.
   ANDROID_LOG_VERBOSE, ANDROID_LOG_DEBUG, ANDROID_LOG_INFO, ANDROID_LOG_WARN,
   ANDROID_LOG_ERROR, ANDROID_LOG_FATAL, ANDROID_LOG_FATAL
 };
@@ -252,10 +251,6 @@
 
 void LogMessage::LogLine(const char* file, unsigned int line, LogSeverity log_severity,
                          const char* message) {
-  if (log_severity == LogSeverity::NONE) {
-    return;
-  }
-
 #ifdef ART_TARGET_ANDROID
   const char* tag = ProgramInvocationShortName();
   int priority = kLogSeverityToAndroidLogPriority[static_cast<size_t>(log_severity)];
@@ -265,7 +260,7 @@
     LOG_PRI(priority, tag, "%s", message);
   }
 #else
-  static const char* log_characters = "NVDIWEFF";
+  static const char* log_characters = "VDIWEFF";
   CHECK_EQ(strlen(log_characters), INTERNAL_FATAL + 1U);
   char severity = log_characters[log_severity];
   fprintf(stderr, "%s %c %5d %5d %s:%u] %s\n",
@@ -275,10 +270,6 @@
 
 void LogMessage::LogLineLowStack(const char* file, unsigned int line, LogSeverity log_severity,
                                  const char* message) {
-  if (log_severity == LogSeverity::NONE) {
-    return;
-  }
-
 #ifdef ART_TARGET_ANDROID
   // Use android_writeLog() to avoid stack-based buffers used by android_printLog().
   const char* tag = ProgramInvocationShortName();
@@ -300,7 +291,7 @@
     android_writeLog(priority, tag, message);
   }
 #else
-  static constexpr char kLogCharacters[] = { 'N', 'V', 'D', 'I', 'W', 'E', 'F', 'F' };
+  static constexpr char kLogCharacters[] = { 'V', 'D', 'I', 'W', 'E', 'F', 'F' };
   static_assert(arraysize(kLogCharacters) == static_cast<size_t>(INTERNAL_FATAL) + 1,
                 "Wrong character array size");
 
diff --git a/runtime/base/logging.h b/runtime/base/logging.h
index f43cb8b..185aa0e 100644
--- a/runtime/base/logging.h
+++ b/runtime/base/logging.h
@@ -24,7 +24,6 @@
 namespace art {
 
 enum LogSeverity {
-  NONE,            // Fake level, don't log at all.
   VERBOSE,
   DEBUG,
   INFO,
diff --git a/runtime/base/scoped_arena_containers.h b/runtime/base/scoped_arena_containers.h
index bd19d00..7964705 100644
--- a/runtime/base/scoped_arena_containers.h
+++ b/runtime/base/scoped_arena_containers.h
@@ -87,7 +87,7 @@
         arena_stack_(arena_allocator->arena_stack_) {
   }
   template <typename U>
-  ScopedArenaAllocatorAdapter(const ScopedArenaAllocatorAdapter<U>& other)
+  ScopedArenaAllocatorAdapter(const ScopedArenaAllocatorAdapter<U>& other)  // NOLINT, implicit
       : DebugStackReference(other),
         DebugStackIndirectTopRef(other),
         ArenaAllocatorAdapterKind(other),
@@ -130,7 +130,7 @@
         arena_stack_(arena_allocator->arena_stack_) {
   }
   template <typename U>
-  ScopedArenaAllocatorAdapter(const ScopedArenaAllocatorAdapter<U>& other)
+  ScopedArenaAllocatorAdapter(const ScopedArenaAllocatorAdapter<U>& other)  // NOLINT, implicit
       : DebugStackReference(other),
         DebugStackIndirectTopRef(other),
         ArenaAllocatorAdapterKind(other),
diff --git a/compiler/utils/transform_array_ref.h b/runtime/base/transform_array_ref.h
similarity index 96%
rename from compiler/utils/transform_array_ref.h
rename to runtime/base/transform_array_ref.h
index a6da34f..b432f86 100644
--- a/compiler/utils/transform_array_ref.h
+++ b/runtime/base/transform_array_ref.h
@@ -14,13 +14,13 @@
  * limitations under the License.
  */
 
-#ifndef ART_COMPILER_UTILS_TRANSFORM_ARRAY_REF_H_
-#define ART_COMPILER_UTILS_TRANSFORM_ARRAY_REF_H_
+#ifndef ART_RUNTIME_BASE_TRANSFORM_ARRAY_REF_H_
+#define ART_RUNTIME_BASE_TRANSFORM_ARRAY_REF_H_
 
 #include <type_traits>
 
-#include "utils/array_ref.h"
-#include "utils/transform_iterator.h"
+#include "base/array_ref.h"
+#include "base/transform_iterator.h"
 
 namespace art {
 
@@ -72,7 +72,7 @@
 
   template <typename OtherBT,
             typename = typename std::enable_if<std::is_same<BaseType, const OtherBT>::value>::type>
-  TransformArrayRef(const TransformArrayRef<OtherBT, Function>& other)
+  TransformArrayRef(const TransformArrayRef<OtherBT, Function>& other)  // NOLINT, implicit
       : TransformArrayRef(other.base(), other.GetFunction()) { }
 
   // Assignment operators.
@@ -193,4 +193,4 @@
 
 }  // namespace art
 
-#endif  // ART_COMPILER_UTILS_TRANSFORM_ARRAY_REF_H_
+#endif  // ART_RUNTIME_BASE_TRANSFORM_ARRAY_REF_H_
diff --git a/compiler/utils/transform_array_ref_test.cc b/runtime/base/transform_array_ref_test.cc
similarity index 99%
rename from compiler/utils/transform_array_ref_test.cc
rename to runtime/base/transform_array_ref_test.cc
index 8d71fd7..494dbb2 100644
--- a/compiler/utils/transform_array_ref_test.cc
+++ b/runtime/base/transform_array_ref_test.cc
@@ -19,7 +19,7 @@
 
 #include "gtest/gtest.h"
 
-#include "utils/transform_array_ref.h"
+#include "base/transform_array_ref.h"
 
 namespace art {
 
diff --git a/compiler/utils/transform_iterator.h b/runtime/base/transform_iterator.h
similarity index 96%
rename from compiler/utils/transform_iterator.h
rename to runtime/base/transform_iterator.h
index 3bc9046..f1a8a52 100644
--- a/compiler/utils/transform_iterator.h
+++ b/runtime/base/transform_iterator.h
@@ -14,8 +14,8 @@
  * limitations under the License.
  */
 
-#ifndef ART_COMPILER_UTILS_TRANSFORM_ITERATOR_H_
-#define ART_COMPILER_UTILS_TRANSFORM_ITERATOR_H_
+#ifndef ART_RUNTIME_BASE_TRANSFORM_ITERATOR_H_
+#define ART_RUNTIME_BASE_TRANSFORM_ITERATOR_H_
 
 #include <iterator>
 #include <type_traits>
@@ -62,7 +62,7 @@
       : data_(base, fn) { }
 
   template <typename OtherBI>
-  TransformIterator(const TransformIterator<OtherBI, Function>& other)
+  TransformIterator(const TransformIterator<OtherBI, Function>& other)  // NOLINT, implicit
       : data_(other.base(), other.GetFunction()) {
   }
 
@@ -175,4 +175,4 @@
 
 }  // namespace art
 
-#endif  // ART_COMPILER_UTILS_TRANSFORM_ITERATOR_H_
+#endif  // ART_RUNTIME_BASE_TRANSFORM_ITERATOR_H_
diff --git a/compiler/utils/transform_iterator_test.cc b/runtime/base/transform_iterator_test.cc
similarity index 99%
rename from compiler/utils/transform_iterator_test.cc
rename to runtime/base/transform_iterator_test.cc
index 57ff0a6..a85dda8 100644
--- a/compiler/utils/transform_iterator_test.cc
+++ b/runtime/base/transform_iterator_test.cc
@@ -22,7 +22,7 @@
 
 #include "gtest/gtest.h"
 
-#include "utils/transform_iterator.h"
+#include "base/transform_iterator.h"
 
 namespace art {
 
diff --git a/runtime/class_linker.cc b/runtime/class_linker.cc
index 726e897..6d93736 100644
--- a/runtime/class_linker.cc
+++ b/runtime/class_linker.cc
@@ -1533,7 +1533,7 @@
 bool ClassLinker::OpenImageDexFiles(gc::space::ImageSpace* space,
                                     std::vector<std::unique_ptr<const DexFile>>* out_dex_files,
                                     std::string* error_msg) {
-  ScopedAssertNoThreadSuspension nts(Thread::Current(), __FUNCTION__);
+  ScopedAssertNoThreadSuspension nts(__FUNCTION__);
   const ImageHeader& header = space->GetImageHeader();
   mirror::Object* dex_caches_object = header.GetImageRoot(ImageHeader::kDexCaches);
   DCHECK(dex_caches_object != nullptr);
@@ -1923,7 +1923,7 @@
   ReaderMutexLock mu(self, *Locks::classlinker_classes_lock_);
   // Not safe to have thread suspension when we are holding a lock.
   if (self != nullptr) {
-    ScopedAssertNoThreadSuspension nts(self, __FUNCTION__);
+    ScopedAssertNoThreadSuspension nts(__FUNCTION__);
     VisitClassesInternal(visitor);
   } else {
     VisitClassesInternal(visitor);
@@ -1965,9 +1965,8 @@
 void ClassLinker::VisitClassesWithoutClassesLock(ClassVisitor* visitor) {
   // TODO: it may be possible to avoid secondary storage if we iterate over dex caches. The problem
   // is avoiding duplicates.
-  Thread* const self = Thread::Current();
   if (!kMovingClasses) {
-    ScopedAssertNoThreadSuspension nts(self, __FUNCTION__);
+    ScopedAssertNoThreadSuspension nts(__FUNCTION__);
     GetClassesInToVector accumulator;
     VisitClasses(&accumulator);
     for (mirror::Class* klass : accumulator.classes_) {
@@ -1976,6 +1975,7 @@
       }
     }
   } else {
+    Thread* const self = Thread::Current();
     StackHandleScope<1> hs(self);
     auto classes = hs.NewHandle<mirror::ObjectArray<mirror::Class>>(nullptr);
     // We size the array assuming classes won't be added to the class table during the visit.
@@ -3047,7 +3047,7 @@
   {
     // Note: We cannot have thread suspension until the field and method arrays are setup or else
     // Class::VisitFieldRoots may miss some fields or methods.
-    ScopedAssertNoThreadSuspension nts(self, __FUNCTION__);
+    ScopedAssertNoThreadSuspension nts(__FUNCTION__);
     // Load static fields.
     // We allow duplicate definitions of the same field in a class_data_item
     // but ignore the repeated indexes here, b/21868015.
@@ -3113,7 +3113,7 @@
     // TODO These should really use the iterators.
     for (size_t i = 0; it.HasNextDirectMethod(); i++, it.Next()) {
       ArtMethod* method = klass->GetDirectMethodUnchecked(i, image_pointer_size_);
-      LoadMethod(self, dex_file, it, klass, method);
+      LoadMethod(dex_file, it, klass, method);
       LinkCode(method, oat_class, class_def_method_index);
       uint32_t it_method_index = it.GetMemberIndex();
       if (last_dex_method_index == it_method_index) {
@@ -3128,7 +3128,7 @@
     }
     for (size_t i = 0; it.HasNextVirtualMethod(); i++, it.Next()) {
       ArtMethod* method = klass->GetVirtualMethodUnchecked(i, image_pointer_size_);
-      LoadMethod(self, dex_file, it, klass, method);
+      LoadMethod(dex_file, it, klass, method);
       DCHECK_EQ(class_def_method_index, it.NumDirectMethods() + i);
       LinkCode(method, oat_class, class_def_method_index);
       class_def_method_index++;
@@ -3149,8 +3149,7 @@
   dst->SetAccessFlags(it.GetFieldAccessFlags());
 }
 
-void ClassLinker::LoadMethod(Thread* self,
-                             const DexFile& dex_file,
+void ClassLinker::LoadMethod(const DexFile& dex_file,
                              const ClassDataItemIterator& it,
                              Handle<mirror::Class> klass,
                              ArtMethod* dst) {
@@ -3158,7 +3157,7 @@
   const DexFile::MethodId& method_id = dex_file.GetMethodId(dex_method_idx);
   const char* method_name = dex_file.StringDataByIdx(method_id.name_idx_);
 
-  ScopedAssertNoThreadSuspension ants(self, "LoadMethod");
+  ScopedAssertNoThreadSuspension ants("LoadMethod");
   dst->SetDexMethodIndex(dex_method_idx);
   dst->SetDeclaringClass(klass.Get());
   dst->SetCodeItemOffset(it.GetMethodCodeItemOffset());
@@ -3692,7 +3691,7 @@
                                               mirror::ClassLoader* class_loader) {
   Thread* self = Thread::Current();
   WriterMutexLock mu(self, *Locks::classlinker_classes_lock_);
-  ScopedAssertNoThreadSuspension ants(self, "Moving image classes to class table");
+  ScopedAssertNoThreadSuspension ants("Moving image classes to class table");
 
   ClassTable* const class_table = InsertClassTableForClassLoader(class_loader);
 
@@ -3747,7 +3746,7 @@
 }
 
 mirror::Class* ClassLinker::LookupClassFromBootImage(const char* descriptor) {
-  ScopedAssertNoThreadSuspension ants(Thread::Current(), "Image class lookup");
+  ScopedAssertNoThreadSuspension ants("Image class lookup");
   std::vector<mirror::ObjectArray<mirror::DexCache>*> dex_caches_vector =
       GetImageDexCaches(Runtime::Current()->GetHeap()->GetBootImageSpaces());
   for (mirror::ObjectArray<mirror::DexCache>* dex_caches : dex_caches_vector) {
@@ -3848,7 +3847,9 @@
   return false;
 }
 
-void ClassLinker::VerifyClass(Thread* self, Handle<mirror::Class> klass, LogSeverity log_level) {
+void ClassLinker::VerifyClass(Thread* self,
+                              Handle<mirror::Class> klass,
+                              verifier::HardFailLogMode log_level) {
   {
     // TODO: assert that the monitor on the Class is held
     ObjectLock<mirror::Class> lock(self, klass);
@@ -4637,8 +4638,11 @@
       }
     }
 
-    EncodedStaticFieldValueIterator value_it(dex_file, &dex_cache, &class_loader,
-                                             this, *dex_class_def);
+    annotations::RuntimeEncodedStaticFieldValueIterator value_it(dex_file,
+                                                                 &dex_cache,
+                                                                 &class_loader,
+                                                                 this,
+                                                                 *dex_class_def);
     const uint8_t* class_data = dex_file.GetClassData(*dex_class_def);
     ClassDataItemIterator field_it(dex_file, class_data);
     if (value_it.HasNext()) {
@@ -6503,7 +6507,7 @@
 
   size_t new_ifcount;
   {
-    ScopedAssertNoThreadSuspension nts(self, "Copying mirror::Class*'s for FillIfTable");
+    ScopedAssertNoThreadSuspension nts("Copying mirror::Class*'s for FillIfTable");
     std::vector<mirror::Class*> to_add;
     for (size_t i = 0; i < num_interfaces; i++) {
       mirror::Class* interface = have_interfaces ? interfaces->Get(i) :
@@ -6533,39 +6537,90 @@
   return true;
 }
 
-// Finds the method with a name/signature that matches cmp in the given list of methods. The list of
-// methods must be unique.
+// Finds the method with a name/signature that matches cmp in the given lists of methods. The list
+// of methods must be unique.
+static ArtMethod* FindSameNameAndSignature(MethodNameAndSignatureComparator& cmp ATTRIBUTE_UNUSED) {
+  return nullptr;
+}
+
+template <typename ... Types>
 static ArtMethod* FindSameNameAndSignature(MethodNameAndSignatureComparator& cmp,
-                                           const ScopedArenaVector<ArtMethod*>& list)
+                                           const ScopedArenaVector<ArtMethod*>& list,
+                                           const Types& ... rest)
     REQUIRES_SHARED(Locks::mutator_lock_) {
   for (ArtMethod* method : list) {
     if (cmp.HasSameNameAndSignature(method)) {
       return method;
     }
   }
-  return nullptr;
+  return FindSameNameAndSignature(cmp, rest...);
 }
 
-static void SanityCheckVTable(Handle<mirror::Class> klass, PointerSize pointer_size)
+// Check that all vtable entries are present in this class's virtuals or are the same as a
+// superclasses vtable entry.
+static void CheckClassOwnsVTableEntries(Thread* self,
+                                        Handle<mirror::Class> klass,
+                                        PointerSize pointer_size)
     REQUIRES_SHARED(Locks::mutator_lock_) {
-  mirror::PointerArray* check_vtable = klass->GetVTableDuringLinking();
-  mirror::Class* superclass = (klass->HasSuperClass()) ? klass->GetSuperClass() : nullptr;
-  int32_t super_vtable_length = (superclass != nullptr) ? superclass->GetVTableLength() : 0;
+  StackHandleScope<2> hs(self);
+  Handle<mirror::PointerArray> check_vtable(hs.NewHandle(klass->GetVTableDuringLinking()));
+  mirror::Class* super_temp = (klass->HasSuperClass()) ? klass->GetSuperClass() : nullptr;
+  Handle<mirror::Class> superclass(hs.NewHandle(super_temp));
+  int32_t super_vtable_length = (superclass.Get() != nullptr) ? superclass->GetVTableLength() : 0;
   for (int32_t i = 0; i < check_vtable->GetLength(); ++i) {
     ArtMethod* m = check_vtable->GetElementPtrSize<ArtMethod*>(i, pointer_size);
     CHECK(m != nullptr);
 
+    CHECK_EQ(m->GetMethodIndexDuringLinking(), i)
+        << PrettyMethod(m) << " has an unexpected method index for its spot in the vtable for class"
+        << PrettyClass(klass.Get());
     ArraySlice<ArtMethod> virtuals = klass->GetVirtualMethodsSliceUnchecked(pointer_size);
     auto is_same_method = [m] (const ArtMethod& meth) {
       return &meth == m;
     };
     CHECK((super_vtable_length > i && superclass->GetVTableEntry(i, pointer_size) == m) ||
           std::find_if(virtuals.begin(), virtuals.end(), is_same_method) != virtuals.end())
-        << "While linking class '" << PrettyClass(klass.Get()) << "' unable to find owning class "
-        << "of '" << PrettyMethod(m) << "' (vtable index: " << i << ").";
+        << PrettyMethod(m) << " does not seem to be owned by current class "
+        << PrettyClass(klass.Get()) << " or any of its superclasses!";
   }
 }
 
+// Check to make sure the vtable does not have duplicates. Duplicates could cause problems when a
+// method is overridden in a subclass.
+static void CheckVTableHasNoDuplicates(Thread* self,
+                                       Handle<mirror::Class> klass,
+                                       PointerSize pointer_size)
+    REQUIRES_SHARED(Locks::mutator_lock_) {
+  StackHandleScope<1> hs(self);
+  Handle<mirror::PointerArray> vtable(hs.NewHandle(klass->GetVTableDuringLinking()));
+  int32_t num_entries = vtable->GetLength();
+  for (int32_t i = 0; i < num_entries; i++) {
+    ArtMethod* vtable_entry = vtable->GetElementPtrSize<ArtMethod*>(i, pointer_size);
+    // Don't bother if we cannot 'see' the vtable entry (i.e. it is a package-private member maybe).
+    if (!klass->CanAccessMember(vtable_entry->GetDeclaringClass(),
+                                vtable_entry->GetAccessFlags())) {
+      continue;
+    }
+    MethodNameAndSignatureComparator name_comparator(
+        vtable_entry->GetInterfaceMethodIfProxy(pointer_size));
+    for (int32_t j = i+1; j < num_entries; j++) {
+      ArtMethod* other_entry = vtable->GetElementPtrSize<ArtMethod*>(j, pointer_size);
+      CHECK(vtable_entry != other_entry &&
+            !name_comparator.HasSameNameAndSignature(
+                other_entry->GetInterfaceMethodIfProxy(pointer_size)))
+          << "vtable entries " << i << " and " << j << " are identical for "
+          << PrettyClass(klass.Get()) << " in method " << PrettyMethod(vtable_entry) << " and "
+          << PrettyMethod(other_entry);
+    }
+  }
+}
+
+static void SanityCheckVTable(Thread* self, Handle<mirror::Class> klass, PointerSize pointer_size)
+    REQUIRES_SHARED(Locks::mutator_lock_) {
+  CheckClassOwnsVTableEntries(self, klass, pointer_size);
+  CheckVTableHasNoDuplicates(self, klass, pointer_size);
+}
+
 void ClassLinker::FillImtFromSuperClass(Handle<mirror::Class> klass,
                                         ArtMethod* unimplemented_method,
                                         ArtMethod* imt_conflict_method,
@@ -6624,8 +6679,10 @@
   ScopedArenaAllocator allocator(&stack);
 
   ScopedArenaVector<ArtMethod*> default_conflict_methods(allocator.Adapter());
+  ScopedArenaVector<ArtMethod*> overriding_default_conflict_methods(allocator.Adapter());
   ScopedArenaVector<ArtMethod*> miranda_methods(allocator.Adapter());
   ScopedArenaVector<ArtMethod*> default_methods(allocator.Adapter());
+  ScopedArenaVector<ArtMethod*> overriding_default_methods(allocator.Adapter());
 
   MutableHandle<mirror::PointerArray> vtable(hs.NewHandle(klass->GetVTableDuringLinking()));
   ArtMethod* const unimplemented_method = runtime->GetImtUnimplementedMethod();
@@ -6829,8 +6886,10 @@
               default_conflict_method = vtable_impl;
             } else {
               // See if we already have a conflict method for this method.
-              ArtMethod* preexisting_conflict = FindSameNameAndSignature(interface_name_comparator,
-                                                                         default_conflict_methods);
+              ArtMethod* preexisting_conflict = FindSameNameAndSignature(
+                  interface_name_comparator,
+                  default_conflict_methods,
+                  overriding_default_conflict_methods);
               if (LIKELY(preexisting_conflict != nullptr)) {
                 // We already have another conflict we can reuse.
                 default_conflict_method = preexisting_conflict;
@@ -6841,7 +6900,13 @@
                 default_conflict_method =
                     reinterpret_cast<ArtMethod*>(allocator.Alloc(method_size));
                 new(default_conflict_method) ArtMethod(interface_method, image_pointer_size_);
-                default_conflict_methods.push_back(default_conflict_method);
+                if (vtable_impl == nullptr) {
+                  // Save the conflict method. We need to add it to the vtable.
+                  default_conflict_methods.push_back(default_conflict_method);
+                } else {
+                  // Save the conflict method but it is already in the vtable.
+                  overriding_default_conflict_methods.push_back(default_conflict_method);
+                }
               }
             }
             current_method = default_conflict_method;
@@ -6861,11 +6926,18 @@
               // TODO It might be worthwhile to copy default methods on interfaces anyway since it
               //      would make lookup for interface super much faster. (We would only need to scan
               //      the iftable to find if there is a NSME or AME.)
-              ArtMethod* old = FindSameNameAndSignature(interface_name_comparator, default_methods);
+              ArtMethod* old = FindSameNameAndSignature(interface_name_comparator,
+                                                        default_methods,
+                                                        overriding_default_methods);
               if (old == nullptr) {
                 // We found a default method implementation and there were no conflicts.
-                // Save the default method. We need to add it to the vtable.
-                default_methods.push_back(current_method);
+                if (vtable_impl == nullptr) {
+                  // Save the default method. We need to add it to the vtable.
+                  default_methods.push_back(current_method);
+                } else {
+                  // Save the default method but it is already in the vtable.
+                  overriding_default_methods.push_back(current_method);
+                }
               } else {
                 CHECK(old == current_method) << "Multiple default implementations selected!";
               }
@@ -6920,6 +6992,8 @@
   }  // For each interface.
   const bool has_new_virtuals = !(miranda_methods.empty() &&
                                   default_methods.empty() &&
+                                  overriding_default_methods.empty() &&
+                                  overriding_default_conflict_methods.empty() &&
                                   default_conflict_methods.empty());
   // TODO don't extend virtuals of interface unless necessary (when is it?).
   if (has_new_virtuals) {
@@ -6927,11 +7001,16 @@
         << "Interfaces should only have default-conflict methods appended to them.";
     VLOG(class_linker) << PrettyClass(klass.Get()) << ": miranda_methods=" << miranda_methods.size()
                        << " default_methods=" << default_methods.size()
-                       << " default_conflict_methods=" << default_conflict_methods.size();
+                       << " overriding_default_methods=" << overriding_default_methods.size()
+                       << " default_conflict_methods=" << default_conflict_methods.size()
+                       << " overriding_default_conflict_methods="
+                       << overriding_default_conflict_methods.size();
     const size_t old_method_count = klass->NumMethods();
     const size_t new_method_count = old_method_count +
                                     miranda_methods.size() +
                                     default_methods.size() +
+                                    overriding_default_conflict_methods.size() +
+                                    overriding_default_methods.size() +
                                     default_conflict_methods.size();
     // Attempt to realloc to save RAM if possible.
     LengthPrefixedArray<ArtMethod>* old_methods = klass->GetMethodsPtr();
@@ -6986,36 +7065,42 @@
     // interface but will have different ArtMethod*s for them. This also means we cannot compare a
     // default method found on a class with one found on the declaring interface directly and must
     // look at the declaring class to determine if they are the same.
-    for (ArtMethod* def_method : default_methods) {
-      ArtMethod& new_method = *out;
-      new_method.CopyFrom(def_method, image_pointer_size_);
-      // Clear the kAccSkipAccessChecks flag if it is present. Since this class hasn't been verified
-      // yet it shouldn't have methods that are skipping access checks.
-      // TODO This is rather arbitrary. We should maybe support classes where only some of its
-      // methods are skip_access_checks.
-      constexpr uint32_t kSetFlags = kAccDefault | kAccCopied;
-      constexpr uint32_t kMaskFlags = ~kAccSkipAccessChecks;
-      new_method.SetAccessFlags((new_method.GetAccessFlags() | kSetFlags) & kMaskFlags);
-      move_table.emplace(def_method, &new_method);
-      ++out;
+    for (const ScopedArenaVector<ArtMethod*>& methods_vec : {default_methods,
+                                                             overriding_default_methods}) {
+      for (ArtMethod* def_method : methods_vec) {
+        ArtMethod& new_method = *out;
+        new_method.CopyFrom(def_method, image_pointer_size_);
+        // Clear the kAccSkipAccessChecks flag if it is present. Since this class hasn't been
+        // verified yet it shouldn't have methods that are skipping access checks.
+        // TODO This is rather arbitrary. We should maybe support classes where only some of its
+        // methods are skip_access_checks.
+        constexpr uint32_t kSetFlags = kAccDefault | kAccCopied;
+        constexpr uint32_t kMaskFlags = ~kAccSkipAccessChecks;
+        new_method.SetAccessFlags((new_method.GetAccessFlags() | kSetFlags) & kMaskFlags);
+        move_table.emplace(def_method, &new_method);
+        ++out;
+      }
     }
-    for (ArtMethod* conf_method : default_conflict_methods) {
-      ArtMethod& new_method = *out;
-      new_method.CopyFrom(conf_method, image_pointer_size_);
-      // This is a type of default method (there are default method impls, just a conflict) so mark
-      // this as a default, non-abstract method, since thats what it is. Also clear the
-      // kAccSkipAccessChecks bit since this class hasn't been verified yet it shouldn't have
-      // methods that are skipping access checks.
-      constexpr uint32_t kSetFlags = kAccDefault | kAccDefaultConflict | kAccCopied;
-      constexpr uint32_t kMaskFlags = ~(kAccAbstract | kAccSkipAccessChecks);
-      new_method.SetAccessFlags((new_method.GetAccessFlags() | kSetFlags) & kMaskFlags);
-      DCHECK(new_method.IsDefaultConflicting());
-      // The actual method might or might not be marked abstract since we just copied it from a
-      // (possibly default) interface method. We need to set it entry point to be the bridge so that
-      // the compiler will not invoke the implementation of whatever method we copied from.
-      EnsureThrowsInvocationError(&new_method);
-      move_table.emplace(conf_method, &new_method);
-      ++out;
+    for (const ScopedArenaVector<ArtMethod*>& methods_vec : {default_conflict_methods,
+                                                             overriding_default_conflict_methods}) {
+      for (ArtMethod* conf_method : methods_vec) {
+        ArtMethod& new_method = *out;
+        new_method.CopyFrom(conf_method, image_pointer_size_);
+        // This is a type of default method (there are default method impls, just a conflict) so
+        // mark this as a default, non-abstract method, since thats what it is. Also clear the
+        // kAccSkipAccessChecks bit since this class hasn't been verified yet it shouldn't have
+        // methods that are skipping access checks.
+        constexpr uint32_t kSetFlags = kAccDefault | kAccDefaultConflict | kAccCopied;
+        constexpr uint32_t kMaskFlags = ~(kAccAbstract | kAccSkipAccessChecks);
+        new_method.SetAccessFlags((new_method.GetAccessFlags() | kSetFlags) & kMaskFlags);
+        DCHECK(new_method.IsDefaultConflicting());
+        // The actual method might or might not be marked abstract since we just copied it from a
+        // (possibly default) interface method. We need to set it entry point to be the bridge so
+        // that the compiler will not invoke the implementation of whatever method we copied from.
+        EnsureThrowsInvocationError(&new_method);
+        move_table.emplace(conf_method, &new_method);
+        ++out;
+      }
     }
     methods->SetSize(new_method_count);
     UpdateClassMethods(klass.Get(), methods);
@@ -7031,22 +7116,31 @@
                                       miranda_methods.size() +
                                       default_methods.size() +
                                       default_conflict_methods.size();
+
       vtable.Assign(down_cast<mirror::PointerArray*>(vtable->CopyOf(self, new_vtable_count)));
       if (UNLIKELY(vtable.Get() == nullptr)) {
         self->AssertPendingOOMException();
         return false;
       }
-      out = methods->begin(method_size, method_alignment) + old_method_count;
       size_t vtable_pos = old_vtable_count;
       // Update all the newly copied method's indexes so they denote their placement in the vtable.
-      for (size_t i = old_method_count; i < new_method_count; ++i) {
-        // Leave the declaring class alone the method's dex_code_item_offset_ and dex_method_index_
-        // fields are references into the dex file the method was defined in. Since the ArtMethod
-        // does not store that information it uses declaring_class_->dex_cache_.
-        out->SetMethodIndex(0xFFFF & vtable_pos);
-        vtable->SetElementPtrSize(vtable_pos, &*out, image_pointer_size_);
-        ++out;
-        ++vtable_pos;
+      for (const ScopedArenaVector<ArtMethod*>& methods_vec : {default_methods,
+                                                               default_conflict_methods,
+                                                               miranda_methods}) {
+        // These are the functions that are not already in the vtable!
+        for (ArtMethod* new_method : methods_vec) {
+          auto translated_method_it = move_table.find(new_method);
+          CHECK(translated_method_it != move_table.end())
+              << "We must have a translation for methods added to the classes methods_ array! We "
+              << "could not find the ArtMethod added for " << PrettyMethod(new_method);
+          ArtMethod* new_vtable_method = translated_method_it->second;
+          // Leave the declaring class alone the method's dex_code_item_offset_ and dex_method_index_
+          // fields are references into the dex file the method was defined in. Since the ArtMethod
+          // does not store that information it uses declaring_class_->dex_cache_.
+          new_vtable_method->SetMethodIndex(0xFFFF & vtable_pos);
+          vtable->SetElementPtrSize(vtable_pos, new_vtable_method, image_pointer_size_);
+          ++vtable_pos;
+        }
       }
       CHECK_EQ(vtable_pos, new_vtable_count);
       // Update old vtable methods. We use the default_translations map to figure out what each
@@ -7062,8 +7156,10 @@
             // Find which conflict method we are to use for this method.
             MethodNameAndSignatureComparator old_method_comparator(
                 translated_method->GetInterfaceMethodIfProxy(image_pointer_size_));
-            ArtMethod* new_conflict_method = FindSameNameAndSignature(old_method_comparator,
-                                                                      default_conflict_methods);
+            // We only need to look through overriding_default_conflict_methods since this is an
+            // overridden method we are fixing up here.
+            ArtMethod* new_conflict_method = FindSameNameAndSignature(
+                old_method_comparator, overriding_default_conflict_methods);
             CHECK(new_conflict_method != nullptr) << "Expected a conflict method!";
             translated_method = new_conflict_method;
           } else if (translation_it->second.IsAbstract()) {
@@ -7071,7 +7167,7 @@
             MethodNameAndSignatureComparator old_method_comparator(
                 translated_method->GetInterfaceMethodIfProxy(image_pointer_size_));
             ArtMethod* miranda_method = FindSameNameAndSignature(old_method_comparator,
-                                                                miranda_methods);
+                                                                 miranda_methods);
             DCHECK(miranda_method != nullptr);
             translated_method = miranda_method;
           } else {
@@ -7086,6 +7182,14 @@
         if (it != move_table.end()) {
           auto* new_method = it->second;
           DCHECK(new_method != nullptr);
+          // Make sure the new_methods index is set.
+          if (new_method->GetMethodIndexDuringLinking() != i) {
+            DCHECK_LE(reinterpret_cast<uintptr_t>(&*methods->begin(method_size, method_alignment)),
+                      reinterpret_cast<uintptr_t>(new_method));
+            DCHECK_LT(reinterpret_cast<uintptr_t>(new_method),
+                      reinterpret_cast<uintptr_t>(&*methods->end(method_size, method_alignment)));
+            new_method->SetMethodIndex(0xFFFF & i);
+          }
           vtable->SetElementPtrSize(i, new_method, image_pointer_size_);
         } else {
           // If it was not going to be updated we wouldn't have put it into the default_translations
@@ -7149,7 +7253,7 @@
     self->EndAssertNoThreadSuspension(old_cause);
   }
   if (kIsDebugBuild && !is_interface) {
-    SanityCheckVTable(klass, image_pointer_size_);
+    SanityCheckVTable(self, klass, image_pointer_size_);
   }
   return true;
 }
@@ -8166,7 +8270,7 @@
 std::set<DexCacheResolvedClasses> ClassLinker::GetResolvedClasses(bool ignore_boot_classes) {
   ScopedTrace trace(__PRETTY_FUNCTION__);
   ScopedObjectAccess soa(Thread::Current());
-  ScopedAssertNoThreadSuspension ants(soa.Self(), __FUNCTION__);
+  ScopedAssertNoThreadSuspension ants(__FUNCTION__);
   std::set<DexCacheResolvedClasses> ret;
   VLOG(class_linker) << "Collecting resolved classes";
   const uint64_t start_time = NanoTime();
@@ -8240,7 +8344,7 @@
   Thread* const self = Thread::Current();
   std::unordered_map<std::string, const DexFile*> location_to_dex_file;
   ScopedObjectAccess soa(self);
-  ScopedAssertNoThreadSuspension ants(soa.Self(), __FUNCTION__);
+  ScopedAssertNoThreadSuspension ants(__FUNCTION__);
   ReaderMutexLock mu(self, *DexLock());
   for (const ClassLinker::DexCacheData& data : GetDexCachesData()) {
     if (!self->IsJWeakCleared(data.weak_root)) {
diff --git a/runtime/class_linker.h b/runtime/class_linker.h
index 4bd1bd2..0a46e2e 100644
--- a/runtime/class_linker.h
+++ b/runtime/class_linker.h
@@ -36,6 +36,7 @@
 #include "jni.h"
 #include "oat_file.h"
 #include "object_callbacks.h"
+#include "verifier/verifier_log_mode.h"
 
 namespace art {
 
@@ -460,7 +461,7 @@
 
   void VerifyClass(Thread* self,
                    Handle<mirror::Class> klass,
-                   LogSeverity log_level = LogSeverity::NONE)
+                   verifier::HardFailLogMode log_level = verifier::HardFailLogMode::kLogNone)
       REQUIRES_SHARED(Locks::mutator_lock_)
       REQUIRES(!dex_lock_);
   bool VerifyClassUsingOatFile(const DexFile& dex_file,
@@ -768,8 +769,7 @@
   void LoadField(const ClassDataItemIterator& it, Handle<mirror::Class> klass, ArtField* dst)
       REQUIRES_SHARED(Locks::mutator_lock_);
 
-  void LoadMethod(Thread* self,
-                  const DexFile& dex_file,
+  void LoadMethod(const DexFile& dex_file,
                   const ClassDataItemIterator& it,
                   Handle<mirror::Class> klass, ArtMethod* dst)
       REQUIRES_SHARED(Locks::mutator_lock_);
diff --git a/runtime/class_linker_test.cc b/runtime/class_linker_test.cc
index 3be39a1..5e0ee6f 100644
--- a/runtime/class_linker_test.cc
+++ b/runtime/class_linker_test.cc
@@ -697,6 +697,9 @@
 struct ExecutableOffsets : public CheckOffsets<mirror::Executable> {
   ExecutableOffsets() : CheckOffsets<mirror::Executable>(
       false, "Ljava/lang/reflect/Executable;") {
+    addOffset(OFFSETOF_MEMBER(mirror::Executable, has_real_parameter_data_),
+              "hasRealParameterData");
+    addOffset(OFFSETOF_MEMBER(mirror::Executable, parameters_), "parameters");
   };
 };
 
diff --git a/runtime/common_runtime_test.cc b/runtime/common_runtime_test.cc
index 531b863..7234952 100644
--- a/runtime/common_runtime_test.cc
+++ b/runtime/common_runtime_test.cc
@@ -582,9 +582,9 @@
   if (IsHost()) {
     const char* host_dir = getenv("ANDROID_HOST_OUT");
     CHECK(host_dir != nullptr);
-    location = StringPrintf("%s/framework/core.%s", host_dir, suffix);
+    location = StringPrintf("%s/framework/core-npic.%s", host_dir, suffix);
   } else {
-    location = StringPrintf("/data/art-test/core.%s", suffix);
+    location = StringPrintf("/data/art-test/core-npic.%s", suffix);
   }
 
   return location;
diff --git a/runtime/common_throws.cc b/runtime/common_throws.cc
index 77362a5..1e4c772 100644
--- a/runtime/common_throws.cc
+++ b/runtime/common_throws.cc
@@ -357,16 +357,6 @@
   ThrowException("Ljava/lang/NoSuchMethodError;", c, msg.str().c_str());
 }
 
-void ThrowNoSuchMethodError(uint32_t method_idx) {
-  ArtMethod* method = Thread::Current()->GetCurrentMethod(nullptr);
-  mirror::DexCache* dex_cache = method->GetDeclaringClass()->GetDexCache();
-  const DexFile& dex_file = *dex_cache->GetDexFile();
-  std::ostringstream msg;
-  msg << "No method '" << PrettyMethod(method_idx, dex_file, true) << "'";
-  ThrowException("Ljava/lang/NoSuchMethodError;",
-                 method->GetDeclaringClass(), msg.str().c_str());
-}
-
 // NullPointerException
 
 void ThrowNullPointerExceptionForFieldAccess(ArtField* field, bool is_read) {
diff --git a/runtime/common_throws.h b/runtime/common_throws.h
index ab25543..945dc2d 100644
--- a/runtime/common_throws.h
+++ b/runtime/common_throws.h
@@ -178,9 +178,6 @@
                             const Signature& signature)
     REQUIRES_SHARED(Locks::mutator_lock_) COLD_ATTR;
 
-void ThrowNoSuchMethodError(uint32_t method_idx)
-    REQUIRES_SHARED(Locks::mutator_lock_) COLD_ATTR;
-
 // NullPointerException
 
 void ThrowNullPointerExceptionForFieldAccess(ArtField* field,
diff --git a/runtime/debugger.cc b/runtime/debugger.cc
index 9f3c2aa..b49c01c 100644
--- a/runtime/debugger.cc
+++ b/runtime/debugger.cc
@@ -28,6 +28,7 @@
 #include "class_linker.h"
 #include "class_linker-inl.h"
 #include "dex_file-inl.h"
+#include "dex_file_annotations.h"
 #include "dex_instruction.h"
 #include "entrypoints/runtime_asm_entrypoints.h"
 #include "gc/accounting/card_table-inl.h"
@@ -1986,7 +1987,7 @@
   if (error != JDWP::ERR_NONE) {
     return JDWP::ERR_INVALID_OBJECT;
   }
-  ScopedAssertNoThreadSuspension ants(soa.Self(), "Debugger: GetThreadGroup");
+  ScopedAssertNoThreadSuspension ants("Debugger: GetThreadGroup");
   // Okay, so it's an object, but is it actually a thread?
   DecodeThread(soa, thread_id, &error);
   if (error == JDWP::ERR_THREAD_NOT_ALIVE) {
@@ -2036,7 +2037,7 @@
   if (error != JDWP::ERR_NONE) {
     return error;
   }
-  ScopedAssertNoThreadSuspension ants(soa.Self(), "Debugger: GetThreadGroupName");
+  ScopedAssertNoThreadSuspension ants("Debugger: GetThreadGroupName");
   ArtField* f = soa.DecodeField(WellKnownClasses::java_lang_ThreadGroup_name);
   CHECK(f != nullptr);
   mirror::String* s = reinterpret_cast<mirror::String*>(f->GetObject(thread_group));
@@ -2055,7 +2056,7 @@
   }
   mirror::Object* parent;
   {
-    ScopedAssertNoThreadSuspension ants(soa.Self(), "Debugger: GetThreadGroupParent");
+    ScopedAssertNoThreadSuspension ants("Debugger: GetThreadGroupParent");
     ArtField* f = soa.DecodeField(WellKnownClasses::java_lang_ThreadGroup_parent);
     CHECK(f != nullptr);
     parent = f->GetObject(thread_group);
@@ -3694,8 +3695,8 @@
           mirror::DexCache* dex_cache = m->GetDeclaringClass()->GetDexCache();
           method = m;
           if (dex_cache != nullptr) {
-            const DexFile& dex_file = *dex_cache->GetDexFile();
-            line_number = dex_file.GetLineNumFromPC(m, GetDexPc());
+            const DexFile* dex_file = dex_cache->GetDexFile();
+            line_number = annotations::GetLineNumFromPC(dex_file, m, GetDexPc());
           }
         }
       }
diff --git a/runtime/dex_file.cc b/runtime/dex_file.cc
index ebadd79..ccc4c16 100644
--- a/runtime/dex_file.cc
+++ b/runtime/dex_file.cc
@@ -27,28 +27,20 @@
 #include <memory>
 #include <sstream>
 
-#include "art_field-inl.h"
-#include "art_method-inl.h"
 #include "base/enums.h"
 #include "base/file_magic.h"
 #include "base/hash_map.h"
 #include "base/logging.h"
 #include "base/stl_util.h"
-#include "base/stringprintf.h"
 #include "base/systrace.h"
 #include "base/unix_file/fd_file.h"
 #include "class_linker-inl.h"
 #include "dex_file-inl.h"
 #include "dex_file_verifier.h"
 #include "globals.h"
-#include "handle_scope-inl.h"
 #include "jvalue.h"
 #include "leb128.h"
-#include "mirror/field.h"
-#include "mirror/method.h"
-#include "mirror/string.h"
 #include "os.h"
-#include "reflection.h"
 #include "safe_map.h"
 #include "thread.h"
 #include "type_lookup_table.h"
@@ -864,22 +856,6 @@
   return Signature(this, *proto_id);
 }
 
-int32_t DexFile::GetLineNumFromPC(ArtMethod* method, uint32_t rel_pc) const {
-  // For native method, lineno should be -2 to indicate it is native. Note that
-  // "line number == -2" is how libcore tells from StackTraceElement.
-  if (method->GetCodeItemOffset() == 0) {
-    return -2;
-  }
-
-  const CodeItem* code_item = GetCodeItem(method->GetCodeItemOffset());
-  DCHECK(code_item != nullptr) << PrettyMethod(method) << " " << GetLocation();
-
-  // A method with no line number info should return -1
-  LineNumFromPcContext context(rel_pc, -1);
-  DecodeDebugPositionInfo(code_item, LineNumForPcCb, &context);
-  return context.line_num_;
-}
-
 int32_t DexFile::FindTryItem(const CodeItem &code_item, uint32_t address) {
   // Note: Signed type is important for max and min.
   int32_t min = 0;
@@ -1186,7 +1162,7 @@
 }
 
 // Read a signed integer.  "zwidth" is the zero-based byte count.
-static int32_t ReadSignedInt(const uint8_t* ptr, int zwidth) {
+int32_t DexFile::ReadSignedInt(const uint8_t* ptr, int zwidth) {
   int32_t val = 0;
   for (int i = zwidth; i >= 0; --i) {
     val = ((uint32_t)val >> 8) | (((int32_t)*ptr++) << 24);
@@ -1197,7 +1173,7 @@
 
 // Read an unsigned integer.  "zwidth" is the zero-based byte count,
 // "fill_on_right" indicates which side we want to zero-fill from.
-static uint32_t ReadUnsignedInt(const uint8_t* ptr, int zwidth, bool fill_on_right) {
+uint32_t DexFile::ReadUnsignedInt(const uint8_t* ptr, int zwidth, bool fill_on_right) {
   uint32_t val = 0;
   for (int i = zwidth; i >= 0; --i) {
     val = (val >> 8) | (((uint32_t)*ptr++) << 24);
@@ -1209,7 +1185,7 @@
 }
 
 // Read a signed long.  "zwidth" is the zero-based byte count.
-static int64_t ReadSignedLong(const uint8_t* ptr, int zwidth) {
+int64_t DexFile::ReadSignedLong(const uint8_t* ptr, int zwidth) {
   int64_t val = 0;
   for (int i = zwidth; i >= 0; --i) {
     val = ((uint64_t)val >> 8) | (((int64_t)*ptr++) << 56);
@@ -1220,7 +1196,7 @@
 
 // Read an unsigned long.  "zwidth" is the zero-based byte count,
 // "fill_on_right" indicates which side we want to zero-fill from.
-static uint64_t ReadUnsignedLong(const uint8_t* ptr, int zwidth, bool fill_on_right) {
+uint64_t DexFile::ReadUnsignedLong(const uint8_t* ptr, int zwidth, bool fill_on_right) {
   uint64_t val = 0;
   for (int i = zwidth; i >= 0; --i) {
     val = (val >> 8) | (((uint64_t)*ptr++) << 56);
@@ -1233,1122 +1209,6 @@
 
 // Checks that visibility is as expected. Includes special behavior for M and
 // before to allow runtime and build visibility when expecting runtime.
-static bool IsVisibilityCompatible(uint32_t actual, uint32_t expected) {
-  if (expected == DexFile::kDexVisibilityRuntime) {
-    int32_t sdk_version = Runtime::Current()->GetTargetSdkVersion();
-    if (sdk_version > 0 && sdk_version <= 23) {
-      return actual == DexFile::kDexVisibilityRuntime || actual == DexFile::kDexVisibilityBuild;
-    }
-  }
-  return actual == expected;
-}
-
-const DexFile::AnnotationSetItem* DexFile::FindAnnotationSetForField(ArtField* field) const {
-  mirror::Class* klass = field->GetDeclaringClass();
-  const AnnotationsDirectoryItem* annotations_dir = GetAnnotationsDirectory(*klass->GetClassDef());
-  if (annotations_dir == nullptr) {
-    return nullptr;
-  }
-  const FieldAnnotationsItem* field_annotations = GetFieldAnnotations(annotations_dir);
-  if (field_annotations == nullptr) {
-    return nullptr;
-  }
-  uint32_t field_index = field->GetDexFieldIndex();
-  uint32_t field_count = annotations_dir->fields_size_;
-  for (uint32_t i = 0; i < field_count; ++i) {
-    if (field_annotations[i].field_idx_ == field_index) {
-      return GetFieldAnnotationSetItem(field_annotations[i]);
-    }
-  }
-  return nullptr;
-}
-
-mirror::Object* DexFile::GetAnnotationForField(ArtField* field,
-                                               Handle<mirror::Class> annotation_class) const {
-  const AnnotationSetItem* annotation_set = FindAnnotationSetForField(field);
-  if (annotation_set == nullptr) {
-    return nullptr;
-  }
-  StackHandleScope<1> hs(Thread::Current());
-  Handle<mirror::Class> field_class(hs.NewHandle(field->GetDeclaringClass()));
-  return GetAnnotationObjectFromAnnotationSet(
-      field_class, annotation_set, kDexVisibilityRuntime, annotation_class);
-}
-
-mirror::ObjectArray<mirror::Object>* DexFile::GetAnnotationsForField(ArtField* field) const {
-  const AnnotationSetItem* annotation_set = FindAnnotationSetForField(field);
-  StackHandleScope<1> hs(Thread::Current());
-  Handle<mirror::Class> field_class(hs.NewHandle(field->GetDeclaringClass()));
-  return ProcessAnnotationSet(field_class, annotation_set, kDexVisibilityRuntime);
-}
-
-mirror::ObjectArray<mirror::String>* DexFile::GetSignatureAnnotationForField(ArtField* field)
-    const {
-  const AnnotationSetItem* annotation_set = FindAnnotationSetForField(field);
-  if (annotation_set == nullptr) {
-    return nullptr;
-  }
-  StackHandleScope<1> hs(Thread::Current());
-  Handle<mirror::Class> field_class(hs.NewHandle(field->GetDeclaringClass()));
-  return GetSignatureValue(field_class, annotation_set);
-}
-
-bool DexFile::IsFieldAnnotationPresent(ArtField* field, Handle<mirror::Class> annotation_class)
-    const {
-  const AnnotationSetItem* annotation_set = FindAnnotationSetForField(field);
-  if (annotation_set == nullptr) {
-    return false;
-  }
-  StackHandleScope<1> hs(Thread::Current());
-  Handle<mirror::Class> field_class(hs.NewHandle(field->GetDeclaringClass()));
-  const AnnotationItem* annotation_item = GetAnnotationItemFromAnnotationSet(
-      field_class, annotation_set, kDexVisibilityRuntime, annotation_class);
-  return annotation_item != nullptr;
-}
-
-const DexFile::AnnotationSetItem* DexFile::FindAnnotationSetForMethod(ArtMethod* method) const {
-  mirror::Class* klass = method->GetDeclaringClass();
-  const AnnotationsDirectoryItem* annotations_dir = GetAnnotationsDirectory(*klass->GetClassDef());
-  if (annotations_dir == nullptr) {
-    return nullptr;
-  }
-  const MethodAnnotationsItem* method_annotations = GetMethodAnnotations(annotations_dir);
-  if (method_annotations == nullptr) {
-    return nullptr;
-  }
-  uint32_t method_index = method->GetDexMethodIndex();
-  uint32_t method_count = annotations_dir->methods_size_;
-  for (uint32_t i = 0; i < method_count; ++i) {
-    if (method_annotations[i].method_idx_ == method_index) {
-      return GetMethodAnnotationSetItem(method_annotations[i]);
-    }
-  }
-  return nullptr;
-}
-
-const DexFile::ParameterAnnotationsItem* DexFile::FindAnnotationsItemForMethod(ArtMethod* method)
-    const {
-  mirror::Class* klass = method->GetDeclaringClass();
-  const AnnotationsDirectoryItem* annotations_dir = GetAnnotationsDirectory(*klass->GetClassDef());
-  if (annotations_dir == nullptr) {
-    return nullptr;
-  }
-  const ParameterAnnotationsItem* parameter_annotations = GetParameterAnnotations(annotations_dir);
-  if (parameter_annotations == nullptr) {
-    return nullptr;
-  }
-  uint32_t method_index = method->GetDexMethodIndex();
-  uint32_t parameter_count = annotations_dir->parameters_size_;
-  for (uint32_t i = 0; i < parameter_count; ++i) {
-    if (parameter_annotations[i].method_idx_ == method_index) {
-      return &parameter_annotations[i];
-    }
-  }
-  return nullptr;
-}
-
-mirror::Object* DexFile::GetAnnotationDefaultValue(ArtMethod* method) const {
-  mirror::Class* klass = method->GetDeclaringClass();
-  const AnnotationsDirectoryItem* annotations_dir = GetAnnotationsDirectory(*klass->GetClassDef());
-  if (annotations_dir == nullptr) {
-    return nullptr;
-  }
-  const AnnotationSetItem* annotation_set = GetClassAnnotationSet(annotations_dir);
-  if (annotation_set == nullptr) {
-    return nullptr;
-  }
-  const AnnotationItem* annotation_item = SearchAnnotationSet(annotation_set,
-      "Ldalvik/annotation/AnnotationDefault;", kDexVisibilitySystem);
-  if (annotation_item == nullptr) {
-    return nullptr;
-  }
-  const uint8_t* annotation = SearchEncodedAnnotation(annotation_item->annotation_, "value");
-  if (annotation == nullptr) {
-    return nullptr;
-  }
-  uint8_t header_byte = *(annotation++);
-  if ((header_byte & kDexAnnotationValueTypeMask) != kDexAnnotationAnnotation) {
-    return nullptr;
-  }
-  annotation = SearchEncodedAnnotation(annotation, method->GetName());
-  if (annotation == nullptr) {
-    return nullptr;
-  }
-  AnnotationValue annotation_value;
-  StackHandleScope<2> hs(Thread::Current());
-  Handle<mirror::Class> h_klass(hs.NewHandle(klass));
-  PointerSize pointer_size = Runtime::Current()->GetClassLinker()->GetImagePointerSize();
-  Handle<mirror::Class> return_type(hs.NewHandle(
-      method->GetReturnType(true /* resolve */, pointer_size)));
-  if (!ProcessAnnotationValue(h_klass, &annotation, &annotation_value, return_type, kAllObjects)) {
-    return nullptr;
-  }
-  return annotation_value.value_.GetL();
-}
-
-mirror::Object* DexFile::GetAnnotationForMethod(ArtMethod* method,
-                                                Handle<mirror::Class> annotation_class) const {
-  const AnnotationSetItem* annotation_set = FindAnnotationSetForMethod(method);
-  if (annotation_set == nullptr) {
-    return nullptr;
-  }
-  StackHandleScope<1> hs(Thread::Current());
-  Handle<mirror::Class> method_class(hs.NewHandle(method->GetDeclaringClass()));
-  return GetAnnotationObjectFromAnnotationSet(method_class, annotation_set,
-                                              kDexVisibilityRuntime, annotation_class);
-}
-
-mirror::ObjectArray<mirror::Object>* DexFile::GetAnnotationsForMethod(ArtMethod* method) const {
-  const AnnotationSetItem* annotation_set = FindAnnotationSetForMethod(method);
-  StackHandleScope<1> hs(Thread::Current());
-  Handle<mirror::Class> method_class(hs.NewHandle(method->GetDeclaringClass()));
-  return ProcessAnnotationSet(method_class, annotation_set, kDexVisibilityRuntime);
-}
-
-mirror::ObjectArray<mirror::Class>* DexFile::GetExceptionTypesForMethod(ArtMethod* method) const {
-  const AnnotationSetItem* annotation_set = FindAnnotationSetForMethod(method);
-  if (annotation_set == nullptr) {
-    return nullptr;
-  }
-  StackHandleScope<1> hs(Thread::Current());
-  Handle<mirror::Class> method_class(hs.NewHandle(method->GetDeclaringClass()));
-  return GetThrowsValue(method_class, annotation_set);
-}
-
-mirror::ObjectArray<mirror::Object>* DexFile::GetParameterAnnotations(ArtMethod* method) const {
-  const ParameterAnnotationsItem* parameter_annotations = FindAnnotationsItemForMethod(method);
-  if (parameter_annotations == nullptr) {
-    return nullptr;
-  }
-  const AnnotationSetRefList* set_ref_list =
-      GetParameterAnnotationSetRefList(parameter_annotations);
-  if (set_ref_list == nullptr) {
-    return nullptr;
-  }
-  uint32_t size = set_ref_list->size_;
-  StackHandleScope<1> hs(Thread::Current());
-  Handle<mirror::Class> method_class(hs.NewHandle(method->GetDeclaringClass()));
-  return ProcessAnnotationSetRefList(method_class, set_ref_list, size);
-}
-
-mirror::ObjectArray<mirror::String>* DexFile::GetSignatureAnnotationForMethod(ArtMethod* method)
-    const {
-  const AnnotationSetItem* annotation_set = FindAnnotationSetForMethod(method);
-  if (annotation_set == nullptr) {
-    return nullptr;
-  }
-  StackHandleScope<1> hs(Thread::Current());
-  Handle<mirror::Class> method_class(hs.NewHandle(method->GetDeclaringClass()));
-  return GetSignatureValue(method_class, annotation_set);
-}
-
-bool DexFile::IsMethodAnnotationPresent(ArtMethod* method,
-                                        Handle<mirror::Class> annotation_class,
-                                        uint32_t visibility /* = kDexVisibilityRuntime */)
-    const {
-  const AnnotationSetItem* annotation_set = FindAnnotationSetForMethod(method);
-  if (annotation_set == nullptr) {
-    return false;
-  }
-  StackHandleScope<1> hs(Thread::Current());
-  Handle<mirror::Class> method_class(hs.NewHandle(method->GetDeclaringClass()));
-  const AnnotationItem* annotation_item = GetAnnotationItemFromAnnotationSet(method_class,
-                                                                             annotation_set,
-                                                                             visibility,
-                                                                             annotation_class);
-  return annotation_item != nullptr;
-}
-
-const DexFile::AnnotationSetItem* DexFile::FindAnnotationSetForClass(Handle<mirror::Class> klass)
-    const {
-  const AnnotationsDirectoryItem* annotations_dir = GetAnnotationsDirectory(*klass->GetClassDef());
-  if (annotations_dir == nullptr) {
-    return nullptr;
-  }
-  return GetClassAnnotationSet(annotations_dir);
-}
-
-mirror::Object* DexFile::GetAnnotationForClass(Handle<mirror::Class> klass,
-                                               Handle<mirror::Class> annotation_class) const {
-  const AnnotationSetItem* annotation_set = FindAnnotationSetForClass(klass);
-  if (annotation_set == nullptr) {
-    return nullptr;
-  }
-  return GetAnnotationObjectFromAnnotationSet(klass, annotation_set, kDexVisibilityRuntime,
-                                              annotation_class);
-}
-
-mirror::ObjectArray<mirror::Object>* DexFile::GetAnnotationsForClass(Handle<mirror::Class> klass)
-    const {
-  const AnnotationSetItem* annotation_set = FindAnnotationSetForClass(klass);
-  return ProcessAnnotationSet(klass, annotation_set, kDexVisibilityRuntime);
-}
-
-mirror::ObjectArray<mirror::Class>* DexFile::GetDeclaredClasses(Handle<mirror::Class> klass) const {
-  const AnnotationSetItem* annotation_set = FindAnnotationSetForClass(klass);
-  if (annotation_set == nullptr) {
-    return nullptr;
-  }
-  const AnnotationItem* annotation_item = SearchAnnotationSet(
-      annotation_set, "Ldalvik/annotation/MemberClasses;", kDexVisibilitySystem);
-  if (annotation_item == nullptr) {
-    return nullptr;
-  }
-  StackHandleScope<1> hs(Thread::Current());
-  mirror::Class* class_class = mirror::Class::GetJavaLangClass();
-  Handle<mirror::Class> class_array_class(hs.NewHandle(
-      Runtime::Current()->GetClassLinker()->FindArrayClass(hs.Self(), &class_class)));
-  if (class_array_class.Get() == nullptr) {
-    return nullptr;
-  }
-  mirror::Object* obj = GetAnnotationValue(
-      klass, annotation_item, "value", class_array_class, kDexAnnotationArray);
-  if (obj == nullptr) {
-    return nullptr;
-  }
-  return obj->AsObjectArray<mirror::Class>();
-}
-
-mirror::Class* DexFile::GetDeclaringClass(Handle<mirror::Class> klass) const {
-  const AnnotationSetItem* annotation_set = FindAnnotationSetForClass(klass);
-  if (annotation_set == nullptr) {
-    return nullptr;
-  }
-  const AnnotationItem* annotation_item = SearchAnnotationSet(
-      annotation_set, "Ldalvik/annotation/EnclosingClass;", kDexVisibilitySystem);
-  if (annotation_item == nullptr) {
-    return nullptr;
-  }
-  mirror::Object* obj = GetAnnotationValue(klass,
-                                           annotation_item,
-                                           "value",
-                                           ScopedNullHandle<mirror::Class>(),
-                                           kDexAnnotationType);
-  if (obj == nullptr) {
-    return nullptr;
-  }
-  return obj->AsClass();
-}
-
-mirror::Class* DexFile::GetEnclosingClass(Handle<mirror::Class> klass) const {
-  mirror::Class* declaring_class = GetDeclaringClass(klass);
-  if (declaring_class != nullptr) {
-    return declaring_class;
-  }
-  const AnnotationSetItem* annotation_set = FindAnnotationSetForClass(klass);
-  if (annotation_set == nullptr) {
-    return nullptr;
-  }
-  const AnnotationItem* annotation_item = SearchAnnotationSet(
-      annotation_set, "Ldalvik/annotation/EnclosingMethod;", kDexVisibilitySystem);
-  if (annotation_item == nullptr) {
-    return nullptr;
-  }
-  const uint8_t* annotation = SearchEncodedAnnotation(annotation_item->annotation_, "value");
-  if (annotation == nullptr) {
-    return nullptr;
-  }
-  AnnotationValue annotation_value;
-  if (!ProcessAnnotationValue(klass,
-                              &annotation,
-                              &annotation_value,
-                              ScopedNullHandle<mirror::Class>(),
-                              kAllRaw)) {
-    return nullptr;
-  }
-  if (annotation_value.type_ != kDexAnnotationMethod) {
-    return nullptr;
-  }
-  StackHandleScope<2> hs(Thread::Current());
-  Handle<mirror::DexCache> dex_cache(hs.NewHandle(klass->GetDexCache()));
-  Handle<mirror::ClassLoader> class_loader(hs.NewHandle(klass->GetClassLoader()));
-  ArtMethod* method = Runtime::Current()->GetClassLinker()->ResolveMethodWithoutInvokeType(
-      klass->GetDexFile(), annotation_value.value_.GetI(), dex_cache, class_loader);
-  if (method == nullptr) {
-    return nullptr;
-  }
-  return method->GetDeclaringClass();
-}
-
-mirror::Object* DexFile::GetEnclosingMethod(Handle<mirror::Class> klass) const {
-  const AnnotationSetItem* annotation_set = FindAnnotationSetForClass(klass);
-  if (annotation_set == nullptr) {
-    return nullptr;
-  }
-  const AnnotationItem* annotation_item = SearchAnnotationSet(
-      annotation_set, "Ldalvik/annotation/EnclosingMethod;", kDexVisibilitySystem);
-  if (annotation_item == nullptr) {
-    return nullptr;
-  }
-  return GetAnnotationValue(
-      klass, annotation_item, "value", ScopedNullHandle<mirror::Class>(), kDexAnnotationMethod);
-}
-
-bool DexFile::GetInnerClass(Handle<mirror::Class> klass, mirror::String** name) const {
-  const AnnotationSetItem* annotation_set = FindAnnotationSetForClass(klass);
-  if (annotation_set == nullptr) {
-    return false;
-  }
-  const AnnotationItem* annotation_item = SearchAnnotationSet(
-      annotation_set, "Ldalvik/annotation/InnerClass;", kDexVisibilitySystem);
-  if (annotation_item == nullptr) {
-    return false;
-  }
-  const uint8_t* annotation = SearchEncodedAnnotation(annotation_item->annotation_, "name");
-  if (annotation == nullptr) {
-    return false;
-  }
-  AnnotationValue annotation_value;
-  if (!ProcessAnnotationValue(klass,
-                              &annotation,
-                              &annotation_value,
-                              ScopedNullHandle<mirror::Class>(),
-                              kAllObjects)) {
-    return false;
-  }
-  if (annotation_value.type_ != kDexAnnotationNull &&
-      annotation_value.type_ != kDexAnnotationString) {
-    return false;
-  }
-  *name = down_cast<mirror::String*>(annotation_value.value_.GetL());
-  return true;
-}
-
-bool DexFile::GetInnerClassFlags(Handle<mirror::Class> klass, uint32_t* flags) const {
-  const AnnotationSetItem* annotation_set = FindAnnotationSetForClass(klass);
-  if (annotation_set == nullptr) {
-    return false;
-  }
-  const AnnotationItem* annotation_item = SearchAnnotationSet(
-      annotation_set, "Ldalvik/annotation/InnerClass;", kDexVisibilitySystem);
-  if (annotation_item == nullptr) {
-    return false;
-  }
-  const uint8_t* annotation = SearchEncodedAnnotation(annotation_item->annotation_, "accessFlags");
-  if (annotation == nullptr) {
-    return false;
-  }
-  AnnotationValue annotation_value;
-  if (!ProcessAnnotationValue(klass,
-                              &annotation,
-                              &annotation_value,
-                              ScopedNullHandle<mirror::Class>(),
-                              kAllRaw)) {
-    return false;
-  }
-  if (annotation_value.type_ != kDexAnnotationInt) {
-    return false;
-  }
-  *flags = annotation_value.value_.GetI();
-  return true;
-}
-
-mirror::ObjectArray<mirror::String>* DexFile::GetSignatureAnnotationForClass(
-    Handle<mirror::Class> klass) const {
-  const AnnotationSetItem* annotation_set = FindAnnotationSetForClass(klass);
-  if (annotation_set == nullptr) {
-    return nullptr;
-  }
-  return GetSignatureValue(klass, annotation_set);
-}
-
-bool DexFile::IsClassAnnotationPresent(Handle<mirror::Class> klass,
-                                       Handle<mirror::Class> annotation_class) const {
-  const AnnotationSetItem* annotation_set = FindAnnotationSetForClass(klass);
-  if (annotation_set == nullptr) {
-    return false;
-  }
-  const AnnotationItem* annotation_item = GetAnnotationItemFromAnnotationSet(
-      klass, annotation_set, kDexVisibilityRuntime, annotation_class);
-  return annotation_item != nullptr;
-}
-
-mirror::Object* DexFile::CreateAnnotationMember(Handle<mirror::Class> klass,
-    Handle<mirror::Class> annotation_class, const uint8_t** annotation) const {
-  Thread* self = Thread::Current();
-  ScopedObjectAccessUnchecked soa(self);
-  StackHandleScope<5> hs(self);
-  uint32_t element_name_index = DecodeUnsignedLeb128(annotation);
-  const char* name = StringDataByIdx(element_name_index);
-  Handle<mirror::String> string_name(
-      hs.NewHandle(mirror::String::AllocFromModifiedUtf8(self, name)));
-
-  PointerSize pointer_size = Runtime::Current()->GetClassLinker()->GetImagePointerSize();
-  ArtMethod* annotation_method =
-      annotation_class->FindDeclaredVirtualMethodByName(name, pointer_size);
-  if (annotation_method == nullptr) {
-    return nullptr;
-  }
-  Handle<mirror::Class> method_return(hs.NewHandle(
-      annotation_method->GetReturnType(true /* resolve */, pointer_size)));
-
-  AnnotationValue annotation_value;
-  if (!ProcessAnnotationValue(klass, annotation, &annotation_value, method_return, kAllObjects)) {
-    return nullptr;
-  }
-  Handle<mirror::Object> value_object(hs.NewHandle(annotation_value.value_.GetL()));
-
-  mirror::Class* annotation_member_class =
-      WellKnownClasses::ToClass(WellKnownClasses::libcore_reflect_AnnotationMember);
-  Handle<mirror::Object> new_member(hs.NewHandle(annotation_member_class->AllocObject(self)));
-  mirror::Method* method_obj_ptr;
-  DCHECK(!Runtime::Current()->IsActiveTransaction());
-  if (pointer_size == PointerSize::k64) {
-    method_obj_ptr = mirror::Method::CreateFromArtMethod<PointerSize::k64, false>(
-        self, annotation_method);
-  } else {
-    method_obj_ptr = mirror::Method::CreateFromArtMethod<PointerSize::k32, false>(
-        self, annotation_method);
-  }
-  Handle<mirror::Method> method_object(hs.NewHandle(method_obj_ptr));
-
-  if (new_member.Get() == nullptr || string_name.Get() == nullptr ||
-      method_object.Get() == nullptr || method_return.Get() == nullptr) {
-    LOG(ERROR) << StringPrintf("Failed creating annotation element (m=%p n=%p a=%p r=%p",
-        new_member.Get(), string_name.Get(), method_object.Get(), method_return.Get());
-    return nullptr;
-  }
-
-  JValue result;
-  ArtMethod* annotation_member_init =
-      soa.DecodeMethod(WellKnownClasses::libcore_reflect_AnnotationMember_init);
-  uint32_t args[5] = { static_cast<uint32_t>(reinterpret_cast<uintptr_t>(new_member.Get())),
-                       static_cast<uint32_t>(reinterpret_cast<uintptr_t>(string_name.Get())),
-                       static_cast<uint32_t>(reinterpret_cast<uintptr_t>(value_object.Get())),
-                       static_cast<uint32_t>(reinterpret_cast<uintptr_t>(method_return.Get())),
-                       static_cast<uint32_t>(reinterpret_cast<uintptr_t>(method_object.Get()))
-  };
-  annotation_member_init->Invoke(self, args, sizeof(args), &result, "VLLLL");
-  if (self->IsExceptionPending()) {
-    LOG(INFO) << "Exception in AnnotationMember.<init>";
-    return nullptr;
-  }
-
-  return new_member.Get();
-}
-
-const DexFile::AnnotationItem* DexFile::GetAnnotationItemFromAnnotationSet(
-    Handle<mirror::Class> klass, const AnnotationSetItem* annotation_set, uint32_t visibility,
-    Handle<mirror::Class> annotation_class) const {
-  for (uint32_t i = 0; i < annotation_set->size_; ++i) {
-    const AnnotationItem* annotation_item = GetAnnotationItem(annotation_set, i);
-    if (!IsVisibilityCompatible(annotation_item->visibility_, visibility)) {
-      continue;
-    }
-    const uint8_t* annotation = annotation_item->annotation_;
-    uint32_t type_index = DecodeUnsignedLeb128(&annotation);
-    mirror::Class* resolved_class = Runtime::Current()->GetClassLinker()->ResolveType(
-        klass->GetDexFile(), type_index, klass.Get());
-    if (resolved_class == nullptr) {
-      std::string temp;
-      LOG(WARNING) << StringPrintf("Unable to resolve %s annotation class %d",
-                                   klass->GetDescriptor(&temp), type_index);
-      CHECK(Thread::Current()->IsExceptionPending());
-      Thread::Current()->ClearException();
-      continue;
-    }
-    if (resolved_class == annotation_class.Get()) {
-      return annotation_item;
-    }
-  }
-
-  return nullptr;
-}
-
-mirror::Object* DexFile::GetAnnotationObjectFromAnnotationSet(Handle<mirror::Class> klass,
-    const AnnotationSetItem* annotation_set, uint32_t visibility,
-    Handle<mirror::Class> annotation_class) const {
-  const AnnotationItem* annotation_item =
-      GetAnnotationItemFromAnnotationSet(klass, annotation_set, visibility, annotation_class);
-  if (annotation_item == nullptr) {
-    return nullptr;
-  }
-  const uint8_t* annotation = annotation_item->annotation_;
-  return ProcessEncodedAnnotation(klass, &annotation);
-}
-
-mirror::Object* DexFile::GetAnnotationValue(Handle<mirror::Class> klass,
-    const AnnotationItem* annotation_item, const char* annotation_name,
-    Handle<mirror::Class> array_class, uint32_t expected_type) const {
-  const uint8_t* annotation =
-      SearchEncodedAnnotation(annotation_item->annotation_, annotation_name);
-  if (annotation == nullptr) {
-    return nullptr;
-  }
-  AnnotationValue annotation_value;
-  if (!ProcessAnnotationValue(klass, &annotation, &annotation_value, array_class, kAllObjects)) {
-    return nullptr;
-  }
-  if (annotation_value.type_ != expected_type) {
-    return nullptr;
-  }
-  return annotation_value.value_.GetL();
-}
-
-mirror::ObjectArray<mirror::String>* DexFile::GetSignatureValue(Handle<mirror::Class> klass,
-    const AnnotationSetItem* annotation_set) const {
-  StackHandleScope<1> hs(Thread::Current());
-  const AnnotationItem* annotation_item =
-      SearchAnnotationSet(annotation_set, "Ldalvik/annotation/Signature;", kDexVisibilitySystem);
-  if (annotation_item == nullptr) {
-    return nullptr;
-  }
-  mirror::Class* string_class = mirror::String::GetJavaLangString();
-  Handle<mirror::Class> string_array_class(hs.NewHandle(
-      Runtime::Current()->GetClassLinker()->FindArrayClass(Thread::Current(), &string_class)));
-  if (string_array_class.Get() == nullptr) {
-    return nullptr;
-  }
-  mirror::Object* obj =
-      GetAnnotationValue(klass, annotation_item, "value", string_array_class, kDexAnnotationArray);
-  if (obj == nullptr) {
-    return nullptr;
-  }
-  return obj->AsObjectArray<mirror::String>();
-}
-
-mirror::ObjectArray<mirror::Class>* DexFile::GetThrowsValue(Handle<mirror::Class> klass,
-    const AnnotationSetItem* annotation_set) const {
-  StackHandleScope<1> hs(Thread::Current());
-  const AnnotationItem* annotation_item =
-      SearchAnnotationSet(annotation_set, "Ldalvik/annotation/Throws;", kDexVisibilitySystem);
-  if (annotation_item == nullptr) {
-    return nullptr;
-  }
-  mirror::Class* class_class = mirror::Class::GetJavaLangClass();
-  Handle<mirror::Class> class_array_class(hs.NewHandle(
-      Runtime::Current()->GetClassLinker()->FindArrayClass(Thread::Current(), &class_class)));
-  if (class_array_class.Get() == nullptr) {
-    return nullptr;
-  }
-  mirror::Object* obj =
-      GetAnnotationValue(klass, annotation_item, "value", class_array_class, kDexAnnotationArray);
-  if (obj == nullptr) {
-    return nullptr;
-  }
-  return obj->AsObjectArray<mirror::Class>();
-}
-
-mirror::ObjectArray<mirror::Object>* DexFile::ProcessAnnotationSet(Handle<mirror::Class> klass,
-    const AnnotationSetItem* annotation_set, uint32_t visibility) const {
-  Thread* self = Thread::Current();
-  ScopedObjectAccessUnchecked soa(self);
-  StackHandleScope<2> hs(self);
-  Handle<mirror::Class> annotation_array_class(hs.NewHandle(
-      soa.Decode<mirror::Class*>(WellKnownClasses::java_lang_annotation_Annotation__array)));
-  if (annotation_set == nullptr) {
-    return mirror::ObjectArray<mirror::Object>::Alloc(self, annotation_array_class.Get(), 0);
-  }
-
-  uint32_t size = annotation_set->size_;
-  Handle<mirror::ObjectArray<mirror::Object>> result(hs.NewHandle(
-      mirror::ObjectArray<mirror::Object>::Alloc(self, annotation_array_class.Get(), size)));
-  if (result.Get() == nullptr) {
-    return nullptr;
-  }
-
-  uint32_t dest_index = 0;
-  for (uint32_t i = 0; i < size; ++i) {
-    const AnnotationItem* annotation_item = GetAnnotationItem(annotation_set, i);
-    // Note that we do not use IsVisibilityCompatible here because older code
-    // was correct for this case.
-    if (annotation_item->visibility_ != visibility) {
-      continue;
-    }
-    const uint8_t* annotation = annotation_item->annotation_;
-    mirror::Object* annotation_obj = ProcessEncodedAnnotation(klass, &annotation);
-    if (annotation_obj != nullptr) {
-      result->SetWithoutChecks<false>(dest_index, annotation_obj);
-      ++dest_index;
-    } else if (self->IsExceptionPending()) {
-      return nullptr;
-    }
-  }
-
-  if (dest_index == size) {
-    return result.Get();
-  }
-
-  mirror::ObjectArray<mirror::Object>* trimmed_result =
-      mirror::ObjectArray<mirror::Object>::Alloc(self, annotation_array_class.Get(), dest_index);
-  if (trimmed_result == nullptr) {
-    return nullptr;
-  }
-
-  for (uint32_t i = 0; i < dest_index; ++i) {
-    mirror::Object* obj = result->GetWithoutChecks(i);
-    trimmed_result->SetWithoutChecks<false>(i, obj);
-  }
-
-  return trimmed_result;
-}
-
-mirror::ObjectArray<mirror::Object>* DexFile::ProcessAnnotationSetRefList(
-    Handle<mirror::Class> klass, const AnnotationSetRefList* set_ref_list, uint32_t size) const {
-  Thread* self = Thread::Current();
-  ScopedObjectAccessUnchecked soa(self);
-  StackHandleScope<1> hs(self);
-  mirror::Class* annotation_array_class =
-      soa.Decode<mirror::Class*>(WellKnownClasses::java_lang_annotation_Annotation__array);
-  mirror::Class* annotation_array_array_class =
-      Runtime::Current()->GetClassLinker()->FindArrayClass(self, &annotation_array_class);
-  if (annotation_array_array_class == nullptr) {
-    return nullptr;
-  }
-  Handle<mirror::ObjectArray<mirror::Object>> annotation_array_array(hs.NewHandle(
-      mirror::ObjectArray<mirror::Object>::Alloc(self, annotation_array_array_class, size)));
-  if (annotation_array_array.Get() == nullptr) {
-    LOG(ERROR) << "Annotation set ref array allocation failed";
-    return nullptr;
-  }
-  for (uint32_t index = 0; index < size; ++index) {
-    const AnnotationSetRefItem* set_ref_item = &set_ref_list->list_[index];
-    const AnnotationSetItem* set_item = GetSetRefItemItem(set_ref_item);
-    mirror::Object* annotation_set = ProcessAnnotationSet(klass, set_item, kDexVisibilityRuntime);
-    if (annotation_set == nullptr) {
-      return nullptr;
-    }
-    annotation_array_array->SetWithoutChecks<false>(index, annotation_set);
-  }
-  return annotation_array_array.Get();
-}
-
-bool DexFile::ProcessAnnotationValue(Handle<mirror::Class> klass, const uint8_t** annotation_ptr,
-    AnnotationValue* annotation_value, Handle<mirror::Class> array_class,
-    DexFile::AnnotationResultStyle result_style) const {
-  Thread* self = Thread::Current();
-  mirror::Object* element_object = nullptr;
-  bool set_object = false;
-  Primitive::Type primitive_type = Primitive::kPrimVoid;
-  const uint8_t* annotation = *annotation_ptr;
-  uint8_t header_byte = *(annotation++);
-  uint8_t value_type = header_byte & kDexAnnotationValueTypeMask;
-  uint8_t value_arg = header_byte >> kDexAnnotationValueArgShift;
-  int32_t width = value_arg + 1;
-  annotation_value->type_ = value_type;
-
-  switch (value_type) {
-    case kDexAnnotationByte:
-      annotation_value->value_.SetB(static_cast<int8_t>(ReadSignedInt(annotation, value_arg)));
-      primitive_type = Primitive::kPrimByte;
-      break;
-    case kDexAnnotationShort:
-      annotation_value->value_.SetS(static_cast<int16_t>(ReadSignedInt(annotation, value_arg)));
-      primitive_type = Primitive::kPrimShort;
-      break;
-    case kDexAnnotationChar:
-      annotation_value->value_.SetC(static_cast<uint16_t>(ReadUnsignedInt(annotation, value_arg,
-                                                                          false)));
-      primitive_type = Primitive::kPrimChar;
-      break;
-    case kDexAnnotationInt:
-      annotation_value->value_.SetI(ReadSignedInt(annotation, value_arg));
-      primitive_type = Primitive::kPrimInt;
-      break;
-    case kDexAnnotationLong:
-      annotation_value->value_.SetJ(ReadSignedLong(annotation, value_arg));
-      primitive_type = Primitive::kPrimLong;
-      break;
-    case kDexAnnotationFloat:
-      annotation_value->value_.SetI(ReadUnsignedInt(annotation, value_arg, true));
-      primitive_type = Primitive::kPrimFloat;
-      break;
-    case kDexAnnotationDouble:
-      annotation_value->value_.SetJ(ReadUnsignedLong(annotation, value_arg, true));
-      primitive_type = Primitive::kPrimDouble;
-      break;
-    case kDexAnnotationBoolean:
-      annotation_value->value_.SetZ(value_arg != 0);
-      primitive_type = Primitive::kPrimBoolean;
-      width = 0;
-      break;
-    case kDexAnnotationString: {
-      uint32_t index = ReadUnsignedInt(annotation, value_arg, false);
-      if (result_style == kAllRaw) {
-        annotation_value->value_.SetI(index);
-      } else {
-        StackHandleScope<1> hs(self);
-        Handle<mirror::DexCache> dex_cache(hs.NewHandle(klass->GetDexCache()));
-        element_object = Runtime::Current()->GetClassLinker()->ResolveString(
-            klass->GetDexFile(), index, dex_cache);
-        set_object = true;
-        if (element_object == nullptr) {
-          return false;
-        }
-      }
-      break;
-    }
-    case kDexAnnotationType: {
-      uint32_t index = ReadUnsignedInt(annotation, value_arg, false);
-      if (result_style == kAllRaw) {
-        annotation_value->value_.SetI(index);
-      } else {
-        element_object = Runtime::Current()->GetClassLinker()->ResolveType(
-            klass->GetDexFile(), index, klass.Get());
-        set_object = true;
-        if (element_object == nullptr) {
-          CHECK(self->IsExceptionPending());
-          if (result_style == kAllObjects) {
-            const char* msg = StringByTypeIdx(index);
-            self->ThrowNewWrappedException("Ljava/lang/TypeNotPresentException;", msg);
-            element_object = self->GetException();
-            self->ClearException();
-          } else {
-            return false;
-          }
-        }
-      }
-      break;
-    }
-    case kDexAnnotationMethod: {
-      uint32_t index = ReadUnsignedInt(annotation, value_arg, false);
-      if (result_style == kAllRaw) {
-        annotation_value->value_.SetI(index);
-      } else {
-        StackHandleScope<2> hs(self);
-        Handle<mirror::DexCache> dex_cache(hs.NewHandle(klass->GetDexCache()));
-        Handle<mirror::ClassLoader> class_loader(hs.NewHandle(klass->GetClassLoader()));
-        ClassLinker* class_linker = Runtime::Current()->GetClassLinker();
-        ArtMethod* method = class_linker->ResolveMethodWithoutInvokeType(
-            klass->GetDexFile(), index, dex_cache, class_loader);
-        if (method == nullptr) {
-          return false;
-        }
-        PointerSize pointer_size = class_linker->GetImagePointerSize();
-        set_object = true;
-        DCHECK(!Runtime::Current()->IsActiveTransaction());
-        if (method->IsConstructor()) {
-          if (pointer_size == PointerSize::k64) {
-            element_object = mirror::Constructor::CreateFromArtMethod<PointerSize::k64,
-                                                                      false>(self, method);
-          } else {
-            element_object = mirror::Constructor::CreateFromArtMethod<PointerSize::k32,
-                                                                      false>(self, method);
-          }
-        } else {
-          if (pointer_size == PointerSize::k64) {
-            element_object = mirror::Method::CreateFromArtMethod<PointerSize::k64,
-                                                                 false>(self, method);
-          } else {
-            element_object = mirror::Method::CreateFromArtMethod<PointerSize::k32,
-                                                                 false>(self, method);
-          }
-        }
-        if (element_object == nullptr) {
-          return false;
-        }
-      }
-      break;
-    }
-    case kDexAnnotationField: {
-      uint32_t index = ReadUnsignedInt(annotation, value_arg, false);
-      if (result_style == kAllRaw) {
-        annotation_value->value_.SetI(index);
-      } else {
-        StackHandleScope<2> hs(self);
-        Handle<mirror::DexCache> dex_cache(hs.NewHandle(klass->GetDexCache()));
-        Handle<mirror::ClassLoader> class_loader(hs.NewHandle(klass->GetClassLoader()));
-        ArtField* field = Runtime::Current()->GetClassLinker()->ResolveFieldJLS(
-            klass->GetDexFile(), index, dex_cache, class_loader);
-        if (field == nullptr) {
-          return false;
-        }
-        set_object = true;
-        PointerSize pointer_size = Runtime::Current()->GetClassLinker()->GetImagePointerSize();
-        if (pointer_size == PointerSize::k64) {
-          element_object = mirror::Field::CreateFromArtField<PointerSize::k64>(self, field, true);
-        } else {
-          element_object = mirror::Field::CreateFromArtField<PointerSize::k32>(self, field, true);
-        }
-        if (element_object == nullptr) {
-          return false;
-        }
-      }
-      break;
-    }
-    case kDexAnnotationEnum: {
-      uint32_t index = ReadUnsignedInt(annotation, value_arg, false);
-      if (result_style == kAllRaw) {
-        annotation_value->value_.SetI(index);
-      } else {
-        StackHandleScope<3> hs(self);
-        Handle<mirror::DexCache> dex_cache(hs.NewHandle(klass->GetDexCache()));
-        Handle<mirror::ClassLoader> class_loader(hs.NewHandle(klass->GetClassLoader()));
-        ArtField* enum_field = Runtime::Current()->GetClassLinker()->ResolveField(
-            klass->GetDexFile(), index, dex_cache, class_loader, true);
-        if (enum_field == nullptr) {
-          return false;
-        } else {
-          Handle<mirror::Class> field_class(hs.NewHandle(enum_field->GetDeclaringClass()));
-          Runtime::Current()->GetClassLinker()->EnsureInitialized(self, field_class, true, true);
-          element_object = enum_field->GetObject(field_class.Get());
-          set_object = true;
-        }
-      }
-      break;
-    }
-    case kDexAnnotationArray:
-      if (result_style == kAllRaw || array_class.Get() == nullptr) {
-        return false;
-      } else {
-        ScopedObjectAccessUnchecked soa(self);
-        StackHandleScope<2> hs(self);
-        uint32_t size = DecodeUnsignedLeb128(&annotation);
-        Handle<mirror::Class> component_type(hs.NewHandle(array_class->GetComponentType()));
-        Handle<mirror::Array> new_array(hs.NewHandle(mirror::Array::Alloc<true>(
-            self, array_class.Get(), size, array_class->GetComponentSizeShift(),
-            Runtime::Current()->GetHeap()->GetCurrentAllocator())));
-        if (new_array.Get() == nullptr) {
-          LOG(ERROR) << "Annotation element array allocation failed with size " << size;
-          return false;
-        }
-        AnnotationValue new_annotation_value;
-        for (uint32_t i = 0; i < size; ++i) {
-          if (!ProcessAnnotationValue(klass, &annotation, &new_annotation_value, component_type,
-                                      kPrimitivesOrObjects)) {
-            return false;
-          }
-          if (!component_type->IsPrimitive()) {
-            mirror::Object* obj = new_annotation_value.value_.GetL();
-            new_array->AsObjectArray<mirror::Object>()->SetWithoutChecks<false>(i, obj);
-          } else {
-            switch (new_annotation_value.type_) {
-              case kDexAnnotationByte:
-                new_array->AsByteArray()->SetWithoutChecks<false>(
-                    i, new_annotation_value.value_.GetB());
-                break;
-              case kDexAnnotationShort:
-                new_array->AsShortArray()->SetWithoutChecks<false>(
-                    i, new_annotation_value.value_.GetS());
-                break;
-              case kDexAnnotationChar:
-                new_array->AsCharArray()->SetWithoutChecks<false>(
-                    i, new_annotation_value.value_.GetC());
-                break;
-              case kDexAnnotationInt:
-                new_array->AsIntArray()->SetWithoutChecks<false>(
-                    i, new_annotation_value.value_.GetI());
-                break;
-              case kDexAnnotationLong:
-                new_array->AsLongArray()->SetWithoutChecks<false>(
-                    i, new_annotation_value.value_.GetJ());
-                break;
-              case kDexAnnotationFloat:
-                new_array->AsFloatArray()->SetWithoutChecks<false>(
-                    i, new_annotation_value.value_.GetF());
-                break;
-              case kDexAnnotationDouble:
-                new_array->AsDoubleArray()->SetWithoutChecks<false>(
-                    i, new_annotation_value.value_.GetD());
-                break;
-              case kDexAnnotationBoolean:
-                new_array->AsBooleanArray()->SetWithoutChecks<false>(
-                    i, new_annotation_value.value_.GetZ());
-                break;
-              default:
-                LOG(FATAL) << "Found invalid annotation value type while building annotation array";
-                return false;
-            }
-          }
-        }
-        element_object = new_array.Get();
-        set_object = true;
-        width = 0;
-      }
-      break;
-    case kDexAnnotationAnnotation:
-      if (result_style == kAllRaw) {
-        return false;
-      }
-      element_object = ProcessEncodedAnnotation(klass, &annotation);
-      if (element_object == nullptr) {
-        return false;
-      }
-      set_object = true;
-      width = 0;
-      break;
-    case kDexAnnotationNull:
-      if (result_style == kAllRaw) {
-        annotation_value->value_.SetI(0);
-      } else {
-        CHECK(element_object == nullptr);
-        set_object = true;
-      }
-      width = 0;
-      break;
-    default:
-      LOG(ERROR) << StringPrintf("Bad annotation element value type 0x%02x", value_type);
-      return false;
-  }
-
-  annotation += width;
-  *annotation_ptr = annotation;
-
-  if (result_style == kAllObjects && primitive_type != Primitive::kPrimVoid) {
-    element_object = BoxPrimitive(primitive_type, annotation_value->value_);
-    set_object = true;
-  }
-
-  if (set_object) {
-    annotation_value->value_.SetL(element_object);
-  }
-
-  return true;
-}
-
-mirror::Object* DexFile::ProcessEncodedAnnotation(Handle<mirror::Class> klass,
-    const uint8_t** annotation) const {
-  uint32_t type_index = DecodeUnsignedLeb128(annotation);
-  uint32_t size = DecodeUnsignedLeb128(annotation);
-
-  Thread* self = Thread::Current();
-  ScopedObjectAccessUnchecked soa(self);
-  StackHandleScope<2> hs(self);
-  ClassLinker* class_linker = Runtime::Current()->GetClassLinker();
-  Handle<mirror::Class> annotation_class(hs.NewHandle(
-      class_linker->ResolveType(klass->GetDexFile(), type_index, klass.Get())));
-  if (annotation_class.Get() == nullptr) {
-    LOG(INFO) << "Unable to resolve " << PrettyClass(klass.Get()) << " annotation class "
-              << type_index;
-    DCHECK(Thread::Current()->IsExceptionPending());
-    Thread::Current()->ClearException();
-    return nullptr;
-  }
-
-  mirror::Class* annotation_member_class =
-      soa.Decode<mirror::Class*>(WellKnownClasses::libcore_reflect_AnnotationMember);
-  mirror::Class* annotation_member_array_class =
-      class_linker->FindArrayClass(self, &annotation_member_class);
-  if (annotation_member_array_class == nullptr) {
-    return nullptr;
-  }
-  mirror::ObjectArray<mirror::Object>* element_array = nullptr;
-  if (size > 0) {
-    element_array =
-        mirror::ObjectArray<mirror::Object>::Alloc(self, annotation_member_array_class, size);
-    if (element_array == nullptr) {
-      LOG(ERROR) << "Failed to allocate annotation member array (" << size << " elements)";
-      return nullptr;
-    }
-  }
-
-  Handle<mirror::ObjectArray<mirror::Object>> h_element_array(hs.NewHandle(element_array));
-  for (uint32_t i = 0; i < size; ++i) {
-    mirror::Object* new_member = CreateAnnotationMember(klass, annotation_class, annotation);
-    if (new_member == nullptr) {
-      return nullptr;
-    }
-    h_element_array->SetWithoutChecks<false>(i, new_member);
-  }
-
-  JValue result;
-  ArtMethod* create_annotation_method =
-      soa.DecodeMethod(WellKnownClasses::libcore_reflect_AnnotationFactory_createAnnotation);
-  uint32_t args[2] = { static_cast<uint32_t>(reinterpret_cast<uintptr_t>(annotation_class.Get())),
-                       static_cast<uint32_t>(reinterpret_cast<uintptr_t>(h_element_array.Get())) };
-  create_annotation_method->Invoke(self, args, sizeof(args), &result, "LLL");
-  if (self->IsExceptionPending()) {
-    LOG(INFO) << "Exception in AnnotationFactory.createAnnotation";
-    return nullptr;
-  }
-
-  return result.GetL();
-}
-
-const DexFile::AnnotationItem* DexFile::SearchAnnotationSet(const AnnotationSetItem* annotation_set,
-    const char* descriptor, uint32_t visibility) const {
-  const AnnotationItem* result = nullptr;
-  for (uint32_t i = 0; i < annotation_set->size_; ++i) {
-    const AnnotationItem* annotation_item = GetAnnotationItem(annotation_set, i);
-    if (!IsVisibilityCompatible(annotation_item->visibility_, visibility)) {
-      continue;
-    }
-    const uint8_t* annotation = annotation_item->annotation_;
-    uint32_t type_index = DecodeUnsignedLeb128(&annotation);
-
-    if (strcmp(descriptor, StringByTypeIdx(type_index)) == 0) {
-      result = annotation_item;
-      break;
-    }
-  }
-  return result;
-}
-
-const uint8_t* DexFile::SearchEncodedAnnotation(const uint8_t* annotation, const char* name) const {
-  DecodeUnsignedLeb128(&annotation);  // unused type_index
-  uint32_t size = DecodeUnsignedLeb128(&annotation);
-
-  while (size != 0) {
-    uint32_t element_name_index = DecodeUnsignedLeb128(&annotation);
-    const char* element_name = GetStringData(GetStringId(element_name_index));
-    if (strcmp(name, element_name) == 0) {
-      return annotation;
-    }
-    SkipAnnotationValue(&annotation);
-    size--;
-  }
-  return nullptr;
-}
-
-bool DexFile::SkipAnnotationValue(const uint8_t** annotation_ptr) const {
-  const uint8_t* annotation = *annotation_ptr;
-  uint8_t header_byte = *(annotation++);
-  uint8_t value_type = header_byte & kDexAnnotationValueTypeMask;
-  uint8_t value_arg = header_byte >> kDexAnnotationValueArgShift;
-  int32_t width = value_arg + 1;
-
-  switch (value_type) {
-    case kDexAnnotationByte:
-    case kDexAnnotationShort:
-    case kDexAnnotationChar:
-    case kDexAnnotationInt:
-    case kDexAnnotationLong:
-    case kDexAnnotationFloat:
-    case kDexAnnotationDouble:
-    case kDexAnnotationString:
-    case kDexAnnotationType:
-    case kDexAnnotationMethod:
-    case kDexAnnotationField:
-    case kDexAnnotationEnum:
-      break;
-    case kDexAnnotationArray:
-    {
-      uint32_t size = DecodeUnsignedLeb128(&annotation);
-      while (size--) {
-        if (!SkipAnnotationValue(&annotation)) {
-          return false;
-        }
-      }
-      width = 0;
-      break;
-    }
-    case kDexAnnotationAnnotation:
-    {
-      DecodeUnsignedLeb128(&annotation);  // unused type_index
-      uint32_t size = DecodeUnsignedLeb128(&annotation);
-      while (size--) {
-        DecodeUnsignedLeb128(&annotation);  // unused element_name_index
-        if (!SkipAnnotationValue(&annotation)) {
-          return false;
-        }
-      }
-      width = 0;
-      break;
-    }
-    case kDexAnnotationBoolean:
-    case kDexAnnotationNull:
-      width = 0;
-      break;
-    default:
-      LOG(FATAL) << StringPrintf("Bad annotation element value byte 0x%02x", value_type);
-      return false;
-  }
-
-  annotation += width;
-  *annotation_ptr = annotation;
-  return true;
-}
-
 std::ostream& operator<<(std::ostream& os, const DexFile& dex_file) {
   os << StringPrintf("[DexFile: %s dex-checksum=%08x location-checksum=%08x %p-%p]",
                      dex_file.GetLocation().c_str(),
@@ -2432,50 +1292,13 @@
   }
 }
 
-EncodedStaticFieldValueIterator::EncodedStaticFieldValueIterator(
-    const DexFile& dex_file,
-    const DexFile::ClassDef& class_def)
-    : EncodedStaticFieldValueIterator(dex_file,
-                                      nullptr,
-                                      nullptr,
-                                      nullptr,
-                                      class_def,
-                                      -1,
-                                      kByte) {
-}
-
-EncodedStaticFieldValueIterator::EncodedStaticFieldValueIterator(
-    const DexFile& dex_file,
-    Handle<mirror::DexCache>* dex_cache,
-    Handle<mirror::ClassLoader>* class_loader,
-    ClassLinker* linker,
-    const DexFile::ClassDef& class_def)
-    : EncodedStaticFieldValueIterator(dex_file,
-                                      dex_cache, class_loader,
-                                      linker,
-                                      class_def,
-                                      -1,
-                                      kByte) {
-  DCHECK(dex_cache_ != nullptr);
-  DCHECK(class_loader_ != nullptr);
-}
-
-EncodedStaticFieldValueIterator::EncodedStaticFieldValueIterator(
-    const DexFile& dex_file,
-    Handle<mirror::DexCache>* dex_cache,
-    Handle<mirror::ClassLoader>* class_loader,
-    ClassLinker* linker,
-    const DexFile::ClassDef& class_def,
-    size_t pos,
-    ValueType type)
+EncodedStaticFieldValueIterator::EncodedStaticFieldValueIterator(const DexFile& dex_file,
+                                                                 const DexFile::ClassDef& class_def)
     : dex_file_(dex_file),
-      dex_cache_(dex_cache),
-      class_loader_(class_loader),
-      linker_(linker),
       array_size_(),
-      pos_(pos),
-      type_(type) {
-  ptr_ = dex_file.GetEncodedStaticFieldValuesArray(class_def);
+      pos_(-1),
+      type_(kByte) {
+  ptr_ = dex_file_.GetEncodedStaticFieldValuesArray(class_def);
   if (ptr_ == nullptr) {
     array_size_ = 0;
   } else {
@@ -2501,32 +1324,32 @@
     width = 0;
     break;
   case kByte:
-    jval_.i = ReadSignedInt(ptr_, value_arg);
+    jval_.i = DexFile::ReadSignedInt(ptr_, value_arg);
     CHECK(IsInt<8>(jval_.i));
     break;
   case kShort:
-    jval_.i = ReadSignedInt(ptr_, value_arg);
+    jval_.i = DexFile::ReadSignedInt(ptr_, value_arg);
     CHECK(IsInt<16>(jval_.i));
     break;
   case kChar:
-    jval_.i = ReadUnsignedInt(ptr_, value_arg, false);
+    jval_.i = DexFile::ReadUnsignedInt(ptr_, value_arg, false);
     CHECK(IsUint<16>(jval_.i));
     break;
   case kInt:
-    jval_.i = ReadSignedInt(ptr_, value_arg);
+    jval_.i = DexFile::ReadSignedInt(ptr_, value_arg);
     break;
   case kLong:
-    jval_.j = ReadSignedLong(ptr_, value_arg);
+    jval_.j = DexFile::ReadSignedLong(ptr_, value_arg);
     break;
   case kFloat:
-    jval_.i = ReadUnsignedInt(ptr_, value_arg, true);
+    jval_.i = DexFile::ReadUnsignedInt(ptr_, value_arg, true);
     break;
   case kDouble:
-    jval_.j = ReadUnsignedLong(ptr_, value_arg, true);
+    jval_.j = DexFile::ReadUnsignedLong(ptr_, value_arg, true);
     break;
   case kString:
   case kType:
-    jval_.i = ReadUnsignedInt(ptr_, value_arg, false);
+    jval_.i = DexFile::ReadUnsignedInt(ptr_, value_arg, false);
     break;
   case kField:
   case kMethod:
@@ -2546,38 +1369,6 @@
   ptr_ += width;
 }
 
-template<bool kTransactionActive>
-void EncodedStaticFieldValueIterator::ReadValueToField(ArtField* field) const {
-  DCHECK(dex_cache_ != nullptr);
-  DCHECK(class_loader_ != nullptr);
-  switch (type_) {
-    case kBoolean: field->SetBoolean<kTransactionActive>(field->GetDeclaringClass(), jval_.z);
-        break;
-    case kByte:    field->SetByte<kTransactionActive>(field->GetDeclaringClass(), jval_.b); break;
-    case kShort:   field->SetShort<kTransactionActive>(field->GetDeclaringClass(), jval_.s); break;
-    case kChar:    field->SetChar<kTransactionActive>(field->GetDeclaringClass(), jval_.c); break;
-    case kInt:     field->SetInt<kTransactionActive>(field->GetDeclaringClass(), jval_.i); break;
-    case kLong:    field->SetLong<kTransactionActive>(field->GetDeclaringClass(), jval_.j); break;
-    case kFloat:   field->SetFloat<kTransactionActive>(field->GetDeclaringClass(), jval_.f); break;
-    case kDouble:  field->SetDouble<kTransactionActive>(field->GetDeclaringClass(), jval_.d); break;
-    case kNull:    field->SetObject<kTransactionActive>(field->GetDeclaringClass(), nullptr); break;
-    case kString: {
-      mirror::String* resolved = linker_->ResolveString(dex_file_, jval_.i, *dex_cache_);
-      field->SetObject<kTransactionActive>(field->GetDeclaringClass(), resolved);
-      break;
-    }
-    case kType: {
-      mirror::Class* resolved = linker_->ResolveType(dex_file_, jval_.i, *dex_cache_,
-                                                     *class_loader_);
-      field->SetObject<kTransactionActive>(field->GetDeclaringClass(), resolved);
-      break;
-    }
-    default: UNIMPLEMENTED(FATAL) << ": type " << type_;
-  }
-}
-template void EncodedStaticFieldValueIterator::ReadValueToField<true>(ArtField* field) const;
-template void EncodedStaticFieldValueIterator::ReadValueToField<false>(ArtField* field) const;
-
 CatchHandlerIterator::CatchHandlerIterator(const DexFile::CodeItem& code_item, uint32_t address) {
   handler_.address_ = -1;
   int32_t offset = -1;
diff --git a/runtime/dex_file.h b/runtime/dex_file.h
index ebbde0a..0ae36f7 100644
--- a/runtime/dex_file.h
+++ b/runtime/dex_file.h
@@ -27,27 +27,14 @@
 #include "globals.h"
 #include "invoke_type.h"
 #include "jni.h"
-#include "mirror/object_array.h"
 #include "modifiers.h"
 #include "utf.h"
 
 namespace art {
 
-// TODO: remove dependencies on mirror classes, primarily by moving
-// EncodedStaticFieldValueIterator to its own file.
-namespace mirror {
-  class ClassLoader;
-  class DexCache;
-}  // namespace mirror
-class ArtField;
-class ArtMethod;
-class ClassLinker;
-template <class Key, class Value, class EmptyFn, class HashFn, class Pred, class Alloc>
-class HashMap;
 class MemMap;
 class OatDexFile;
 class Signature;
-template<class T> class Handle;
 class StringPiece;
 class TypeLookupTable;
 class ZipArchive;
@@ -402,6 +389,8 @@
     kAllRaw
   };
 
+  struct AnnotationValue;
+
   // Returns the checksum of a file for comparison with GetLocationChecksum().
   // For .dex files, this is the header checksum.
   // For zip files, this is the classes.dex zip entry CRC32 checksum.
@@ -934,106 +923,6 @@
     return reinterpret_cast<const AnnotationSetItem*>(begin_ + offset);
   }
 
-  const AnnotationSetItem* FindAnnotationSetForField(ArtField* field) const
-      REQUIRES_SHARED(Locks::mutator_lock_);
-  mirror::Object* GetAnnotationForField(ArtField* field, Handle<mirror::Class> annotation_class)
-      const REQUIRES_SHARED(Locks::mutator_lock_);
-  mirror::ObjectArray<mirror::Object>* GetAnnotationsForField(ArtField* field) const
-      REQUIRES_SHARED(Locks::mutator_lock_);
-  mirror::ObjectArray<mirror::String>* GetSignatureAnnotationForField(ArtField* field) const
-      REQUIRES_SHARED(Locks::mutator_lock_);
-  bool IsFieldAnnotationPresent(ArtField* field, Handle<mirror::Class> annotation_class) const
-      REQUIRES_SHARED(Locks::mutator_lock_);
-
-  const AnnotationSetItem* FindAnnotationSetForMethod(ArtMethod* method) const
-      REQUIRES_SHARED(Locks::mutator_lock_);
-  const ParameterAnnotationsItem* FindAnnotationsItemForMethod(ArtMethod* method) const
-      REQUIRES_SHARED(Locks::mutator_lock_);
-  mirror::Object* GetAnnotationDefaultValue(ArtMethod* method) const
-      REQUIRES_SHARED(Locks::mutator_lock_);
-  mirror::Object* GetAnnotationForMethod(ArtMethod* method, Handle<mirror::Class> annotation_class)
-      const REQUIRES_SHARED(Locks::mutator_lock_);
-  mirror::ObjectArray<mirror::Object>* GetAnnotationsForMethod(ArtMethod* method) const
-      REQUIRES_SHARED(Locks::mutator_lock_);
-  mirror::ObjectArray<mirror::Class>* GetExceptionTypesForMethod(ArtMethod* method) const
-      REQUIRES_SHARED(Locks::mutator_lock_);
-  mirror::ObjectArray<mirror::Object>* GetParameterAnnotations(ArtMethod* method) const
-      REQUIRES_SHARED(Locks::mutator_lock_);
-  mirror::ObjectArray<mirror::String>* GetSignatureAnnotationForMethod(ArtMethod* method) const
-      REQUIRES_SHARED(Locks::mutator_lock_);
-  bool IsMethodAnnotationPresent(ArtMethod* method,
-                                 Handle<mirror::Class> annotation_class,
-                                 uint32_t visibility = kDexVisibilityRuntime) const
-      REQUIRES_SHARED(Locks::mutator_lock_);
-
-  const AnnotationSetItem* FindAnnotationSetForClass(Handle<mirror::Class> klass) const
-      REQUIRES_SHARED(Locks::mutator_lock_);
-  mirror::Object* GetAnnotationForClass(Handle<mirror::Class> klass,
-                                        Handle<mirror::Class> annotation_class) const
-      REQUIRES_SHARED(Locks::mutator_lock_);
-  mirror::ObjectArray<mirror::Object>* GetAnnotationsForClass(Handle<mirror::Class> klass) const
-      REQUIRES_SHARED(Locks::mutator_lock_);
-  mirror::ObjectArray<mirror::Class>* GetDeclaredClasses(Handle<mirror::Class> klass) const
-      REQUIRES_SHARED(Locks::mutator_lock_);
-  mirror::Class* GetDeclaringClass(Handle<mirror::Class> klass) const
-      REQUIRES_SHARED(Locks::mutator_lock_);
-  mirror::Class* GetEnclosingClass(Handle<mirror::Class> klass) const
-      REQUIRES_SHARED(Locks::mutator_lock_);
-  mirror::Object* GetEnclosingMethod(Handle<mirror::Class> klass) const
-      REQUIRES_SHARED(Locks::mutator_lock_);
-  bool GetInnerClass(Handle<mirror::Class> klass, mirror::String** name) const
-      REQUIRES_SHARED(Locks::mutator_lock_);
-  bool GetInnerClassFlags(Handle<mirror::Class> klass, uint32_t* flags) const
-      REQUIRES_SHARED(Locks::mutator_lock_);
-  mirror::ObjectArray<mirror::String>* GetSignatureAnnotationForClass(Handle<mirror::Class> klass)
-      const REQUIRES_SHARED(Locks::mutator_lock_);
-  bool IsClassAnnotationPresent(Handle<mirror::Class> klass, Handle<mirror::Class> annotation_class)
-      const REQUIRES_SHARED(Locks::mutator_lock_);
-
-  mirror::Object* CreateAnnotationMember(Handle<mirror::Class> klass,
-                                         Handle<mirror::Class> annotation_class,
-                                         const uint8_t** annotation) const
-      REQUIRES_SHARED(Locks::mutator_lock_);
-  const AnnotationItem* GetAnnotationItemFromAnnotationSet(Handle<mirror::Class> klass,
-                                                           const AnnotationSetItem* annotation_set,
-                                                           uint32_t visibility,
-                                                           Handle<mirror::Class> annotation_class)
-      const REQUIRES_SHARED(Locks::mutator_lock_);
-  mirror::Object* GetAnnotationObjectFromAnnotationSet(Handle<mirror::Class> klass,
-                                                       const AnnotationSetItem* annotation_set,
-                                                       uint32_t visibility,
-                                                       Handle<mirror::Class> annotation_class) const
-      REQUIRES_SHARED(Locks::mutator_lock_);
-  mirror::Object* GetAnnotationValue(Handle<mirror::Class> klass,
-                                     const AnnotationItem* annotation_item,
-                                     const char* annotation_name,
-                                     Handle<mirror::Class> array_class,
-                                     uint32_t expected_type) const
-      REQUIRES_SHARED(Locks::mutator_lock_);
-  mirror::ObjectArray<mirror::String>* GetSignatureValue(Handle<mirror::Class> klass,
-                                                         const AnnotationSetItem* annotation_set)
-      const REQUIRES_SHARED(Locks::mutator_lock_);
-  mirror::ObjectArray<mirror::Class>* GetThrowsValue(Handle<mirror::Class> klass,
-                                                     const AnnotationSetItem* annotation_set) const
-      REQUIRES_SHARED(Locks::mutator_lock_);
-  mirror::ObjectArray<mirror::Object>* ProcessAnnotationSet(Handle<mirror::Class> klass,
-                                                            const AnnotationSetItem* annotation_set,
-                                                            uint32_t visibility) const
-      REQUIRES_SHARED(Locks::mutator_lock_);
-  mirror::ObjectArray<mirror::Object>* ProcessAnnotationSetRefList(Handle<mirror::Class> klass,
-      const AnnotationSetRefList* set_ref_list, uint32_t size) const
-      REQUIRES_SHARED(Locks::mutator_lock_);
-  mirror::Object* ProcessEncodedAnnotation(Handle<mirror::Class> klass,
-                                           const uint8_t** annotation) const
-      REQUIRES_SHARED(Locks::mutator_lock_);
-  const AnnotationItem* SearchAnnotationSet(const AnnotationSetItem* annotation_set,
-                                            const char* descriptor, uint32_t visibility) const
-      REQUIRES_SHARED(Locks::mutator_lock_);
-  const uint8_t* SearchEncodedAnnotation(const uint8_t* annotation, const char* name) const
-      REQUIRES_SHARED(Locks::mutator_lock_);
-  bool SkipAnnotationValue(const uint8_t** annotation_ptr) const
-      REQUIRES_SHARED(Locks::mutator_lock_);
-
   // Debug info opcodes and constants
   enum {
     DBG_END_SEQUENCE         = 0x00,
@@ -1060,17 +949,6 @@
     DISALLOW_COPY_AND_ASSIGN(LineNumFromPcContext);
   };
 
-  // Determine the source file line number based on the program counter.
-  // "pc" is an offset, in 16-bit units, from the start of the method's code.
-  //
-  // Returns -1 if no match was found (possibly because the source files were
-  // compiled without "-g", so no line number information is present).
-  // Returns -2 for native methods (as expected in exception traces).
-  //
-  // This is used by runtime; therefore use art::Method not art::DexFile::Method.
-  int32_t GetLineNumFromPC(ArtMethod* method, uint32_t rel_pc) const
-      REQUIRES_SHARED(Locks::mutator_lock_);
-
   // Returns false if there is no debugging information or if it cannot be decoded.
   bool DecodeDebugLocalInfo(const CodeItem* code_item, bool is_static, uint32_t method_idx,
                             DexDebugNewLocalCb local_cb, void* context) const;
@@ -1136,6 +1014,12 @@
 
   void CreateTypeLookupTable(uint8_t* storage = nullptr) const;
 
+  // Utility methods for reading integral values from a buffer.
+  static int32_t ReadSignedInt(const uint8_t* ptr, int zwidth);
+  static uint32_t ReadUnsignedInt(const uint8_t* ptr, int zwidth, bool fill_on_right);
+  static int64_t ReadSignedLong(const uint8_t* ptr, int zwidth);
+  static uint64_t ReadUnsignedLong(const uint8_t* ptr, int zwidth, bool fill_on_right);
+
  private:
   // Opens a .dex file
   static std::unique_ptr<const DexFile> OpenFile(int fd,
@@ -1200,13 +1084,6 @@
   // whether the string contains the separator character.
   static bool IsMultiDexLocation(const char* location);
 
-  struct AnnotationValue;
-
-  bool ProcessAnnotationValue(Handle<mirror::Class> klass, const uint8_t** annotation_ptr,
-                              AnnotationValue* annotation_value, Handle<mirror::Class> return_class,
-                              DexFile::AnnotationResultStyle result_style) const
-      REQUIRES_SHARED(Locks::mutator_lock_);
-
   // The base address of the memory mapping.
   const uint8_t* const begin_;
 
@@ -1510,22 +1387,9 @@
 
 class EncodedStaticFieldValueIterator {
  public:
-  // A constructor for static tools. You cannot call
-  // ReadValueToField() for an object created by this.
   EncodedStaticFieldValueIterator(const DexFile& dex_file,
                                   const DexFile::ClassDef& class_def);
 
-  // A constructor meant to be called from runtime code.
-  EncodedStaticFieldValueIterator(const DexFile& dex_file,
-                                  Handle<mirror::DexCache>* dex_cache,
-                                  Handle<mirror::ClassLoader>* class_loader,
-                                  ClassLinker* linker,
-                                  const DexFile::ClassDef& class_def)
-      REQUIRES_SHARED(Locks::mutator_lock_);
-
-  template<bool kTransactionActive>
-  void ReadValueToField(ArtField* field) const REQUIRES_SHARED(Locks::mutator_lock_);
-
   bool HasNext() const { return pos_ < array_size_; }
 
   void Next();
@@ -1552,27 +1416,18 @@
   ValueType GetValueType() const { return type_; }
   const jvalue& GetJavaValue() const { return jval_; }
 
- private:
-  EncodedStaticFieldValueIterator(const DexFile& dex_file,
-                                  Handle<mirror::DexCache>* dex_cache,
-                                  Handle<mirror::ClassLoader>* class_loader,
-                                  ClassLinker* linker,
-                                  const DexFile::ClassDef& class_def,
-                                  size_t pos,
-                                  ValueType type);
-
+ protected:
   static constexpr uint8_t kEncodedValueTypeMask = 0x1f;  // 0b11111
   static constexpr uint8_t kEncodedValueArgShift = 5;
 
   const DexFile& dex_file_;
-  Handle<mirror::DexCache>* const dex_cache_;  // Dex cache to resolve literal objects.
-  Handle<mirror::ClassLoader>* const class_loader_;  // ClassLoader to resolve types.
-  ClassLinker* linker_;  // Linker to resolve literal objects.
   size_t array_size_;  // Size of array.
   size_t pos_;  // Current position.
   const uint8_t* ptr_;  // Pointer into encoded data array.
   ValueType type_;  // Type of current encoded value.
   jvalue jval_;  // Value of current encoded value.
+
+ private:
   DISALLOW_IMPLICIT_CONSTRUCTORS(EncodedStaticFieldValueIterator);
 };
 std::ostream& operator<<(std::ostream& os, const EncodedStaticFieldValueIterator::ValueType& code);
diff --git a/runtime/dex_file_annotations.cc b/runtime/dex_file_annotations.cc
new file mode 100644
index 0000000..c6c87fd
--- /dev/null
+++ b/runtime/dex_file_annotations.cc
@@ -0,0 +1,1303 @@
+/*
+ * 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 "dex_file_annotations.h"
+
+#include <stdlib.h>
+
+#include "art_field-inl.h"
+#include "art_method-inl.h"
+#include "class_linker-inl.h"
+#include "dex_file-inl.h"
+#include "jvalue.h"
+#include "mirror/field.h"
+#include "mirror/method.h"
+#include "reflection.h"
+#include "thread.h"
+
+namespace art {
+
+struct DexFile::AnnotationValue {
+  JValue value_;
+  uint8_t type_;
+};
+
+namespace {
+mirror::Object* CreateAnnotationMember(Handle<mirror::Class> klass,
+                                       Handle<mirror::Class> annotation_class,
+                                       const uint8_t** annotation)
+    REQUIRES_SHARED(Locks::mutator_lock_);
+
+bool IsVisibilityCompatible(uint32_t actual, uint32_t expected) {
+  if (expected == DexFile::kDexVisibilityRuntime) {
+    int32_t sdk_version = Runtime::Current()->GetTargetSdkVersion();
+    if (sdk_version > 0 && sdk_version <= 23) {
+      return actual == DexFile::kDexVisibilityRuntime || actual == DexFile::kDexVisibilityBuild;
+    }
+  }
+  return actual == expected;
+}
+
+const DexFile::AnnotationSetItem* FindAnnotationSetForField(ArtField* field)
+    REQUIRES_SHARED(Locks::mutator_lock_) {
+  const DexFile* dex_file = field->GetDexFile();
+  mirror::Class* klass = field->GetDeclaringClass();
+  const DexFile::AnnotationsDirectoryItem* annotations_dir =
+      dex_file->GetAnnotationsDirectory(*klass->GetClassDef());
+  if (annotations_dir == nullptr) {
+    return nullptr;
+  }
+  const DexFile::FieldAnnotationsItem* field_annotations =
+      dex_file->GetFieldAnnotations(annotations_dir);
+  if (field_annotations == nullptr) {
+    return nullptr;
+  }
+  uint32_t field_index = field->GetDexFieldIndex();
+  uint32_t field_count = annotations_dir->fields_size_;
+  for (uint32_t i = 0; i < field_count; ++i) {
+    if (field_annotations[i].field_idx_ == field_index) {
+      return dex_file->GetFieldAnnotationSetItem(field_annotations[i]);
+    }
+  }
+  return nullptr;
+}
+
+const DexFile::AnnotationItem* SearchAnnotationSet(const DexFile& dex_file,
+                                                   const DexFile::AnnotationSetItem* annotation_set,
+                                                   const char* descriptor,
+                                                   uint32_t visibility)
+    REQUIRES_SHARED(Locks::mutator_lock_) {
+  const DexFile::AnnotationItem* result = nullptr;
+  for (uint32_t i = 0; i < annotation_set->size_; ++i) {
+    const DexFile::AnnotationItem* annotation_item = dex_file.GetAnnotationItem(annotation_set, i);
+    if (!IsVisibilityCompatible(annotation_item->visibility_, visibility)) {
+      continue;
+    }
+    const uint8_t* annotation = annotation_item->annotation_;
+    uint32_t type_index = DecodeUnsignedLeb128(&annotation);
+
+    if (strcmp(descriptor, dex_file.StringByTypeIdx(type_index)) == 0) {
+      result = annotation_item;
+      break;
+    }
+  }
+  return result;
+}
+
+bool SkipAnnotationValue(const DexFile& dex_file, const uint8_t** annotation_ptr)
+    REQUIRES_SHARED(Locks::mutator_lock_) {
+  const uint8_t* annotation = *annotation_ptr;
+  uint8_t header_byte = *(annotation++);
+  uint8_t value_type = header_byte & DexFile::kDexAnnotationValueTypeMask;
+  uint8_t value_arg = header_byte >> DexFile::kDexAnnotationValueArgShift;
+  int32_t width = value_arg + 1;
+
+  switch (value_type) {
+    case DexFile::kDexAnnotationByte:
+    case DexFile::kDexAnnotationShort:
+    case DexFile::kDexAnnotationChar:
+    case DexFile::kDexAnnotationInt:
+    case DexFile::kDexAnnotationLong:
+    case DexFile::kDexAnnotationFloat:
+    case DexFile::kDexAnnotationDouble:
+    case DexFile::kDexAnnotationString:
+    case DexFile::kDexAnnotationType:
+    case DexFile::kDexAnnotationMethod:
+    case DexFile::kDexAnnotationField:
+    case DexFile::kDexAnnotationEnum:
+      break;
+    case DexFile::kDexAnnotationArray:
+    {
+      uint32_t size = DecodeUnsignedLeb128(&annotation);
+      while (size--) {
+        if (!SkipAnnotationValue(dex_file, &annotation)) {
+          return false;
+        }
+      }
+      width = 0;
+      break;
+    }
+    case DexFile::kDexAnnotationAnnotation:
+    {
+      DecodeUnsignedLeb128(&annotation);  // unused type_index
+      uint32_t size = DecodeUnsignedLeb128(&annotation);
+      while (size--) {
+        DecodeUnsignedLeb128(&annotation);  // unused element_name_index
+        if (!SkipAnnotationValue(dex_file, &annotation)) {
+          return false;
+        }
+      }
+      width = 0;
+      break;
+    }
+    case DexFile::kDexAnnotationBoolean:
+    case DexFile::kDexAnnotationNull:
+      width = 0;
+      break;
+    default:
+      LOG(FATAL) << StringPrintf("Bad annotation element value byte 0x%02x", value_type);
+      return false;
+  }
+
+  annotation += width;
+  *annotation_ptr = annotation;
+  return true;
+}
+
+const uint8_t* SearchEncodedAnnotation(const DexFile& dex_file,
+                                       const uint8_t* annotation,
+                                       const char* name)
+    REQUIRES_SHARED(Locks::mutator_lock_) {
+  DecodeUnsignedLeb128(&annotation);  // unused type_index
+  uint32_t size = DecodeUnsignedLeb128(&annotation);
+
+  while (size != 0) {
+    uint32_t element_name_index = DecodeUnsignedLeb128(&annotation);
+    const char* element_name = dex_file.GetStringData(dex_file.GetStringId(element_name_index));
+    if (strcmp(name, element_name) == 0) {
+      return annotation;
+    }
+    SkipAnnotationValue(dex_file, &annotation);
+    size--;
+  }
+  return nullptr;
+}
+
+const DexFile::AnnotationSetItem* FindAnnotationSetForMethod(ArtMethod* method)
+    REQUIRES_SHARED(Locks::mutator_lock_) {
+  const DexFile* dex_file = method->GetDexFile();
+  mirror::Class* klass = method->GetDeclaringClass();
+  const DexFile::AnnotationsDirectoryItem* annotations_dir =
+      dex_file->GetAnnotationsDirectory(*klass->GetClassDef());
+  if (annotations_dir == nullptr) {
+    return nullptr;
+  }
+  const DexFile::MethodAnnotationsItem* method_annotations =
+      dex_file->GetMethodAnnotations(annotations_dir);
+  if (method_annotations == nullptr) {
+    return nullptr;
+  }
+  uint32_t method_index = method->GetDexMethodIndex();
+  uint32_t method_count = annotations_dir->methods_size_;
+  for (uint32_t i = 0; i < method_count; ++i) {
+    if (method_annotations[i].method_idx_ == method_index) {
+      return dex_file->GetMethodAnnotationSetItem(method_annotations[i]);
+    }
+  }
+  return nullptr;
+}
+
+const DexFile::ParameterAnnotationsItem* FindAnnotationsItemForMethod(ArtMethod* method)
+    REQUIRES_SHARED(Locks::mutator_lock_) {
+  const DexFile* dex_file = method->GetDexFile();
+  mirror::Class* klass = method->GetDeclaringClass();
+  const DexFile::AnnotationsDirectoryItem* annotations_dir =
+      dex_file->GetAnnotationsDirectory(*klass->GetClassDef());
+  if (annotations_dir == nullptr) {
+    return nullptr;
+  }
+  const DexFile::ParameterAnnotationsItem* parameter_annotations =
+      dex_file->GetParameterAnnotations(annotations_dir);
+  if (parameter_annotations == nullptr) {
+    return nullptr;
+  }
+  uint32_t method_index = method->GetDexMethodIndex();
+  uint32_t parameter_count = annotations_dir->parameters_size_;
+  for (uint32_t i = 0; i < parameter_count; ++i) {
+    if (parameter_annotations[i].method_idx_ == method_index) {
+      return &parameter_annotations[i];
+    }
+  }
+  return nullptr;
+}
+
+const DexFile::AnnotationSetItem* FindAnnotationSetForClass(Handle<mirror::Class> klass)
+    REQUIRES_SHARED(Locks::mutator_lock_) {
+  const DexFile& dex_file = klass->GetDexFile();
+  const DexFile::AnnotationsDirectoryItem* annotations_dir =
+      dex_file.GetAnnotationsDirectory(*klass->GetClassDef());
+  if (annotations_dir == nullptr) {
+    return nullptr;
+  }
+  return dex_file.GetClassAnnotationSet(annotations_dir);
+}
+
+mirror::Object* ProcessEncodedAnnotation(Handle<mirror::Class> klass, const uint8_t** annotation)
+    REQUIRES_SHARED(Locks::mutator_lock_) {
+  uint32_t type_index = DecodeUnsignedLeb128(annotation);
+  uint32_t size = DecodeUnsignedLeb128(annotation);
+
+  Thread* self = Thread::Current();
+  ScopedObjectAccessUnchecked soa(self);
+  StackHandleScope<2> hs(self);
+  ClassLinker* class_linker = Runtime::Current()->GetClassLinker();
+  Handle<mirror::Class> annotation_class(hs.NewHandle(
+      class_linker->ResolveType(klass->GetDexFile(), type_index, klass.Get())));
+  if (annotation_class.Get() == nullptr) {
+    LOG(INFO) << "Unable to resolve " << PrettyClass(klass.Get()) << " annotation class "
+              << type_index;
+    DCHECK(Thread::Current()->IsExceptionPending());
+    Thread::Current()->ClearException();
+    return nullptr;
+  }
+
+  mirror::Class* annotation_member_class =
+      soa.Decode<mirror::Class*>(WellKnownClasses::libcore_reflect_AnnotationMember);
+  mirror::Class* annotation_member_array_class =
+      class_linker->FindArrayClass(self, &annotation_member_class);
+  if (annotation_member_array_class == nullptr) {
+    return nullptr;
+  }
+  mirror::ObjectArray<mirror::Object>* element_array = nullptr;
+  if (size > 0) {
+    element_array =
+        mirror::ObjectArray<mirror::Object>::Alloc(self, annotation_member_array_class, size);
+    if (element_array == nullptr) {
+      LOG(ERROR) << "Failed to allocate annotation member array (" << size << " elements)";
+      return nullptr;
+    }
+  }
+
+  Handle<mirror::ObjectArray<mirror::Object>> h_element_array(hs.NewHandle(element_array));
+  for (uint32_t i = 0; i < size; ++i) {
+    mirror::Object* new_member = CreateAnnotationMember(klass, annotation_class, annotation);
+    if (new_member == nullptr) {
+      return nullptr;
+    }
+    h_element_array->SetWithoutChecks<false>(i, new_member);
+  }
+
+  JValue result;
+  ArtMethod* create_annotation_method =
+      soa.DecodeMethod(WellKnownClasses::libcore_reflect_AnnotationFactory_createAnnotation);
+  uint32_t args[2] = { static_cast<uint32_t>(reinterpret_cast<uintptr_t>(annotation_class.Get())),
+                       static_cast<uint32_t>(reinterpret_cast<uintptr_t>(h_element_array.Get())) };
+  create_annotation_method->Invoke(self, args, sizeof(args), &result, "LLL");
+  if (self->IsExceptionPending()) {
+    LOG(INFO) << "Exception in AnnotationFactory.createAnnotation";
+    return nullptr;
+  }
+
+  return result.GetL();
+}
+
+bool ProcessAnnotationValue(Handle<mirror::Class> klass,
+                            const uint8_t** annotation_ptr,
+                            DexFile::AnnotationValue* annotation_value,
+                            Handle<mirror::Class> array_class,
+                            DexFile::AnnotationResultStyle result_style)
+    REQUIRES_SHARED(Locks::mutator_lock_) {
+  const DexFile& dex_file = klass->GetDexFile();
+  Thread* self = Thread::Current();
+  mirror::Object* element_object = nullptr;
+  bool set_object = false;
+  Primitive::Type primitive_type = Primitive::kPrimVoid;
+  const uint8_t* annotation = *annotation_ptr;
+  uint8_t header_byte = *(annotation++);
+  uint8_t value_type = header_byte & DexFile::kDexAnnotationValueTypeMask;
+  uint8_t value_arg = header_byte >> DexFile::kDexAnnotationValueArgShift;
+  int32_t width = value_arg + 1;
+  annotation_value->type_ = value_type;
+
+  switch (value_type) {
+    case DexFile::kDexAnnotationByte:
+      annotation_value->value_.SetB(
+          static_cast<int8_t>(DexFile::ReadSignedInt(annotation, value_arg)));
+      primitive_type = Primitive::kPrimByte;
+      break;
+    case DexFile::kDexAnnotationShort:
+      annotation_value->value_.SetS(
+          static_cast<int16_t>(DexFile::ReadSignedInt(annotation, value_arg)));
+      primitive_type = Primitive::kPrimShort;
+      break;
+    case DexFile::kDexAnnotationChar:
+      annotation_value->value_.SetC(
+          static_cast<uint16_t>(DexFile::ReadUnsignedInt(annotation, value_arg, false)));
+      primitive_type = Primitive::kPrimChar;
+      break;
+    case DexFile::kDexAnnotationInt:
+      annotation_value->value_.SetI(DexFile::ReadSignedInt(annotation, value_arg));
+      primitive_type = Primitive::kPrimInt;
+      break;
+    case DexFile::kDexAnnotationLong:
+      annotation_value->value_.SetJ(DexFile::ReadSignedLong(annotation, value_arg));
+      primitive_type = Primitive::kPrimLong;
+      break;
+    case DexFile::kDexAnnotationFloat:
+      annotation_value->value_.SetI(DexFile::ReadUnsignedInt(annotation, value_arg, true));
+      primitive_type = Primitive::kPrimFloat;
+      break;
+    case DexFile::kDexAnnotationDouble:
+      annotation_value->value_.SetJ(DexFile::ReadUnsignedLong(annotation, value_arg, true));
+      primitive_type = Primitive::kPrimDouble;
+      break;
+    case DexFile::kDexAnnotationBoolean:
+      annotation_value->value_.SetZ(value_arg != 0);
+      primitive_type = Primitive::kPrimBoolean;
+      width = 0;
+      break;
+    case DexFile::kDexAnnotationString: {
+      uint32_t index = DexFile::ReadUnsignedInt(annotation, value_arg, false);
+      if (result_style == DexFile::kAllRaw) {
+        annotation_value->value_.SetI(index);
+      } else {
+        StackHandleScope<1> hs(self);
+        Handle<mirror::DexCache> dex_cache(hs.NewHandle(klass->GetDexCache()));
+        element_object = Runtime::Current()->GetClassLinker()->ResolveString(
+            klass->GetDexFile(), index, dex_cache);
+        set_object = true;
+        if (element_object == nullptr) {
+          return false;
+        }
+      }
+      break;
+    }
+    case DexFile::kDexAnnotationType: {
+      uint32_t index = DexFile::ReadUnsignedInt(annotation, value_arg, false);
+      if (result_style == DexFile::kAllRaw) {
+        annotation_value->value_.SetI(index);
+      } else {
+        element_object = Runtime::Current()->GetClassLinker()->ResolveType(
+            klass->GetDexFile(), index, klass.Get());
+        set_object = true;
+        if (element_object == nullptr) {
+          CHECK(self->IsExceptionPending());
+          if (result_style == DexFile::kAllObjects) {
+            const char* msg = dex_file.StringByTypeIdx(index);
+            self->ThrowNewWrappedException("Ljava/lang/TypeNotPresentException;", msg);
+            element_object = self->GetException();
+            self->ClearException();
+          } else {
+            return false;
+          }
+        }
+      }
+      break;
+    }
+    case DexFile::kDexAnnotationMethod: {
+      uint32_t index = DexFile::ReadUnsignedInt(annotation, value_arg, false);
+      if (result_style == DexFile::kAllRaw) {
+        annotation_value->value_.SetI(index);
+      } else {
+        StackHandleScope<2> hs(self);
+        Handle<mirror::DexCache> dex_cache(hs.NewHandle(klass->GetDexCache()));
+        Handle<mirror::ClassLoader> class_loader(hs.NewHandle(klass->GetClassLoader()));
+        ClassLinker* class_linker = Runtime::Current()->GetClassLinker();
+        ArtMethod* method = class_linker->ResolveMethodWithoutInvokeType(
+            klass->GetDexFile(), index, dex_cache, class_loader);
+        if (method == nullptr) {
+          return false;
+        }
+        PointerSize pointer_size = class_linker->GetImagePointerSize();
+        set_object = true;
+        DCHECK(!Runtime::Current()->IsActiveTransaction());
+        if (method->IsConstructor()) {
+          if (pointer_size == PointerSize::k64) {
+            element_object = mirror::Constructor::CreateFromArtMethod<PointerSize::k64,
+                                                                      false>(self, method);
+          } else {
+            element_object = mirror::Constructor::CreateFromArtMethod<PointerSize::k32,
+                                                                      false>(self, method);
+          }
+        } else {
+          if (pointer_size == PointerSize::k64) {
+            element_object = mirror::Method::CreateFromArtMethod<PointerSize::k64,
+                                                                 false>(self, method);
+          } else {
+            element_object = mirror::Method::CreateFromArtMethod<PointerSize::k32,
+                                                                 false>(self, method);
+          }
+        }
+        if (element_object == nullptr) {
+          return false;
+        }
+      }
+      break;
+    }
+    case DexFile::kDexAnnotationField: {
+      uint32_t index = DexFile::ReadUnsignedInt(annotation, value_arg, false);
+      if (result_style == DexFile::kAllRaw) {
+        annotation_value->value_.SetI(index);
+      } else {
+        StackHandleScope<2> hs(self);
+        Handle<mirror::DexCache> dex_cache(hs.NewHandle(klass->GetDexCache()));
+        Handle<mirror::ClassLoader> class_loader(hs.NewHandle(klass->GetClassLoader()));
+        ArtField* field = Runtime::Current()->GetClassLinker()->ResolveFieldJLS(
+            klass->GetDexFile(), index, dex_cache, class_loader);
+        if (field == nullptr) {
+          return false;
+        }
+        set_object = true;
+        PointerSize pointer_size = Runtime::Current()->GetClassLinker()->GetImagePointerSize();
+        if (pointer_size == PointerSize::k64) {
+          element_object = mirror::Field::CreateFromArtField<PointerSize::k64>(self, field, true);
+        } else {
+          element_object = mirror::Field::CreateFromArtField<PointerSize::k32>(self, field, true);
+        }
+        if (element_object == nullptr) {
+          return false;
+        }
+      }
+      break;
+    }
+    case DexFile::kDexAnnotationEnum: {
+      uint32_t index = DexFile::ReadUnsignedInt(annotation, value_arg, false);
+      if (result_style == DexFile::kAllRaw) {
+        annotation_value->value_.SetI(index);
+      } else {
+        StackHandleScope<3> hs(self);
+        Handle<mirror::DexCache> dex_cache(hs.NewHandle(klass->GetDexCache()));
+        Handle<mirror::ClassLoader> class_loader(hs.NewHandle(klass->GetClassLoader()));
+        ArtField* enum_field = Runtime::Current()->GetClassLinker()->ResolveField(
+            klass->GetDexFile(), index, dex_cache, class_loader, true);
+        if (enum_field == nullptr) {
+          return false;
+        } else {
+          Handle<mirror::Class> field_class(hs.NewHandle(enum_field->GetDeclaringClass()));
+          Runtime::Current()->GetClassLinker()->EnsureInitialized(self, field_class, true, true);
+          element_object = enum_field->GetObject(field_class.Get());
+          set_object = true;
+        }
+      }
+      break;
+    }
+    case DexFile::kDexAnnotationArray:
+      if (result_style == DexFile::kAllRaw || array_class.Get() == nullptr) {
+        return false;
+      } else {
+        ScopedObjectAccessUnchecked soa(self);
+        StackHandleScope<2> hs(self);
+        uint32_t size = DecodeUnsignedLeb128(&annotation);
+        Handle<mirror::Class> component_type(hs.NewHandle(array_class->GetComponentType()));
+        Handle<mirror::Array> new_array(hs.NewHandle(mirror::Array::Alloc<true>(
+            self, array_class.Get(), size, array_class->GetComponentSizeShift(),
+            Runtime::Current()->GetHeap()->GetCurrentAllocator())));
+        if (new_array.Get() == nullptr) {
+          LOG(ERROR) << "Annotation element array allocation failed with size " << size;
+          return false;
+        }
+        DexFile::AnnotationValue new_annotation_value;
+        for (uint32_t i = 0; i < size; ++i) {
+          if (!ProcessAnnotationValue(klass, &annotation, &new_annotation_value,
+                                      component_type, DexFile::kPrimitivesOrObjects)) {
+            return false;
+          }
+          if (!component_type->IsPrimitive()) {
+            mirror::Object* obj = new_annotation_value.value_.GetL();
+            new_array->AsObjectArray<mirror::Object>()->SetWithoutChecks<false>(i, obj);
+          } else {
+            switch (new_annotation_value.type_) {
+              case DexFile::kDexAnnotationByte:
+                new_array->AsByteArray()->SetWithoutChecks<false>(
+                    i, new_annotation_value.value_.GetB());
+                break;
+              case DexFile::kDexAnnotationShort:
+                new_array->AsShortArray()->SetWithoutChecks<false>(
+                    i, new_annotation_value.value_.GetS());
+                break;
+              case DexFile::kDexAnnotationChar:
+                new_array->AsCharArray()->SetWithoutChecks<false>(
+                    i, new_annotation_value.value_.GetC());
+                break;
+              case DexFile::kDexAnnotationInt:
+                new_array->AsIntArray()->SetWithoutChecks<false>(
+                    i, new_annotation_value.value_.GetI());
+                break;
+              case DexFile::kDexAnnotationLong:
+                new_array->AsLongArray()->SetWithoutChecks<false>(
+                    i, new_annotation_value.value_.GetJ());
+                break;
+              case DexFile::kDexAnnotationFloat:
+                new_array->AsFloatArray()->SetWithoutChecks<false>(
+                    i, new_annotation_value.value_.GetF());
+                break;
+              case DexFile::kDexAnnotationDouble:
+                new_array->AsDoubleArray()->SetWithoutChecks<false>(
+                    i, new_annotation_value.value_.GetD());
+                break;
+              case DexFile::kDexAnnotationBoolean:
+                new_array->AsBooleanArray()->SetWithoutChecks<false>(
+                    i, new_annotation_value.value_.GetZ());
+                break;
+              default:
+                LOG(FATAL) << "Found invalid annotation value type while building annotation array";
+                return false;
+            }
+          }
+        }
+        element_object = new_array.Get();
+        set_object = true;
+        width = 0;
+      }
+      break;
+    case DexFile::kDexAnnotationAnnotation:
+      if (result_style == DexFile::kAllRaw) {
+        return false;
+      }
+      element_object = ProcessEncodedAnnotation(klass, &annotation);
+      if (element_object == nullptr) {
+        return false;
+      }
+      set_object = true;
+      width = 0;
+      break;
+    case DexFile::kDexAnnotationNull:
+      if (result_style == DexFile::kAllRaw) {
+        annotation_value->value_.SetI(0);
+      } else {
+        CHECK(element_object == nullptr);
+        set_object = true;
+      }
+      width = 0;
+      break;
+    default:
+      LOG(ERROR) << StringPrintf("Bad annotation element value type 0x%02x", value_type);
+      return false;
+  }
+
+  annotation += width;
+  *annotation_ptr = annotation;
+
+  if (result_style == DexFile::kAllObjects && primitive_type != Primitive::kPrimVoid) {
+    element_object = BoxPrimitive(primitive_type, annotation_value->value_);
+    set_object = true;
+  }
+
+  if (set_object) {
+    annotation_value->value_.SetL(element_object);
+  }
+
+  return true;
+}
+
+mirror::Object* CreateAnnotationMember(Handle<mirror::Class> klass,
+                                       Handle<mirror::Class> annotation_class,
+                                       const uint8_t** annotation) {
+  const DexFile& dex_file = klass->GetDexFile();
+  Thread* self = Thread::Current();
+  ScopedObjectAccessUnchecked soa(self);
+  StackHandleScope<5> hs(self);
+  uint32_t element_name_index = DecodeUnsignedLeb128(annotation);
+  const char* name = dex_file.StringDataByIdx(element_name_index);
+  Handle<mirror::String> string_name(
+      hs.NewHandle(mirror::String::AllocFromModifiedUtf8(self, name)));
+
+  PointerSize pointer_size = Runtime::Current()->GetClassLinker()->GetImagePointerSize();
+  ArtMethod* annotation_method =
+      annotation_class->FindDeclaredVirtualMethodByName(name, pointer_size);
+  if (annotation_method == nullptr) {
+    return nullptr;
+  }
+  Handle<mirror::Class> method_return(hs.NewHandle(
+      annotation_method->GetReturnType(true /* resolve */, pointer_size)));
+
+  DexFile::AnnotationValue annotation_value;
+  if (!ProcessAnnotationValue(klass, annotation, &annotation_value, method_return,
+                              DexFile::kAllObjects)) {
+    return nullptr;
+  }
+  Handle<mirror::Object> value_object(hs.NewHandle(annotation_value.value_.GetL()));
+
+  mirror::Class* annotation_member_class =
+      WellKnownClasses::ToClass(WellKnownClasses::libcore_reflect_AnnotationMember);
+  Handle<mirror::Object> new_member(hs.NewHandle(annotation_member_class->AllocObject(self)));
+  mirror::Method* method_obj_ptr;
+  DCHECK(!Runtime::Current()->IsActiveTransaction());
+  if (pointer_size == PointerSize::k64) {
+    method_obj_ptr = mirror::Method::CreateFromArtMethod<PointerSize::k64, false>(
+        self, annotation_method);
+  } else {
+    method_obj_ptr = mirror::Method::CreateFromArtMethod<PointerSize::k32, false>(
+        self, annotation_method);
+  }
+  Handle<mirror::Method> method_object(hs.NewHandle(method_obj_ptr));
+
+  if (new_member.Get() == nullptr || string_name.Get() == nullptr ||
+      method_object.Get() == nullptr || method_return.Get() == nullptr) {
+    LOG(ERROR) << StringPrintf("Failed creating annotation element (m=%p n=%p a=%p r=%p",
+        new_member.Get(), string_name.Get(), method_object.Get(), method_return.Get());
+    return nullptr;
+  }
+
+  JValue result;
+  ArtMethod* annotation_member_init =
+      soa.DecodeMethod(WellKnownClasses::libcore_reflect_AnnotationMember_init);
+  uint32_t args[5] = { static_cast<uint32_t>(reinterpret_cast<uintptr_t>(new_member.Get())),
+                       static_cast<uint32_t>(reinterpret_cast<uintptr_t>(string_name.Get())),
+                       static_cast<uint32_t>(reinterpret_cast<uintptr_t>(value_object.Get())),
+                       static_cast<uint32_t>(reinterpret_cast<uintptr_t>(method_return.Get())),
+                       static_cast<uint32_t>(reinterpret_cast<uintptr_t>(method_object.Get()))
+  };
+  annotation_member_init->Invoke(self, args, sizeof(args), &result, "VLLLL");
+  if (self->IsExceptionPending()) {
+    LOG(INFO) << "Exception in AnnotationMember.<init>";
+    return nullptr;
+  }
+
+  return new_member.Get();
+}
+
+const DexFile::AnnotationItem* GetAnnotationItemFromAnnotationSet(
+    Handle<mirror::Class> klass,
+    const DexFile::AnnotationSetItem* annotation_set,
+    uint32_t visibility,
+    Handle<mirror::Class> annotation_class)
+    REQUIRES_SHARED(Locks::mutator_lock_) {
+  const DexFile& dex_file = klass->GetDexFile();
+  for (uint32_t i = 0; i < annotation_set->size_; ++i) {
+    const DexFile::AnnotationItem* annotation_item = dex_file.GetAnnotationItem(annotation_set, i);
+    if (!IsVisibilityCompatible(annotation_item->visibility_, visibility)) {
+      continue;
+    }
+    const uint8_t* annotation = annotation_item->annotation_;
+    uint32_t type_index = DecodeUnsignedLeb128(&annotation);
+    mirror::Class* resolved_class = Runtime::Current()->GetClassLinker()->ResolveType(
+        klass->GetDexFile(), type_index, klass.Get());
+    if (resolved_class == nullptr) {
+      std::string temp;
+      LOG(WARNING) << StringPrintf("Unable to resolve %s annotation class %d",
+                                   klass->GetDescriptor(&temp), type_index);
+      CHECK(Thread::Current()->IsExceptionPending());
+      Thread::Current()->ClearException();
+      continue;
+    }
+    if (resolved_class == annotation_class.Get()) {
+      return annotation_item;
+    }
+  }
+
+  return nullptr;
+}
+
+mirror::Object* GetAnnotationObjectFromAnnotationSet(
+    Handle<mirror::Class> klass,
+    const DexFile::AnnotationSetItem* annotation_set,
+    uint32_t visibility,
+    Handle<mirror::Class> annotation_class)
+    REQUIRES_SHARED(Locks::mutator_lock_) {
+  const DexFile::AnnotationItem* annotation_item =
+      GetAnnotationItemFromAnnotationSet(klass, annotation_set, visibility, annotation_class);
+  if (annotation_item == nullptr) {
+    return nullptr;
+  }
+  const uint8_t* annotation = annotation_item->annotation_;
+  return ProcessEncodedAnnotation(klass, &annotation);
+}
+
+mirror::Object* GetAnnotationValue(Handle<mirror::Class> klass,
+                                   const DexFile::AnnotationItem* annotation_item,
+                                   const char* annotation_name,
+                                   Handle<mirror::Class> array_class,
+                                   uint32_t expected_type)
+    REQUIRES_SHARED(Locks::mutator_lock_) {
+  const DexFile& dex_file = klass->GetDexFile();
+  const uint8_t* annotation =
+      SearchEncodedAnnotation(dex_file, annotation_item->annotation_, annotation_name);
+  if (annotation == nullptr) {
+    return nullptr;
+  }
+  DexFile::AnnotationValue annotation_value;
+  if (!ProcessAnnotationValue(klass, &annotation, &annotation_value, array_class,
+                              DexFile::kAllObjects)) {
+    return nullptr;
+  }
+  if (annotation_value.type_ != expected_type) {
+    return nullptr;
+  }
+  return annotation_value.value_.GetL();
+}
+
+mirror::ObjectArray<mirror::String>* GetSignatureValue(Handle<mirror::Class> klass,
+    const DexFile::AnnotationSetItem* annotation_set)
+    REQUIRES_SHARED(Locks::mutator_lock_) {
+  const DexFile& dex_file = klass->GetDexFile();
+  StackHandleScope<1> hs(Thread::Current());
+  const DexFile::AnnotationItem* annotation_item =
+      SearchAnnotationSet(dex_file, annotation_set, "Ldalvik/annotation/Signature;",
+                          DexFile::kDexVisibilitySystem);
+  if (annotation_item == nullptr) {
+    return nullptr;
+  }
+  mirror::Class* string_class = mirror::String::GetJavaLangString();
+  Handle<mirror::Class> string_array_class(hs.NewHandle(
+      Runtime::Current()->GetClassLinker()->FindArrayClass(Thread::Current(), &string_class)));
+  if (string_array_class.Get() == nullptr) {
+    return nullptr;
+  }
+  mirror::Object* obj =
+      GetAnnotationValue(klass, annotation_item, "value", string_array_class,
+                         DexFile::kDexAnnotationArray);
+  if (obj == nullptr) {
+    return nullptr;
+  }
+  return obj->AsObjectArray<mirror::String>();
+}
+
+mirror::ObjectArray<mirror::Class>* GetThrowsValue(Handle<mirror::Class> klass,
+                                                   const DexFile::AnnotationSetItem* annotation_set)
+    REQUIRES_SHARED(Locks::mutator_lock_) {
+  const DexFile& dex_file = klass->GetDexFile();
+  StackHandleScope<1> hs(Thread::Current());
+  const DexFile::AnnotationItem* annotation_item =
+      SearchAnnotationSet(dex_file, annotation_set, "Ldalvik/annotation/Throws;",
+                          DexFile::kDexVisibilitySystem);
+  if (annotation_item == nullptr) {
+    return nullptr;
+  }
+  mirror::Class* class_class = mirror::Class::GetJavaLangClass();
+  Handle<mirror::Class> class_array_class(hs.NewHandle(
+      Runtime::Current()->GetClassLinker()->FindArrayClass(Thread::Current(), &class_class)));
+  if (class_array_class.Get() == nullptr) {
+    return nullptr;
+  }
+  mirror::Object* obj =
+      GetAnnotationValue(klass, annotation_item, "value", class_array_class,
+                         DexFile::kDexAnnotationArray);
+  if (obj == nullptr) {
+    return nullptr;
+  }
+  return obj->AsObjectArray<mirror::Class>();
+}
+
+mirror::ObjectArray<mirror::Object>* ProcessAnnotationSet(
+    Handle<mirror::Class> klass,
+    const DexFile::AnnotationSetItem* annotation_set,
+    uint32_t visibility)
+    REQUIRES_SHARED(Locks::mutator_lock_) {
+  const DexFile& dex_file = klass->GetDexFile();
+  Thread* self = Thread::Current();
+  ScopedObjectAccessUnchecked soa(self);
+  StackHandleScope<2> hs(self);
+  Handle<mirror::Class> annotation_array_class(hs.NewHandle(
+      soa.Decode<mirror::Class*>(WellKnownClasses::java_lang_annotation_Annotation__array)));
+  if (annotation_set == nullptr) {
+    return mirror::ObjectArray<mirror::Object>::Alloc(self, annotation_array_class.Get(), 0);
+  }
+
+  uint32_t size = annotation_set->size_;
+  Handle<mirror::ObjectArray<mirror::Object>> result(hs.NewHandle(
+      mirror::ObjectArray<mirror::Object>::Alloc(self, annotation_array_class.Get(), size)));
+  if (result.Get() == nullptr) {
+    return nullptr;
+  }
+
+  uint32_t dest_index = 0;
+  for (uint32_t i = 0; i < size; ++i) {
+    const DexFile::AnnotationItem* annotation_item = dex_file.GetAnnotationItem(annotation_set, i);
+    // Note that we do not use IsVisibilityCompatible here because older code
+    // was correct for this case.
+    if (annotation_item->visibility_ != visibility) {
+      continue;
+    }
+    const uint8_t* annotation = annotation_item->annotation_;
+    mirror::Object* annotation_obj = ProcessEncodedAnnotation(klass, &annotation);
+    if (annotation_obj != nullptr) {
+      result->SetWithoutChecks<false>(dest_index, annotation_obj);
+      ++dest_index;
+    } else if (self->IsExceptionPending()) {
+      return nullptr;
+    }
+  }
+
+  if (dest_index == size) {
+    return result.Get();
+  }
+
+  mirror::ObjectArray<mirror::Object>* trimmed_result =
+      mirror::ObjectArray<mirror::Object>::Alloc(self, annotation_array_class.Get(), dest_index);
+  if (trimmed_result == nullptr) {
+    return nullptr;
+  }
+
+  for (uint32_t i = 0; i < dest_index; ++i) {
+    mirror::Object* obj = result->GetWithoutChecks(i);
+    trimmed_result->SetWithoutChecks<false>(i, obj);
+  }
+
+  return trimmed_result;
+}
+
+mirror::ObjectArray<mirror::Object>* ProcessAnnotationSetRefList(
+    Handle<mirror::Class> klass,
+    const DexFile::AnnotationSetRefList* set_ref_list,
+    uint32_t size)
+    REQUIRES_SHARED(Locks::mutator_lock_) {
+  const DexFile& dex_file = klass->GetDexFile();
+  Thread* self = Thread::Current();
+  ScopedObjectAccessUnchecked soa(self);
+  StackHandleScope<1> hs(self);
+  mirror::Class* annotation_array_class =
+      soa.Decode<mirror::Class*>(WellKnownClasses::java_lang_annotation_Annotation__array);
+  mirror::Class* annotation_array_array_class =
+      Runtime::Current()->GetClassLinker()->FindArrayClass(self, &annotation_array_class);
+  if (annotation_array_array_class == nullptr) {
+    return nullptr;
+  }
+  Handle<mirror::ObjectArray<mirror::Object>> annotation_array_array(hs.NewHandle(
+      mirror::ObjectArray<mirror::Object>::Alloc(self, annotation_array_array_class, size)));
+  if (annotation_array_array.Get() == nullptr) {
+    LOG(ERROR) << "Annotation set ref array allocation failed";
+    return nullptr;
+  }
+  for (uint32_t index = 0; index < size; ++index) {
+    const DexFile::AnnotationSetRefItem* set_ref_item = &set_ref_list->list_[index];
+    const DexFile::AnnotationSetItem* set_item = dex_file.GetSetRefItemItem(set_ref_item);
+    mirror::Object* annotation_set = ProcessAnnotationSet(klass, set_item,
+                                                          DexFile::kDexVisibilityRuntime);
+    if (annotation_set == nullptr) {
+      return nullptr;
+    }
+    annotation_array_array->SetWithoutChecks<false>(index, annotation_set);
+  }
+  return annotation_array_array.Get();
+}
+}  // namespace
+
+namespace annotations {
+
+mirror::Object* GetAnnotationForField(ArtField* field, Handle<mirror::Class> annotation_class) {
+  const DexFile::AnnotationSetItem* annotation_set = FindAnnotationSetForField(field);
+  if (annotation_set == nullptr) {
+    return nullptr;
+  }
+  StackHandleScope<1> hs(Thread::Current());
+  Handle<mirror::Class> field_class(hs.NewHandle(field->GetDeclaringClass()));
+  return GetAnnotationObjectFromAnnotationSet(field_class, annotation_set,
+                                              DexFile::kDexVisibilityRuntime, annotation_class);
+}
+
+mirror::ObjectArray<mirror::Object>* GetAnnotationsForField(ArtField* field) {
+  const DexFile::AnnotationSetItem* annotation_set = FindAnnotationSetForField(field);
+  StackHandleScope<1> hs(Thread::Current());
+  Handle<mirror::Class> field_class(hs.NewHandle(field->GetDeclaringClass()));
+  return ProcessAnnotationSet(field_class, annotation_set, DexFile::kDexVisibilityRuntime);
+}
+
+mirror::ObjectArray<mirror::String>* GetSignatureAnnotationForField(ArtField* field) {
+  const DexFile::AnnotationSetItem* annotation_set = FindAnnotationSetForField(field);
+  if (annotation_set == nullptr) {
+    return nullptr;
+  }
+  StackHandleScope<1> hs(Thread::Current());
+  Handle<mirror::Class> field_class(hs.NewHandle(field->GetDeclaringClass()));
+  return GetSignatureValue(field_class, annotation_set);
+}
+
+bool IsFieldAnnotationPresent(ArtField* field, Handle<mirror::Class> annotation_class) {
+  const DexFile::AnnotationSetItem* annotation_set = FindAnnotationSetForField(field);
+  if (annotation_set == nullptr) {
+    return false;
+  }
+  StackHandleScope<1> hs(Thread::Current());
+  Handle<mirror::Class> field_class(hs.NewHandle(field->GetDeclaringClass()));
+  const DexFile::AnnotationItem* annotation_item = GetAnnotationItemFromAnnotationSet(
+      field_class, annotation_set, DexFile::kDexVisibilityRuntime, annotation_class);
+  return annotation_item != nullptr;
+}
+
+mirror::Object* GetAnnotationDefaultValue(ArtMethod* method) {
+  const DexFile* dex_file = method->GetDexFile();
+  mirror::Class* klass = method->GetDeclaringClass();
+  const DexFile::AnnotationsDirectoryItem* annotations_dir =
+      dex_file->GetAnnotationsDirectory(*klass->GetClassDef());
+  if (annotations_dir == nullptr) {
+    return nullptr;
+  }
+  const DexFile::AnnotationSetItem* annotation_set =
+      dex_file->GetClassAnnotationSet(annotations_dir);
+  if (annotation_set == nullptr) {
+    return nullptr;
+  }
+  const DexFile::AnnotationItem* annotation_item = SearchAnnotationSet(*dex_file, annotation_set,
+      "Ldalvik/annotation/AnnotationDefault;", DexFile::kDexVisibilitySystem);
+  if (annotation_item == nullptr) {
+    return nullptr;
+  }
+  const uint8_t* annotation =
+      SearchEncodedAnnotation(*dex_file, annotation_item->annotation_, "value");
+  if (annotation == nullptr) {
+    return nullptr;
+  }
+  uint8_t header_byte = *(annotation++);
+  if ((header_byte & DexFile::kDexAnnotationValueTypeMask) != DexFile::kDexAnnotationAnnotation) {
+    return nullptr;
+  }
+  annotation = SearchEncodedAnnotation(*dex_file, annotation, method->GetName());
+  if (annotation == nullptr) {
+    return nullptr;
+  }
+  DexFile::AnnotationValue annotation_value;
+  StackHandleScope<2> hs(Thread::Current());
+  Handle<mirror::Class> h_klass(hs.NewHandle(klass));
+  PointerSize pointer_size = Runtime::Current()->GetClassLinker()->GetImagePointerSize();
+  Handle<mirror::Class> return_type(hs.NewHandle(
+      method->GetReturnType(true /* resolve */, pointer_size)));
+  if (!ProcessAnnotationValue(h_klass, &annotation, &annotation_value, return_type,
+                              DexFile::kAllObjects)) {
+    return nullptr;
+  }
+  return annotation_value.value_.GetL();
+}
+
+mirror::Object* GetAnnotationForMethod(ArtMethod* method, Handle<mirror::Class> annotation_class) {
+  const DexFile::AnnotationSetItem* annotation_set = FindAnnotationSetForMethod(method);
+  if (annotation_set == nullptr) {
+    return nullptr;
+  }
+  StackHandleScope<1> hs(Thread::Current());
+  Handle<mirror::Class> method_class(hs.NewHandle(method->GetDeclaringClass()));
+  return GetAnnotationObjectFromAnnotationSet(method_class, annotation_set,
+                                              DexFile::kDexVisibilityRuntime, annotation_class);
+}
+
+mirror::ObjectArray<mirror::Object>* GetAnnotationsForMethod(ArtMethod* method) {
+  const DexFile::AnnotationSetItem* annotation_set = FindAnnotationSetForMethod(method);
+  StackHandleScope<1> hs(Thread::Current());
+  Handle<mirror::Class> method_class(hs.NewHandle(method->GetDeclaringClass()));
+  return ProcessAnnotationSet(method_class, annotation_set, DexFile::kDexVisibilityRuntime);
+}
+
+mirror::ObjectArray<mirror::Class>* GetExceptionTypesForMethod(ArtMethod* method) {
+  const DexFile::AnnotationSetItem* annotation_set = FindAnnotationSetForMethod(method);
+  if (annotation_set == nullptr) {
+    return nullptr;
+  }
+  StackHandleScope<1> hs(Thread::Current());
+  Handle<mirror::Class> method_class(hs.NewHandle(method->GetDeclaringClass()));
+  return GetThrowsValue(method_class, annotation_set);
+}
+
+mirror::ObjectArray<mirror::Object>* GetParameterAnnotations(ArtMethod* method) {
+  const DexFile* dex_file = method->GetDexFile();
+  const DexFile::ParameterAnnotationsItem* parameter_annotations =
+      FindAnnotationsItemForMethod(method);
+  if (parameter_annotations == nullptr) {
+    return nullptr;
+  }
+  const DexFile::AnnotationSetRefList* set_ref_list =
+      dex_file->GetParameterAnnotationSetRefList(parameter_annotations);
+  if (set_ref_list == nullptr) {
+    return nullptr;
+  }
+  uint32_t size = set_ref_list->size_;
+  StackHandleScope<1> hs(Thread::Current());
+  Handle<mirror::Class> method_class(hs.NewHandle(method->GetDeclaringClass()));
+  return ProcessAnnotationSetRefList(method_class, set_ref_list, size);
+}
+
+mirror::Object* GetAnnotationForMethodParameter(ArtMethod* method,
+                                                uint32_t parameter_idx,
+                                                Handle<mirror::Class> annotation_class) {
+  const DexFile* dex_file = method->GetDexFile();
+  const DexFile::ParameterAnnotationsItem* parameter_annotations =
+      FindAnnotationsItemForMethod(method);
+  if (parameter_annotations == nullptr) {
+    return nullptr;
+  }
+  const DexFile::AnnotationSetRefList* set_ref_list =
+      dex_file->GetParameterAnnotationSetRefList(parameter_annotations);
+  if (set_ref_list == nullptr) {
+    return nullptr;
+  }
+  if (parameter_idx >= set_ref_list->size_) {
+    return nullptr;
+  }
+  const DexFile::AnnotationSetRefItem* annotation_set_ref = &set_ref_list->list_[parameter_idx];
+  const DexFile::AnnotationSetItem* annotation_set =
+     dex_file->GetSetRefItemItem(annotation_set_ref);
+
+  StackHandleScope<1> hs(Thread::Current());
+  Handle<mirror::Class> method_class(hs.NewHandle(method->GetDeclaringClass()));
+  return GetAnnotationObjectFromAnnotationSet(method_class,
+                                              annotation_set,
+                                              DexFile::kDexVisibilityRuntime,
+                                              annotation_class);
+}
+
+mirror::ObjectArray<mirror::String>* GetSignatureAnnotationForMethod(ArtMethod* method) {
+  const DexFile::AnnotationSetItem* annotation_set = FindAnnotationSetForMethod(method);
+  if (annotation_set == nullptr) {
+    return nullptr;
+  }
+  StackHandleScope<1> hs(Thread::Current());
+  Handle<mirror::Class> method_class(hs.NewHandle(method->GetDeclaringClass()));
+  return GetSignatureValue(method_class, annotation_set);
+}
+
+bool IsMethodAnnotationPresent(ArtMethod* method, Handle<mirror::Class> annotation_class,
+                               uint32_t visibility /* = DexFile::kDexVisibilityRuntime */) {
+  const DexFile::AnnotationSetItem* annotation_set = FindAnnotationSetForMethod(method);
+  if (annotation_set == nullptr) {
+    return false;
+  }
+  StackHandleScope<1> hs(Thread::Current());
+  Handle<mirror::Class> method_class(hs.NewHandle(method->GetDeclaringClass()));
+  const DexFile::AnnotationItem* annotation_item =
+      GetAnnotationItemFromAnnotationSet(method_class, annotation_set, visibility,
+                                         annotation_class);
+  return annotation_item != nullptr;
+}
+
+mirror::Object* GetAnnotationForClass(Handle<mirror::Class> klass,
+                                      Handle<mirror::Class> annotation_class) {
+  const DexFile::AnnotationSetItem* annotation_set = FindAnnotationSetForClass(klass);
+  if (annotation_set == nullptr) {
+    return nullptr;
+  }
+  return GetAnnotationObjectFromAnnotationSet(klass, annotation_set, DexFile::kDexVisibilityRuntime,
+                                              annotation_class);
+}
+
+mirror::ObjectArray<mirror::Object>* GetAnnotationsForClass(Handle<mirror::Class> klass) {
+  const DexFile::AnnotationSetItem* annotation_set = FindAnnotationSetForClass(klass);
+  return ProcessAnnotationSet(klass, annotation_set, DexFile::kDexVisibilityRuntime);
+}
+
+mirror::ObjectArray<mirror::Class>* GetDeclaredClasses(Handle<mirror::Class> klass) {
+  const DexFile& dex_file = klass->GetDexFile();
+  const DexFile::AnnotationSetItem* annotation_set = FindAnnotationSetForClass(klass);
+  if (annotation_set == nullptr) {
+    return nullptr;
+  }
+  const DexFile::AnnotationItem* annotation_item =
+      SearchAnnotationSet(dex_file, annotation_set, "Ldalvik/annotation/MemberClasses;",
+                          DexFile::kDexVisibilitySystem);
+  if (annotation_item == nullptr) {
+    return nullptr;
+  }
+  StackHandleScope<1> hs(Thread::Current());
+  mirror::Class* class_class = mirror::Class::GetJavaLangClass();
+  Handle<mirror::Class> class_array_class(hs.NewHandle(
+      Runtime::Current()->GetClassLinker()->FindArrayClass(hs.Self(), &class_class)));
+  if (class_array_class.Get() == nullptr) {
+    return nullptr;
+  }
+  mirror::Object* obj =
+      GetAnnotationValue(klass, annotation_item, "value", class_array_class,
+                         DexFile::kDexAnnotationArray);
+  if (obj == nullptr) {
+    return nullptr;
+  }
+  return obj->AsObjectArray<mirror::Class>();
+}
+
+mirror::Class* GetDeclaringClass(Handle<mirror::Class> klass) {
+  const DexFile& dex_file = klass->GetDexFile();
+  const DexFile::AnnotationSetItem* annotation_set = FindAnnotationSetForClass(klass);
+  if (annotation_set == nullptr) {
+    return nullptr;
+  }
+  const DexFile::AnnotationItem* annotation_item =
+      SearchAnnotationSet(dex_file, annotation_set, "Ldalvik/annotation/EnclosingClass;",
+                          DexFile::kDexVisibilitySystem);
+  if (annotation_item == nullptr) {
+    return nullptr;
+  }
+  mirror::Object* obj = GetAnnotationValue(klass, annotation_item, "value",
+                                           ScopedNullHandle<mirror::Class>(),
+                                           DexFile::kDexAnnotationType);
+  if (obj == nullptr) {
+    return nullptr;
+  }
+  return obj->AsClass();
+}
+
+mirror::Class* GetEnclosingClass(Handle<mirror::Class> klass) {
+  const DexFile& dex_file = klass->GetDexFile();
+  mirror::Class* declaring_class = GetDeclaringClass(klass);
+  if (declaring_class != nullptr) {
+    return declaring_class;
+  }
+  const DexFile::AnnotationSetItem* annotation_set = FindAnnotationSetForClass(klass);
+  if (annotation_set == nullptr) {
+    return nullptr;
+  }
+  const DexFile::AnnotationItem* annotation_item =
+      SearchAnnotationSet(dex_file, annotation_set, "Ldalvik/annotation/EnclosingMethod;",
+                          DexFile::kDexVisibilitySystem);
+  if (annotation_item == nullptr) {
+    return nullptr;
+  }
+  const uint8_t* annotation =
+      SearchEncodedAnnotation(dex_file, annotation_item->annotation_, "value");
+  if (annotation == nullptr) {
+    return nullptr;
+  }
+  DexFile::AnnotationValue annotation_value;
+  if (!ProcessAnnotationValue(klass, &annotation, &annotation_value,
+                              ScopedNullHandle<mirror::Class>(), DexFile::kAllRaw)) {
+    return nullptr;
+  }
+  if (annotation_value.type_ != DexFile::kDexAnnotationMethod) {
+    return nullptr;
+  }
+  StackHandleScope<2> hs(Thread::Current());
+  Handle<mirror::DexCache> dex_cache(hs.NewHandle(klass->GetDexCache()));
+  Handle<mirror::ClassLoader> class_loader(hs.NewHandle(klass->GetClassLoader()));
+  ArtMethod* method = Runtime::Current()->GetClassLinker()->ResolveMethodWithoutInvokeType(
+      klass->GetDexFile(), annotation_value.value_.GetI(), dex_cache, class_loader);
+  if (method == nullptr) {
+    return nullptr;
+  }
+  return method->GetDeclaringClass();
+}
+
+mirror::Object* GetEnclosingMethod(Handle<mirror::Class> klass) {
+  const DexFile& dex_file = klass->GetDexFile();
+  const DexFile::AnnotationSetItem* annotation_set = FindAnnotationSetForClass(klass);
+  if (annotation_set == nullptr) {
+    return nullptr;
+  }
+  const DexFile::AnnotationItem* annotation_item =
+      SearchAnnotationSet(dex_file, annotation_set, "Ldalvik/annotation/EnclosingMethod;",
+                          DexFile::kDexVisibilitySystem);
+  if (annotation_item == nullptr) {
+    return nullptr;
+  }
+  return GetAnnotationValue(klass, annotation_item, "value", ScopedNullHandle<mirror::Class>(),
+      DexFile::kDexAnnotationMethod);
+}
+
+bool GetInnerClass(Handle<mirror::Class> klass, mirror::String** name) {
+  const DexFile& dex_file = klass->GetDexFile();
+  const DexFile::AnnotationSetItem* annotation_set = FindAnnotationSetForClass(klass);
+  if (annotation_set == nullptr) {
+    return false;
+  }
+  const DexFile::AnnotationItem* annotation_item = SearchAnnotationSet(
+      dex_file, annotation_set, "Ldalvik/annotation/InnerClass;", DexFile::kDexVisibilitySystem);
+  if (annotation_item == nullptr) {
+    return false;
+  }
+  const uint8_t* annotation =
+      SearchEncodedAnnotation(dex_file, annotation_item->annotation_, "name");
+  if (annotation == nullptr) {
+    return false;
+  }
+  DexFile::AnnotationValue annotation_value;
+  if (!ProcessAnnotationValue(klass, &annotation, &annotation_value,
+                              ScopedNullHandle<mirror::Class>(),
+                                           DexFile::kAllObjects)) {
+    return false;
+  }
+  if (annotation_value.type_ != DexFile::kDexAnnotationNull &&
+      annotation_value.type_ != DexFile::kDexAnnotationString) {
+    return false;
+  }
+  *name = down_cast<mirror::String*>(annotation_value.value_.GetL());
+  return true;
+}
+
+bool GetInnerClassFlags(Handle<mirror::Class> klass, uint32_t* flags) {
+  const DexFile& dex_file = klass->GetDexFile();
+  const DexFile::AnnotationSetItem* annotation_set = FindAnnotationSetForClass(klass);
+  if (annotation_set == nullptr) {
+    return false;
+  }
+  const DexFile::AnnotationItem* annotation_item =
+      SearchAnnotationSet(dex_file, annotation_set, "Ldalvik/annotation/InnerClass;",
+                          DexFile::kDexVisibilitySystem);
+  if (annotation_item == nullptr) {
+    return false;
+  }
+  const uint8_t* annotation =
+      SearchEncodedAnnotation(dex_file, annotation_item->annotation_, "accessFlags");
+  if (annotation == nullptr) {
+    return false;
+  }
+  DexFile::AnnotationValue annotation_value;
+  if (!ProcessAnnotationValue(klass, &annotation, &annotation_value,
+                              ScopedNullHandle<mirror::Class>(), DexFile::kAllRaw)) {
+    return false;
+  }
+  if (annotation_value.type_ != DexFile::kDexAnnotationInt) {
+    return false;
+  }
+  *flags = annotation_value.value_.GetI();
+  return true;
+}
+
+mirror::ObjectArray<mirror::String>* GetSignatureAnnotationForClass(Handle<mirror::Class> klass) {
+  const DexFile::AnnotationSetItem* annotation_set = FindAnnotationSetForClass(klass);
+  if (annotation_set == nullptr) {
+    return nullptr;
+  }
+  return GetSignatureValue(klass, annotation_set);
+}
+
+bool IsClassAnnotationPresent(Handle<mirror::Class> klass, Handle<mirror::Class> annotation_class) {
+  const DexFile::AnnotationSetItem* annotation_set = FindAnnotationSetForClass(klass);
+  if (annotation_set == nullptr) {
+    return false;
+  }
+  const DexFile::AnnotationItem* annotation_item = GetAnnotationItemFromAnnotationSet(
+      klass, annotation_set, DexFile::kDexVisibilityRuntime, annotation_class);
+  return annotation_item != nullptr;
+}
+
+int32_t GetLineNumFromPC(const DexFile* dex_file, ArtMethod* method, uint32_t rel_pc) {
+  // For native method, lineno should be -2 to indicate it is native. Note that
+  // "line number == -2" is how libcore tells from StackTraceElement.
+  if (method->GetCodeItemOffset() == 0) {
+    return -2;
+  }
+
+  const DexFile::CodeItem* code_item = dex_file->GetCodeItem(method->GetCodeItemOffset());
+  DCHECK(code_item != nullptr) << PrettyMethod(method) << " " << dex_file->GetLocation();
+
+  // A method with no line number info should return -1
+  DexFile::LineNumFromPcContext context(rel_pc, -1);
+  dex_file->DecodeDebugPositionInfo(code_item, DexFile::LineNumForPcCb, &context);
+  return context.line_num_;
+}
+
+template<bool kTransactionActive>
+void RuntimeEncodedStaticFieldValueIterator::ReadValueToField(ArtField* field) const {
+  DCHECK(dex_cache_ != nullptr);
+  DCHECK(class_loader_ != nullptr);
+  switch (type_) {
+    case kBoolean: field->SetBoolean<kTransactionActive>(field->GetDeclaringClass(), jval_.z);
+        break;
+    case kByte:    field->SetByte<kTransactionActive>(field->GetDeclaringClass(), jval_.b); break;
+    case kShort:   field->SetShort<kTransactionActive>(field->GetDeclaringClass(), jval_.s); break;
+    case kChar:    field->SetChar<kTransactionActive>(field->GetDeclaringClass(), jval_.c); break;
+    case kInt:     field->SetInt<kTransactionActive>(field->GetDeclaringClass(), jval_.i); break;
+    case kLong:    field->SetLong<kTransactionActive>(field->GetDeclaringClass(), jval_.j); break;
+    case kFloat:   field->SetFloat<kTransactionActive>(field->GetDeclaringClass(), jval_.f); break;
+    case kDouble:  field->SetDouble<kTransactionActive>(field->GetDeclaringClass(), jval_.d); break;
+    case kNull:    field->SetObject<kTransactionActive>(field->GetDeclaringClass(), nullptr); break;
+    case kString: {
+      mirror::String* resolved = linker_->ResolveString(dex_file_, jval_.i, *dex_cache_);
+      field->SetObject<kTransactionActive>(field->GetDeclaringClass(), resolved);
+      break;
+    }
+    case kType: {
+      mirror::Class* resolved = linker_->ResolveType(dex_file_, jval_.i, *dex_cache_,
+                                                     *class_loader_);
+      field->SetObject<kTransactionActive>(field->GetDeclaringClass(), resolved);
+      break;
+    }
+    default: UNIMPLEMENTED(FATAL) << ": type " << type_;
+  }
+}
+template
+void RuntimeEncodedStaticFieldValueIterator::ReadValueToField<true>(ArtField* field) const;
+template
+void RuntimeEncodedStaticFieldValueIterator::ReadValueToField<false>(ArtField* field) const;
+
+}  // namespace annotations
+
+}  // namespace art
diff --git a/runtime/dex_file_annotations.h b/runtime/dex_file_annotations.h
new file mode 100644
index 0000000..7b4e856
--- /dev/null
+++ b/runtime/dex_file_annotations.h
@@ -0,0 +1,125 @@
+/*
+ * 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.
+ */
+
+#ifndef ART_RUNTIME_DEX_FILE_ANNOTATIONS_H_
+#define ART_RUNTIME_DEX_FILE_ANNOTATIONS_H_
+
+#include "dex_file.h"
+
+#include "mirror/object_array.h"
+
+namespace art {
+
+namespace mirror {
+  class ClassLoader;
+  class DexCache;
+}  // namespace mirror
+class ArtField;
+class ArtMethod;
+class ClassLinker;
+
+namespace annotations {
+
+// Field annotations.
+mirror::Object* GetAnnotationForField(ArtField* field, Handle<mirror::Class> annotation_class)
+    REQUIRES_SHARED(Locks::mutator_lock_);
+mirror::ObjectArray<mirror::Object>* GetAnnotationsForField(ArtField* field)
+    REQUIRES_SHARED(Locks::mutator_lock_);
+mirror::ObjectArray<mirror::String>* GetSignatureAnnotationForField(ArtField* field)
+    REQUIRES_SHARED(Locks::mutator_lock_);
+bool IsFieldAnnotationPresent(ArtField* field, Handle<mirror::Class> annotation_class)
+    REQUIRES_SHARED(Locks::mutator_lock_);
+
+// Method annotations.
+mirror::Object* GetAnnotationDefaultValue(ArtMethod* method)
+    REQUIRES_SHARED(Locks::mutator_lock_);
+mirror::Object* GetAnnotationForMethod(ArtMethod* method, Handle<mirror::Class> annotation_class)
+    REQUIRES_SHARED(Locks::mutator_lock_);
+mirror::ObjectArray<mirror::Object>* GetAnnotationsForMethod(ArtMethod* method)
+    REQUIRES_SHARED(Locks::mutator_lock_);
+mirror::ObjectArray<mirror::Class>* GetExceptionTypesForMethod(ArtMethod* method)
+    REQUIRES_SHARED(Locks::mutator_lock_);
+mirror::ObjectArray<mirror::Object>* GetParameterAnnotations(ArtMethod* method)
+    REQUIRES_SHARED(Locks::mutator_lock_);
+mirror::Object* GetAnnotationForMethodParameter(ArtMethod* method,
+                                                uint32_t parameter_idx,
+                                                Handle<mirror::Class> annotation_class)
+    REQUIRES_SHARED(Locks::mutator_lock_);
+mirror::ObjectArray<mirror::String>* GetSignatureAnnotationForMethod(ArtMethod* method)
+    REQUIRES_SHARED(Locks::mutator_lock_);
+bool IsMethodAnnotationPresent(ArtMethod* method, Handle<mirror::Class> annotation_class,
+                               uint32_t visibility = DexFile::kDexVisibilityRuntime)
+    REQUIRES_SHARED(Locks::mutator_lock_);
+
+// Class annotations.
+mirror::Object* GetAnnotationForClass(Handle<mirror::Class> klass,
+                                      Handle<mirror::Class> annotation_class)
+    REQUIRES_SHARED(Locks::mutator_lock_);
+mirror::ObjectArray<mirror::Object>* GetAnnotationsForClass(Handle<mirror::Class> klass)
+    REQUIRES_SHARED(Locks::mutator_lock_);
+mirror::ObjectArray<mirror::Class>* GetDeclaredClasses(Handle<mirror::Class> klass)
+    REQUIRES_SHARED(Locks::mutator_lock_);
+mirror::Class* GetDeclaringClass(Handle<mirror::Class> klass)
+    REQUIRES_SHARED(Locks::mutator_lock_);
+mirror::Class* GetEnclosingClass(Handle<mirror::Class> klass)
+    REQUIRES_SHARED(Locks::mutator_lock_);
+mirror::Object* GetEnclosingMethod(Handle<mirror::Class> klass)
+    REQUIRES_SHARED(Locks::mutator_lock_);
+bool GetInnerClass(Handle<mirror::Class> klass, mirror::String** name)
+    REQUIRES_SHARED(Locks::mutator_lock_);
+bool GetInnerClassFlags(Handle<mirror::Class> klass, uint32_t* flags)
+    REQUIRES_SHARED(Locks::mutator_lock_);
+mirror::ObjectArray<mirror::String>* GetSignatureAnnotationForClass(Handle<mirror::Class> klass)
+    REQUIRES_SHARED(Locks::mutator_lock_);
+bool IsClassAnnotationPresent(Handle<mirror::Class> klass,
+                              Handle<mirror::Class> annotation_class)
+    REQUIRES_SHARED(Locks::mutator_lock_);
+
+// Map back from a PC to the line number in a method.
+int32_t GetLineNumFromPC(const DexFile* dex_file, ArtMethod* method, uint32_t rel_pc)
+    REQUIRES_SHARED(Locks::mutator_lock_);
+
+// Annotations iterator.
+class RuntimeEncodedStaticFieldValueIterator : public EncodedStaticFieldValueIterator {
+ public:
+  // A constructor meant to be called from runtime code.
+  RuntimeEncodedStaticFieldValueIterator(const DexFile& dex_file,
+                                         Handle<mirror::DexCache>* dex_cache,
+                                         Handle<mirror::ClassLoader>* class_loader,
+                                         ClassLinker* linker,
+                                         const DexFile::ClassDef& class_def)
+      REQUIRES_SHARED(Locks::mutator_lock_)
+      : EncodedStaticFieldValueIterator(dex_file, class_def),
+        dex_cache_(dex_cache),
+        class_loader_(class_loader),
+        linker_(linker) {
+  }
+
+  template<bool kTransactionActive>
+  void ReadValueToField(ArtField* field) const REQUIRES_SHARED(Locks::mutator_lock_);
+
+ private:
+  Handle<mirror::DexCache>* const dex_cache_;  // Dex cache to resolve literal objects.
+  Handle<mirror::ClassLoader>* const class_loader_;  // ClassLoader to resolve types.
+  ClassLinker* linker_;  // Linker to resolve literal objects.
+  DISALLOW_IMPLICIT_CONSTRUCTORS(RuntimeEncodedStaticFieldValueIterator);
+};
+
+}  // namespace annotations
+
+}  // namespace art
+
+#endif  // ART_RUNTIME_DEX_FILE_ANNOTATIONS_H_
diff --git a/runtime/entrypoints/entrypoint_utils-inl.h b/runtime/entrypoints/entrypoint_utils-inl.h
index d03a9d8..14110c2 100644
--- a/runtime/entrypoints/entrypoint_utils-inl.h
+++ b/runtime/entrypoints/entrypoint_utils-inl.h
@@ -48,7 +48,7 @@
   // This method is being used by artQuickResolutionTrampoline, before it sets up
   // the passed parameters in a GC friendly way. Therefore we must never be
   // suspended while executing it.
-  ScopedAssertNoThreadSuspension sants(Thread::Current(), __FUNCTION__);
+  ScopedAssertNoThreadSuspension sants(__FUNCTION__);
 
   uint32_t method_index = inline_info.GetMethodIndexAtDepth(encoding, inlining_depth);
   InvokeType invoke_type = static_cast<InvokeType>(
@@ -120,8 +120,7 @@
   return inlined_method;
 }
 
-inline ArtMethod* GetCalleeSaveMethodCaller(Thread* self, Runtime::CalleeSaveType type)
-    REQUIRES_SHARED(Locks::mutator_lock_) {
+inline ArtMethod* GetCalleeSaveMethodCaller(Thread* self, Runtime::CalleeSaveType type) {
   return GetCalleeSaveMethodCaller(
       self->GetManagedStack()->GetTopQuickFrame(), type, true /* do_caller_check */);
 }
@@ -130,7 +129,8 @@
 ALWAYS_INLINE
 inline mirror::Class* CheckObjectAlloc(uint32_t type_idx,
                                        ArtMethod* method,
-                                       Thread* self, bool* slow_path) {
+                                       Thread* self,
+                                       bool* slow_path) {
   ClassLinker* class_linker = Runtime::Current()->GetClassLinker();
   PointerSize pointer_size = class_linker->GetImagePointerSize();
   mirror::Class* klass = method->GetDexCacheResolvedType<false>(type_idx, pointer_size);
@@ -363,7 +363,7 @@
 inline ArtField* FindFieldFromCode(uint32_t field_idx,
                                    ArtMethod* referrer,
                                    Thread* self,
-                                   size_t expected_size) REQUIRES(!Roles::uninterruptible_) {
+                                   size_t expected_size) {
   bool is_primitive;
   bool is_set;
   bool is_static;
@@ -444,8 +444,7 @@
       return resolved_field;
     } else {
       StackHandleScope<1> hs(self);
-      Handle<mirror::Class> h_class(hs.NewHandle(fields_class));
-      if (LIKELY(class_linker->EnsureInitialized(self, h_class, true, true))) {
+      if (LIKELY(class_linker->EnsureInitialized(self, hs.NewHandle(fields_class), true, true))) {
         // Otherwise let's ensure the class is initialized before resolving the field.
         return resolved_field;
       }
@@ -479,8 +478,10 @@
 #undef EXPLICIT_FIND_FIELD_FROM_CODE_TEMPLATE_DECL
 
 template<InvokeType type, bool access_check>
-inline ArtMethod* FindMethodFromCode(uint32_t method_idx, mirror::Object** this_object,
-                                     ArtMethod* referrer, Thread* self) {
+inline ArtMethod* FindMethodFromCode(uint32_t method_idx,
+                                     mirror::Object** this_object,
+                                     ArtMethod* referrer,
+                                     Thread* self) {
   ClassLinker* const class_linker = Runtime::Current()->GetClassLinker();
   ArtMethod* resolved_method = class_linker->GetResolvedMethod(method_idx, referrer);
   if (resolved_method == nullptr) {
@@ -554,8 +555,11 @@
       //    that will actually not be what we want in some cases where there are miranda methods or
       //    defaults. What we actually need is a GetContainingClass that says which classes virtuals
       //    this method is coming from.
-      mirror::Class* referring_class = referrer->GetDeclaringClass();
-      uint16_t method_type_idx = referring_class->GetDexFile().GetMethodId(method_idx).class_idx_;
+      StackHandleScope<2> hs2(self);
+      HandleWrapper<mirror::Object> h_this(hs2.NewHandleWrapper(this_object));
+      Handle<mirror::Class> h_referring_class(hs2.NewHandle(referrer->GetDeclaringClass()));
+      const uint16_t method_type_idx =
+          h_referring_class->GetDexFile().GetMethodId(method_idx).class_idx_;
       mirror::Class* method_reference_class = class_linker->ResolveType(method_type_idx, referrer);
       if (UNLIKELY(method_reference_class == nullptr)) {
         // Bad type idx.
@@ -566,8 +570,8 @@
         // referenced class in the bytecode, we use its super class. Otherwise, we throw
         // a NoSuchMethodError.
         mirror::Class* super_class = nullptr;
-        if (method_reference_class->IsAssignableFrom(referring_class)) {
-          super_class = referring_class->GetSuperClass();
+        if (method_reference_class->IsAssignableFrom(h_referring_class.Get())) {
+          super_class = h_referring_class->GetSuperClass();
         }
         uint16_t vtable_index = resolved_method->GetMethodIndex();
         if (access_check) {
@@ -587,10 +591,10 @@
       } else {
         // It is an interface.
         if (access_check) {
-          if (!method_reference_class->IsAssignableFrom((*this_object)->GetClass())) {
+          if (!method_reference_class->IsAssignableFrom(h_this->GetClass())) {
             ThrowIncompatibleClassChangeErrorClassForInterfaceSuper(resolved_method,
                                                                     method_reference_class,
-                                                                    *this_object,
+                                                                    h_this.Get(),
                                                                     referrer);
             return nullptr;  // Failure.
           }
@@ -605,6 +609,7 @@
         }
         return result;
       }
+      UNREACHABLE();
     }
     case kInterface: {
       uint32_t imt_index = resolved_method->GetImtIndex();
@@ -661,6 +666,7 @@
 // Fast path field resolution that can't initialize classes or throw exceptions.
 inline ArtField* FindFieldFast(uint32_t field_idx, ArtMethod* referrer, FindFieldType type,
                                size_t expected_size) {
+  ScopedAssertNoThreadSuspension ants(__FUNCTION__);
   ArtField* resolved_field =
       referrer->GetDeclaringClass()->GetDexCache()->GetResolvedField(field_idx,
                                                                      kRuntimePointerSize);
@@ -713,6 +719,7 @@
 // Fast path method resolution that can't throw exceptions.
 inline ArtMethod* FindMethodFast(uint32_t method_idx, mirror::Object* this_object,
                                  ArtMethod* referrer, bool access_check, InvokeType type) {
+  ScopedAssertNoThreadSuspension ants(__FUNCTION__);
   if (UNLIKELY(this_object == nullptr && type != kStatic)) {
     return nullptr;
   }
diff --git a/runtime/entrypoints/entrypoint_utils.cc b/runtime/entrypoints/entrypoint_utils.cc
index 4056ec5..fd9ffbd 100644
--- a/runtime/entrypoints/entrypoint_utils.cc
+++ b/runtime/entrypoints/entrypoint_utils.cc
@@ -43,7 +43,7 @@
                                                       ArtMethod* referrer,
                                                       Thread* self,
                                                       bool access_check)
-    REQUIRES_SHARED(Locks::mutator_lock_) {
+    REQUIRES_SHARED(Locks::mutator_lock_) REQUIRES(!Roles::uninterruptible_) {
   if (UNLIKELY(component_count < 0)) {
     ThrowNegativeArraySizeException(component_count);
     return nullptr;  // Failure
@@ -120,19 +120,19 @@
                                     heap->GetCurrentAllocator());
 }
 
-void CheckReferenceResult(mirror::Object* o, Thread* self) {
-  if (o == nullptr) {
+void CheckReferenceResult(Handle<mirror::Object> o, Thread* self) {
+  if (o.Get() == nullptr) {
     return;
   }
   // Make sure that the result is an instance of the type this method was expected to return.
-  mirror::Class* return_type = self->GetCurrentMethod(nullptr)->GetReturnType(true /* resolve */,
-                                                                              kRuntimePointerSize);
+  ArtMethod* method = self->GetCurrentMethod(nullptr);
+  mirror::Class* return_type = method->GetReturnType(true /* resolve */, kRuntimePointerSize);
 
   if (!o->InstanceOf(return_type)) {
     Runtime::Current()->GetJavaVM()->JniAbortF(nullptr,
                                                "attempt to return an instance of %s from %s",
-                                               PrettyTypeOf(o).c_str(),
-                                               PrettyMethod(self->GetCurrentMethod(nullptr)).c_str());
+                                               PrettyTypeOf(o.Get()).c_str(),
+                                               PrettyMethod(method).c_str());
   }
 }
 
@@ -186,12 +186,11 @@
       // Do nothing.
       return zero;
     } else {
-      StackHandleScope<1> hs(soa.Self());
-      auto h_interface_method(hs.NewHandle(soa.Decode<mirror::Method*>(interface_method_jobj)));
+      ArtMethod* interface_method =
+          soa.Decode<mirror::Method*>(interface_method_jobj)->GetArtMethod();
       // This can cause thread suspension.
       PointerSize pointer_size = Runtime::Current()->GetClassLinker()->GetImagePointerSize();
-      mirror::Class* result_type =
-          h_interface_method->GetArtMethod()->GetReturnType(true /* resolve */, pointer_size);
+      mirror::Class* result_type = interface_method->GetReturnType(true /* resolve */, pointer_size);
       mirror::Object* result_ref = soa.Decode<mirror::Object*>(result);
       JValue result_unboxed;
       if (!UnboxPrimitiveForResult(result_ref, result_type, &result_unboxed)) {
@@ -205,26 +204,29 @@
     // a UndeclaredThrowableException.
     mirror::Throwable* exception = soa.Self()->GetException();
     if (exception->IsCheckedException()) {
-      mirror::Object* rcvr = soa.Decode<mirror::Object*>(rcvr_jobj);
-      mirror::Class* proxy_class = rcvr->GetClass();
-      mirror::Method* interface_method = soa.Decode<mirror::Method*>(interface_method_jobj);
-      ArtMethod* proxy_method = rcvr->GetClass()->FindVirtualMethodForInterface(
-          interface_method->GetArtMethod(), kRuntimePointerSize);
-      auto virtual_methods = proxy_class->GetVirtualMethodsSlice(kRuntimePointerSize);
-      size_t num_virtuals = proxy_class->NumVirtualMethods();
-      size_t method_size = ArtMethod::Size(kRuntimePointerSize);
-      // Rely on the fact that the methods are contiguous to determine the index of the method in
-      // the slice.
-      int throws_index = (reinterpret_cast<uintptr_t>(proxy_method) -
-          reinterpret_cast<uintptr_t>(&virtual_methods.At(0))) / method_size;
-      CHECK_LT(throws_index, static_cast<int>(num_virtuals));
-      mirror::ObjectArray<mirror::Class>* declared_exceptions =
-          proxy_class->GetThrows()->Get(throws_index);
-      mirror::Class* exception_class = exception->GetClass();
       bool declares_exception = false;
-      for (int32_t i = 0; i < declared_exceptions->GetLength() && !declares_exception; i++) {
-        mirror::Class* declared_exception = declared_exceptions->Get(i);
-        declares_exception = declared_exception->IsAssignableFrom(exception_class);
+      {
+        ScopedAssertNoThreadSuspension ants(__FUNCTION__);
+        mirror::Object* rcvr = soa.Decode<mirror::Object*>(rcvr_jobj);
+        mirror::Class* proxy_class = rcvr->GetClass();
+        mirror::Method* interface_method = soa.Decode<mirror::Method*>(interface_method_jobj);
+        ArtMethod* proxy_method = rcvr->GetClass()->FindVirtualMethodForInterface(
+            interface_method->GetArtMethod(), kRuntimePointerSize);
+        auto virtual_methods = proxy_class->GetVirtualMethodsSlice(kRuntimePointerSize);
+        size_t num_virtuals = proxy_class->NumVirtualMethods();
+        size_t method_size = ArtMethod::Size(kRuntimePointerSize);
+        // Rely on the fact that the methods are contiguous to determine the index of the method in
+        // the slice.
+        int throws_index = (reinterpret_cast<uintptr_t>(proxy_method) -
+            reinterpret_cast<uintptr_t>(&virtual_methods.At(0))) / method_size;
+        CHECK_LT(throws_index, static_cast<int>(num_virtuals));
+        mirror::ObjectArray<mirror::Class>* declared_exceptions =
+            proxy_class->GetThrows()->Get(throws_index);
+        mirror::Class* exception_class = exception->GetClass();
+        for (int32_t i = 0; i < declared_exceptions->GetLength() && !declares_exception; i++) {
+          mirror::Class* declared_exception = declared_exceptions->Get(i);
+          declares_exception = declared_exception->IsAssignableFrom(exception_class);
+        }
       }
       if (!declares_exception) {
         soa.Self()->ThrowNewWrappedException("Ljava/lang/reflect/UndeclaredThrowableException;",
@@ -260,6 +262,7 @@
                                      Runtime::CalleeSaveType type,
                                      bool do_caller_check)
     REQUIRES_SHARED(Locks::mutator_lock_) {
+  ScopedAssertNoThreadSuspension ants(__FUNCTION__);
   DCHECK_EQ(*sp, Runtime::Current()->GetCalleeSaveMethod(type));
 
   const size_t callee_frame_size = GetCalleeSaveFrameSize(kRuntimeISA, type);
diff --git a/runtime/entrypoints/entrypoint_utils.h b/runtime/entrypoints/entrypoint_utils.h
index f88e81d..20c8401 100644
--- a/runtime/entrypoints/entrypoint_utils.h
+++ b/runtime/entrypoints/entrypoint_utils.h
@@ -24,6 +24,7 @@
 #include "base/mutex.h"
 #include "dex_instruction.h"
 #include "gc/allocator_type.h"
+#include "handle.h"
 #include "invoke_type.h"
 #include "jvalue.h"
 #include "runtime.h"
@@ -46,13 +47,16 @@
 template <const bool kAccessCheck>
 ALWAYS_INLINE inline mirror::Class* CheckObjectAlloc(uint32_t type_idx,
                                                      ArtMethod* method,
-                                                     Thread* self, bool* slow_path)
-    REQUIRES_SHARED(Locks::mutator_lock_);
+                                                     Thread* self,
+                                                     bool* slow_path)
+    REQUIRES_SHARED(Locks::mutator_lock_)
+    REQUIRES(!Roles::uninterruptible_);
 
 ALWAYS_INLINE inline mirror::Class* CheckClassInitializedForObjectAlloc(mirror::Class* klass,
                                                                         Thread* self,
                                                                         bool* slow_path)
-    REQUIRES_SHARED(Locks::mutator_lock_);
+    REQUIRES_SHARED(Locks::mutator_lock_)
+    REQUIRES(!Roles::uninterruptible_);
 
 // Given the context of a calling Method, use its DexCache to resolve a type to a Class. If it
 // cannot be resolved, throw an error. If it can, use it to create an instance.
@@ -63,21 +67,25 @@
                                                          ArtMethod* method,
                                                          Thread* self,
                                                          gc::AllocatorType allocator_type)
-    REQUIRES_SHARED(Locks::mutator_lock_);
+    REQUIRES_SHARED(Locks::mutator_lock_)
+    REQUIRES(!Roles::uninterruptible_);
 
 // Given the context of a calling Method and a resolved class, create an instance.
 template <bool kInstrumented>
 ALWAYS_INLINE inline mirror::Object* AllocObjectFromCodeResolved(mirror::Class* klass,
                                                                  Thread* self,
                                                                  gc::AllocatorType allocator_type)
-    REQUIRES_SHARED(Locks::mutator_lock_);
+    REQUIRES_SHARED(Locks::mutator_lock_)
+    REQUIRES(!Roles::uninterruptible_);
 
 // Given the context of a calling Method and an initialized class, create an instance.
 template <bool kInstrumented>
-ALWAYS_INLINE inline mirror::Object* AllocObjectFromCodeInitialized(mirror::Class* klass,
-                                                                    Thread* self,
-                                                                    gc::AllocatorType allocator_type)
-    REQUIRES_SHARED(Locks::mutator_lock_);
+ALWAYS_INLINE inline mirror::Object* AllocObjectFromCodeInitialized(
+    mirror::Class* klass,
+    Thread* self,
+    gc::AllocatorType allocator_type)
+    REQUIRES_SHARED(Locks::mutator_lock_)
+    REQUIRES(!Roles::uninterruptible_);
 
 
 template <bool kAccessCheck>
@@ -85,7 +93,8 @@
                                                     int32_t component_count,
                                                     ArtMethod* method,
                                                     bool* slow_path)
-    REQUIRES_SHARED(Locks::mutator_lock_);
+    REQUIRES_SHARED(Locks::mutator_lock_)
+    REQUIRES(!Roles::uninterruptible_);
 
 // Given the context of a calling Method, use its DexCache to resolve a type to an array Class. If
 // it cannot be resolved, throw an error. If it can, use it to create an array.
@@ -97,7 +106,8 @@
                                                        ArtMethod* method,
                                                        Thread* self,
                                                        gc::AllocatorType allocator_type)
-    REQUIRES_SHARED(Locks::mutator_lock_);
+    REQUIRES_SHARED(Locks::mutator_lock_)
+    REQUIRES(!Roles::uninterruptible_);
 
 template <bool kAccessCheck, bool kInstrumented>
 ALWAYS_INLINE inline mirror::Array* AllocArrayFromCodeResolved(mirror::Class* klass,
@@ -105,13 +115,15 @@
                                                                ArtMethod* method,
                                                                Thread* self,
                                                                gc::AllocatorType allocator_type)
-    REQUIRES_SHARED(Locks::mutator_lock_);
+    REQUIRES_SHARED(Locks::mutator_lock_)
+    REQUIRES(!Roles::uninterruptible_);
 
 extern mirror::Array* CheckAndAllocArrayFromCode(uint32_t type_idx, int32_t component_count,
                                                  ArtMethod* method, Thread* self,
                                                  bool access_check,
                                                  gc::AllocatorType allocator_type)
-    REQUIRES_SHARED(Locks::mutator_lock_);
+    REQUIRES_SHARED(Locks::mutator_lock_)
+    REQUIRES(!Roles::uninterruptible_);
 
 extern mirror::Array* CheckAndAllocArrayFromCodeInstrumented(uint32_t type_idx,
                                                              int32_t component_count,
@@ -119,7 +131,8 @@
                                                              Thread* self,
                                                              bool access_check,
                                                              gc::AllocatorType allocator_type)
-    REQUIRES_SHARED(Locks::mutator_lock_);
+    REQUIRES_SHARED(Locks::mutator_lock_)
+    REQUIRES(!Roles::uninterruptible_);
 
 // Type of find field operation for fast and slow case.
 enum FindFieldType {
@@ -134,54 +147,76 @@
 };
 
 template<FindFieldType type, bool access_check>
-inline ArtField* FindFieldFromCode(
-    uint32_t field_idx, ArtMethod* referrer, Thread* self, size_t expected_size)
-    REQUIRES_SHARED(Locks::mutator_lock_);
+inline ArtField* FindFieldFromCode(uint32_t field_idx,
+                                   ArtMethod* referrer,
+                                   Thread* self,
+                                   size_t expected_size)
+    REQUIRES_SHARED(Locks::mutator_lock_)
+    REQUIRES(!Roles::uninterruptible_);
 
 template<InvokeType type, bool access_check>
-inline ArtMethod* FindMethodFromCode(
-    uint32_t method_idx, mirror::Object** this_object, ArtMethod* referrer, Thread* self)
-    REQUIRES_SHARED(Locks::mutator_lock_);
+inline ArtMethod* FindMethodFromCode(uint32_t method_idx,
+                                     mirror::Object** this_object,
+                                     ArtMethod* referrer,
+                                     Thread* self)
+    REQUIRES_SHARED(Locks::mutator_lock_)
+    REQUIRES(!Roles::uninterruptible_);
 
 // Fast path field resolution that can't initialize classes or throw exceptions.
-inline ArtField* FindFieldFast(
-    uint32_t field_idx, ArtMethod* referrer, FindFieldType type, size_t expected_size)
+inline ArtField* FindFieldFast(uint32_t field_idx,
+                               ArtMethod* referrer,
+                               FindFieldType type,
+                               size_t expected_size)
     REQUIRES_SHARED(Locks::mutator_lock_);
 
 // Fast path method resolution that can't throw exceptions.
-inline ArtMethod* FindMethodFast(
-    uint32_t method_idx, mirror::Object* this_object, ArtMethod* referrer, bool access_check,
-    InvokeType type)
+inline ArtMethod* FindMethodFast(uint32_t method_idx,
+                                 mirror::Object* this_object,
+                                 ArtMethod* referrer,
+                                 bool access_check,
+                                 InvokeType type)
     REQUIRES_SHARED(Locks::mutator_lock_);
 
-inline mirror::Class* ResolveVerifyAndClinit(
-    uint32_t type_idx, ArtMethod* referrer, Thread* self, bool can_run_clinit, bool verify_access)
-    REQUIRES_SHARED(Locks::mutator_lock_);
+inline mirror::Class* ResolveVerifyAndClinit(uint32_t type_idx,
+                                             ArtMethod* referrer,
+                                             Thread* self,
+                                             bool can_run_clinit,
+                                             bool verify_access)
+    REQUIRES_SHARED(Locks::mutator_lock_)
+    REQUIRES(!Roles::uninterruptible_);
 
 inline mirror::String* ResolveStringFromCode(ArtMethod* referrer, uint32_t string_idx)
-    REQUIRES_SHARED(Locks::mutator_lock_);
+    REQUIRES_SHARED(Locks::mutator_lock_)
+    REQUIRES(!Roles::uninterruptible_);
 
 // TODO: annotalysis disabled as monitor semantics are maintained in Java code.
 inline void UnlockJniSynchronizedMethod(jobject locked, Thread* self)
-    NO_THREAD_SAFETY_ANALYSIS;
+    NO_THREAD_SAFETY_ANALYSIS REQUIRES(!Roles::uninterruptible_);
 
-void CheckReferenceResult(mirror::Object* o, Thread* self)
-    REQUIRES_SHARED(Locks::mutator_lock_);
+void CheckReferenceResult(Handle<mirror::Object> o, Thread* self)
+    REQUIRES_SHARED(Locks::mutator_lock_)
+    REQUIRES(!Roles::uninterruptible_);
 
 JValue InvokeProxyInvocationHandler(ScopedObjectAccessAlreadyRunnable& soa, const char* shorty,
                                     jobject rcvr_jobj, jobject interface_art_method_jobj,
                                     std::vector<jvalue>& args)
-    REQUIRES_SHARED(Locks::mutator_lock_);
+    REQUIRES_SHARED(Locks::mutator_lock_)
+    REQUIRES(!Roles::uninterruptible_);
 
 bool FillArrayData(mirror::Object* obj, const Instruction::ArrayDataPayload* payload)
-    REQUIRES_SHARED(Locks::mutator_lock_);
+    REQUIRES_SHARED(Locks::mutator_lock_)
+    REQUIRES(!Roles::uninterruptible_);
 
 template <typename INT_TYPE, typename FLOAT_TYPE>
 inline INT_TYPE art_float_to_integral(FLOAT_TYPE f);
 
 ArtMethod* GetCalleeSaveMethodCaller(ArtMethod** sp,
                                      Runtime::CalleeSaveType type,
-                                     bool do_caller_check = false);
+                                     bool do_caller_check = false)
+    REQUIRES_SHARED(Locks::mutator_lock_);
+
+ArtMethod* GetCalleeSaveMethodCaller(Thread* self, Runtime::CalleeSaveType type)
+    REQUIRES_SHARED(Locks::mutator_lock_);
 
 }  // namespace art
 
diff --git a/runtime/entrypoints/quick/quick_default_externs.h b/runtime/entrypoints/quick/quick_default_externs.h
index 86fb881..cfa5325 100644
--- a/runtime/entrypoints/quick/quick_default_externs.h
+++ b/runtime/entrypoints/quick/quick_default_externs.h
@@ -118,7 +118,6 @@
 extern "C" void art_quick_deliver_exception(art::mirror::Object*);
 extern "C" void art_quick_throw_array_bounds(int32_t index, int32_t limit);
 extern "C" void art_quick_throw_div_zero();
-extern "C" void art_quick_throw_no_such_method(int32_t method_idx);
 extern "C" void art_quick_throw_null_pointer_exception();
 extern "C" void art_quick_throw_null_pointer_exception_from_signal(uintptr_t address);
 extern "C" void art_quick_throw_stack_overflow(void*);
diff --git a/runtime/entrypoints/quick/quick_default_init_entrypoints.h b/runtime/entrypoints/quick/quick_default_init_entrypoints.h
index 2a206c2..1ee1f81 100644
--- a/runtime/entrypoints/quick/quick_default_init_entrypoints.h
+++ b/runtime/entrypoints/quick/quick_default_init_entrypoints.h
@@ -113,7 +113,6 @@
   qpoints->pDeliverException = art_quick_deliver_exception;
   qpoints->pThrowArrayBounds = art_quick_throw_array_bounds;
   qpoints->pThrowDivZero = art_quick_throw_div_zero;
-  qpoints->pThrowNoSuchMethod = art_quick_throw_no_such_method;
   qpoints->pThrowNullPointer = art_quick_throw_null_pointer_exception;
   qpoints->pThrowStackOverflow = art_quick_throw_stack_overflow;
   qpoints->pThrowStringBounds = art_quick_throw_string_bounds;
diff --git a/runtime/entrypoints/quick/quick_entrypoints_list.h b/runtime/entrypoints/quick/quick_entrypoints_list.h
index 74c928a..e402919 100644
--- a/runtime/entrypoints/quick/quick_entrypoints_list.h
+++ b/runtime/entrypoints/quick/quick_entrypoints_list.h
@@ -139,7 +139,6 @@
   V(DeliverException, void, mirror::Object*) \
   V(ThrowArrayBounds, void, int32_t, int32_t) \
   V(ThrowDivZero, void, void) \
-  V(ThrowNoSuchMethod, void, int32_t) \
   V(ThrowNullPointer, void, void) \
   V(ThrowStackOverflow, void, void*) \
   V(ThrowStringBounds, void, int32_t, int32_t) \
diff --git a/runtime/entrypoints/quick/quick_jni_entrypoints.cc b/runtime/entrypoints/quick/quick_jni_entrypoints.cc
index 64f19af..76b5456 100644
--- a/runtime/entrypoints/quick/quick_jni_entrypoints.cc
+++ b/runtime/entrypoints/quick/quick_jni_entrypoints.cc
@@ -114,7 +114,8 @@
   PopLocalReferences(saved_local_ref_cookie, self);
 }
 
-extern void JniMethodEndSynchronized(uint32_t saved_local_ref_cookie, jobject locked,
+extern void JniMethodEndSynchronized(uint32_t saved_local_ref_cookie,
+                                     jobject locked,
                                      Thread* self) {
   GoToRunnable(self);
   UnlockJniSynchronizedMethod(locked, self);  // Must decode before pop.
@@ -135,13 +136,17 @@
   PopLocalReferences(saved_local_ref_cookie, self);
   // Process result.
   if (UNLIKELY(self->GetJniEnv()->check_jni)) {
-    CheckReferenceResult(o, self);
+    // CheckReferenceResult can resolve types.
+    StackHandleScope<1> hs(self);
+    HandleWrapper<mirror::Object> h_obj(hs.NewHandleWrapper(&o));
+    CheckReferenceResult(h_obj, self);
   }
   VerifyObject(o);
   return o;
 }
 
-extern mirror::Object* JniMethodEndWithReference(jobject result, uint32_t saved_local_ref_cookie,
+extern mirror::Object* JniMethodEndWithReference(jobject result,
+                                                 uint32_t saved_local_ref_cookie,
                                                  Thread* self) {
   GoToRunnable(self);
   return JniMethodEndWithReferenceHandleResult(result, saved_local_ref_cookie, self);
@@ -149,7 +154,8 @@
 
 extern mirror::Object* JniMethodEndWithReferenceSynchronized(jobject result,
                                                              uint32_t saved_local_ref_cookie,
-                                                             jobject locked, Thread* self) {
+                                                             jobject locked,
+                                                             Thread* self) {
   GoToRunnable(self);
   UnlockJniSynchronizedMethod(locked, self);
   return JniMethodEndWithReferenceHandleResult(result, saved_local_ref_cookie, self);
diff --git a/runtime/entrypoints/quick/quick_throw_entrypoints.cc b/runtime/entrypoints/quick/quick_throw_entrypoints.cc
index 67cae8a..a205b17 100644
--- a/runtime/entrypoints/quick/quick_throw_entrypoints.cc
+++ b/runtime/entrypoints/quick/quick_throw_entrypoints.cc
@@ -101,13 +101,6 @@
   self->QuickDeliverException();
 }
 
-extern "C" NO_RETURN void artThrowNoSuchMethodFromCode(int32_t method_idx, Thread* self)
-    REQUIRES_SHARED(Locks::mutator_lock_) {
-  ScopedQuickEntrypointChecks sqec(self);
-  ThrowNoSuchMethodError(method_idx);
-  self->QuickDeliverException();
-}
-
 extern "C" NO_RETURN void artThrowClassCastException(mirror::Class* dest_type,
                                                      mirror::Class* src_type,
                                                      Thread* self)
diff --git a/runtime/entrypoints/quick/quick_trampoline_entrypoints.cc b/runtime/entrypoints/quick/quick_trampoline_entrypoints.cc
index 3043c83..3c6f807 100644
--- a/runtime/entrypoints/quick/quick_trampoline_entrypoints.cc
+++ b/runtime/entrypoints/quick/quick_trampoline_entrypoints.cc
@@ -1961,8 +1961,12 @@
 
   // Run the visitor and update sp.
   BuildGenericJniFrameVisitor visitor(self, called->IsStatic(), shorty, shorty_len, &sp);
-  visitor.VisitArguments();
-  visitor.FinalizeHandleScope(self);
+  {
+    ScopedAssertNoThreadSuspension sants(__FUNCTION__);
+    visitor.VisitArguments();
+    // FinalizeHandleScope pushes the handle scope on the thread.
+    visitor.FinalizeHandleScope(self);
+  }
 
   // Fix up managed-stack things in Thread.
   self->SetTopOfStack(sp);
diff --git a/runtime/entrypoints_order_test.cc b/runtime/entrypoints_order_test.cc
index b102334..03254ab 100644
--- a/runtime/entrypoints_order_test.cc
+++ b/runtime/entrypoints_order_test.cc
@@ -122,10 +122,10 @@
 
     // Skip across the entrypoints structures.
 
-    EXPECT_OFFSET_DIFFP(Thread, tlsPtr_, thread_local_start, thread_local_objects, sizeof(void*));
-    EXPECT_OFFSET_DIFFP(Thread, tlsPtr_, thread_local_objects, thread_local_pos, sizeof(size_t));
+    EXPECT_OFFSET_DIFFP(Thread, tlsPtr_, thread_local_start, thread_local_pos, sizeof(void*));
     EXPECT_OFFSET_DIFFP(Thread, tlsPtr_, thread_local_pos, thread_local_end, sizeof(void*));
-    EXPECT_OFFSET_DIFFP(Thread, tlsPtr_, thread_local_end, mterp_current_ibase, sizeof(void*));
+    EXPECT_OFFSET_DIFFP(Thread, tlsPtr_, thread_local_end, thread_local_objects, sizeof(void*));
+    EXPECT_OFFSET_DIFFP(Thread, tlsPtr_, thread_local_objects, mterp_current_ibase, sizeof(size_t));
     EXPECT_OFFSET_DIFFP(Thread, tlsPtr_, mterp_current_ibase, mterp_default_ibase, sizeof(void*));
     EXPECT_OFFSET_DIFFP(Thread, tlsPtr_, mterp_default_ibase, mterp_alt_ibase, sizeof(void*));
     EXPECT_OFFSET_DIFFP(Thread, tlsPtr_, mterp_alt_ibase, rosalloc_runs, sizeof(void*));
@@ -288,8 +288,7 @@
 
     EXPECT_OFFSET_DIFFNP(QuickEntryPoints, pDeliverException, pThrowArrayBounds, sizeof(void*));
     EXPECT_OFFSET_DIFFNP(QuickEntryPoints, pThrowArrayBounds, pThrowDivZero, sizeof(void*));
-    EXPECT_OFFSET_DIFFNP(QuickEntryPoints, pThrowDivZero, pThrowNoSuchMethod, sizeof(void*));
-    EXPECT_OFFSET_DIFFNP(QuickEntryPoints, pThrowNoSuchMethod, pThrowNullPointer, sizeof(void*));
+    EXPECT_OFFSET_DIFFNP(QuickEntryPoints, pThrowDivZero, pThrowNullPointer, sizeof(void*));
     EXPECT_OFFSET_DIFFNP(QuickEntryPoints, pThrowNullPointer, pThrowStackOverflow, sizeof(void*));
     EXPECT_OFFSET_DIFFNP(QuickEntryPoints, pThrowStackOverflow, pThrowStringBounds, sizeof(void*));
     EXPECT_OFFSET_DIFFNP(QuickEntryPoints, pThrowStringBounds, pDeoptimize, sizeof(void*));
diff --git a/runtime/experimental_flags.h b/runtime/experimental_flags.h
index 7faa2dc..54d2c35 100644
--- a/runtime/experimental_flags.h
+++ b/runtime/experimental_flags.h
@@ -31,7 +31,8 @@
   };
 
   constexpr ExperimentalFlags() : value_(0x0000) {}
-  constexpr ExperimentalFlags(decltype(kNone) t) : value_(static_cast<uint32_t>(t)) {}
+  constexpr ExperimentalFlags(decltype(kNone) t)  // NOLINT, implicit
+      : value_(static_cast<uint32_t>(t)) {}
 
   constexpr operator decltype(kNone)() const {
     return static_cast<decltype(kNone)>(value_);
diff --git a/runtime/gc/collector/concurrent_copying.cc b/runtime/gc/collector/concurrent_copying.cc
index 975ac36..247cb96 100644
--- a/runtime/gc/collector/concurrent_copying.cc
+++ b/runtime/gc/collector/concurrent_copying.cc
@@ -2043,13 +2043,23 @@
   }
   DCHECK(to_ref != nullptr);
 
+  // Copy the object excluding the lock word since that is handled in the loop.
+  to_ref->SetClass(from_ref->GetClass<kVerifyNone, kWithoutReadBarrier>());
+  const size_t kObjectHeaderSize = sizeof(mirror::Object);
+  DCHECK_GE(obj_size, kObjectHeaderSize);
+  static_assert(kObjectHeaderSize == sizeof(mirror::HeapReference<mirror::Class>) +
+                    sizeof(LockWord),
+                "Object header size does not match");
+  // Memcpy can tear for words since it may do byte copy. It is only safe to do this since the
+  // object in the from space is immutable other than the lock word. b/31423258
+  memcpy(reinterpret_cast<uint8_t*>(to_ref) + kObjectHeaderSize,
+         reinterpret_cast<const uint8_t*>(from_ref) + kObjectHeaderSize,
+         obj_size - kObjectHeaderSize);
+
   // Attempt to install the forward pointer. This is in a loop as the
   // lock word atomic write can fail.
   while (true) {
-    // Copy the object. TODO: copy only the lockword in the second iteration and on?
-    memcpy(to_ref, from_ref, obj_size);
-
-    LockWord old_lock_word = to_ref->GetLockWord(false);
+    LockWord old_lock_word = from_ref->GetLockWord(false);
 
     if (old_lock_word.GetState() == LockWord::kForwardingAddress) {
       // Lost the race. Another thread (either GC or mutator) stored
@@ -2087,11 +2097,14 @@
       to_ref = reinterpret_cast<mirror::Object*>(old_lock_word.ForwardingAddress());
       CHECK(to_ref != nullptr);
       CHECK_NE(to_ref, lost_fwd_ptr);
-      CHECK(region_space_->IsInToSpace(to_ref) || heap_->non_moving_space_->HasAddress(to_ref));
+      CHECK(region_space_->IsInToSpace(to_ref) || heap_->non_moving_space_->HasAddress(to_ref))
+          << "to_ref=" << to_ref << " " << heap_->DumpSpaces();
       CHECK_NE(to_ref->GetLockWord(false).GetState(), LockWord::kForwardingAddress);
       return to_ref;
     }
 
+    // Copy the old lock word over since we did not copy it yet.
+    to_ref->SetLockWord(old_lock_word, false);
     // Set the gray ptr.
     if (kUseBakerReadBarrier) {
       to_ref->SetReadBarrierPointer(ReadBarrier::GrayPtr());
diff --git a/runtime/gc/collector/concurrent_copying.h b/runtime/gc/collector/concurrent_copying.h
index 1ef0aea..53473f0 100644
--- a/runtime/gc/collector/concurrent_copying.h
+++ b/runtime/gc/collector/concurrent_copying.h
@@ -61,9 +61,9 @@
   // pages.
   static constexpr bool kGrayDirtyImmuneObjects = true;
 
-  ConcurrentCopying(Heap* heap,
-                    const std::string& name_prefix = "",
-                    bool measure_read_barrier_slow_path = false);
+  explicit ConcurrentCopying(Heap* heap,
+                             const std::string& name_prefix = "",
+                             bool measure_read_barrier_slow_path = false);
   ~ConcurrentCopying();
 
   virtual void RunPhases() OVERRIDE
diff --git a/runtime/gc/collector/garbage_collector.h b/runtime/gc/collector/garbage_collector.h
index 6afe876..4ffa254 100644
--- a/runtime/gc/collector/garbage_collector.h
+++ b/runtime/gc/collector/garbage_collector.h
@@ -44,7 +44,7 @@
 namespace collector {
 
 struct ObjectBytePair {
-  ObjectBytePair(uint64_t num_objects = 0, int64_t num_bytes = 0)
+  explicit ObjectBytePair(uint64_t num_objects = 0, int64_t num_bytes = 0)
       : objects(num_objects), bytes(num_bytes) {}
   void Add(const ObjectBytePair& other) {
     objects += other.objects;
diff --git a/runtime/gc/collector_type.h b/runtime/gc/collector_type.h
index b342cc7..7014357 100644
--- a/runtime/gc/collector_type.h
+++ b/runtime/gc/collector_type.h
@@ -55,6 +55,8 @@
   kCollectorTypeClassLinker,
   // JIT Code cache fake collector.
   kCollectorTypeJitCodeCache,
+  // Fake collector for installing/removing a system-weak holder.
+  kCollectorTypeAddRemoveSystemWeakHolder,
 };
 std::ostream& operator<<(std::ostream& os, const CollectorType& collector_type);
 
diff --git a/runtime/gc/gc_cause.h b/runtime/gc/gc_cause.h
index 4348a41..f54f0e4 100644
--- a/runtime/gc/gc_cause.h
+++ b/runtime/gc/gc_cause.h
@@ -51,6 +51,8 @@
   kGcCauseClassLinker,
   // Not a real GC cause, used to implement exclusion between code cache metadata and GC.
   kGcCauseJitCodeCache,
+  // Not a real GC cause, used to add or remove system-weak holders.
+  kGcCauseAddRemoveSystemWeakHolder,
 };
 
 const char* PrettyCause(GcCause cause);
diff --git a/runtime/gc/heap.cc b/runtime/gc/heap.cc
index 600aff1..cb5226b 100644
--- a/runtime/gc/heap.cc
+++ b/runtime/gc/heap.cc
@@ -1011,7 +1011,7 @@
     DecrementDisableMovingGC(self);
   } else {
     // GCs can move objects, so don't allow this.
-    ScopedAssertNoThreadSuspension ants(self, "Visiting objects");
+    ScopedAssertNoThreadSuspension ants("Visiting objects");
     DCHECK(region_space_ == nullptr);
     VisitObjectsInternal(callback, arg);
   }
diff --git a/runtime/gc/system_weak.h b/runtime/gc/system_weak.h
new file mode 100644
index 0000000..3910a28
--- /dev/null
+++ b/runtime/gc/system_weak.h
@@ -0,0 +1,89 @@
+/*
+ * 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.
+ */
+
+#ifndef ART_RUNTIME_GC_SYSTEM_WEAK_H_
+#define ART_RUNTIME_GC_SYSTEM_WEAK_H_
+
+#include "base/mutex.h"
+#include "object_callbacks.h"
+#include "thread-inl.h"
+
+namespace art {
+namespace gc {
+
+class AbstractSystemWeakHolder {
+ public:
+  virtual ~AbstractSystemWeakHolder() {}
+
+  virtual void Allow() REQUIRES_SHARED(Locks::mutator_lock_) = 0;
+  virtual void Disallow() REQUIRES_SHARED(Locks::mutator_lock_) = 0;
+  virtual void Broadcast() REQUIRES_SHARED(Locks::mutator_lock_) = 0;
+
+  virtual void Sweep(IsMarkedVisitor* visitor) REQUIRES_SHARED(Locks::mutator_lock_) = 0;
+};
+
+class SystemWeakHolder : public AbstractSystemWeakHolder {
+ public:
+  explicit SystemWeakHolder(LockLevel level)
+      : allow_disallow_lock_("SystemWeakHolder", level),
+        new_weak_condition_("SystemWeakHolder new condition", allow_disallow_lock_),
+        allow_new_system_weak_(true) {
+  }
+  virtual ~SystemWeakHolder() {}
+
+  void Allow() OVERRIDE
+      REQUIRES_SHARED(Locks::mutator_lock_)
+      REQUIRES(!allow_disallow_lock_) {
+    CHECK(!kUseReadBarrier);
+    MutexLock mu(Thread::Current(), allow_disallow_lock_);
+    allow_new_system_weak_ = true;
+    new_weak_condition_.Broadcast(Thread::Current());
+  }
+
+  void Disallow() OVERRIDE
+      REQUIRES_SHARED(Locks::mutator_lock_)
+      REQUIRES(!allow_disallow_lock_) {
+    CHECK(!kUseReadBarrier);
+    MutexLock mu(Thread::Current(), allow_disallow_lock_);
+    allow_new_system_weak_ = false;
+  }
+
+  void Broadcast() OVERRIDE
+      REQUIRES_SHARED(Locks::mutator_lock_)
+      REQUIRES(!allow_disallow_lock_) {
+    CHECK(kUseReadBarrier);
+    MutexLock mu(Thread::Current(), allow_disallow_lock_);
+    new_weak_condition_.Broadcast(Thread::Current());
+  }
+
+ protected:
+  void Wait(Thread* self) REQUIRES_SHARED(allow_disallow_lock_) {
+    // Wait for GC's sweeping to complete and allow new records
+    while (UNLIKELY((!kUseReadBarrier && !allow_new_system_weak_) ||
+                    (kUseReadBarrier && !self->GetWeakRefAccessEnabled()))) {
+      new_weak_condition_.WaitHoldingLocks(self);
+    }
+  }
+
+  Mutex allow_disallow_lock_;
+  ConditionVariable new_weak_condition_ GUARDED_BY(allow_disallow_lock_);
+  bool allow_new_system_weak_ GUARDED_BY(allow_disallow_lock_);
+};
+
+}  // namespace gc
+}  // namespace art
+
+#endif  // ART_RUNTIME_GC_SYSTEM_WEAK_H_
diff --git a/runtime/gc/system_weak_test.cc b/runtime/gc/system_weak_test.cc
new file mode 100644
index 0000000..7c1ec8a
--- /dev/null
+++ b/runtime/gc/system_weak_test.cc
@@ -0,0 +1,211 @@
+/*
+ * 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 "system_weak.h"
+
+#include <stdint.h>
+#include <stdio.h>
+#include <memory>
+
+#include "base/mutex.h"
+#include "collector_type.h"
+#include "common_runtime_test.h"
+#include "handle_scope-inl.h"
+#include "heap.h"
+#include "mirror/string.h"
+#include "scoped_thread_state_change.h"
+#include "thread_list.h"
+
+namespace art {
+namespace gc {
+
+class SystemWeakTest : public CommonRuntimeTest {
+};
+
+struct CountingSystemWeakHolder : public SystemWeakHolder {
+  CountingSystemWeakHolder()
+      : SystemWeakHolder(kAllocTrackerLock),
+        allow_count_(0),
+        disallow_count_(0),
+        sweep_count_(0) {}
+
+  void Allow() OVERRIDE
+      REQUIRES_SHARED(Locks::mutator_lock_)
+      REQUIRES(!allow_disallow_lock_) {
+    SystemWeakHolder::Allow();
+
+    allow_count_++;
+  }
+
+  void Disallow() OVERRIDE
+      REQUIRES_SHARED(Locks::mutator_lock_)
+      REQUIRES(!allow_disallow_lock_) {
+    SystemWeakHolder::Disallow();
+
+    disallow_count_++;
+  }
+
+  void Broadcast() OVERRIDE
+      REQUIRES_SHARED(Locks::mutator_lock_)
+      REQUIRES(!allow_disallow_lock_) {
+    SystemWeakHolder::Broadcast();
+
+    allow_count_++;
+  }
+
+  void Sweep(IsMarkedVisitor* visitor) OVERRIDE
+      REQUIRES_SHARED(Locks::mutator_lock_)
+      REQUIRES(!allow_disallow_lock_) {
+    MutexLock mu(Thread::Current(), allow_disallow_lock_);
+    mirror::Object* old_object = weak_.Read<kWithoutReadBarrier>();
+    mirror::Object* new_object = old_object == nullptr ? nullptr : visitor->IsMarked(old_object);
+    weak_ = GcRoot<mirror::Object>(new_object);
+
+    sweep_count_++;
+  }
+
+  GcRoot<mirror::Object> Get()
+      REQUIRES_SHARED(Locks::mutator_lock_)
+      REQUIRES(!allow_disallow_lock_) {
+    Thread* self = Thread::Current();
+    MutexLock mu(self, allow_disallow_lock_);
+    Wait(self);
+
+    return weak_;
+  }
+
+  void Set(GcRoot<mirror::Object> obj)
+      REQUIRES_SHARED(Locks::mutator_lock_)
+      REQUIRES(!allow_disallow_lock_) {
+    Thread* self = Thread::Current();
+    MutexLock mu(self, allow_disallow_lock_);
+    Wait(self);
+
+    weak_ = obj;
+  }
+
+  size_t allow_count_;
+  size_t disallow_count_;
+  size_t sweep_count_;
+  GcRoot<mirror::Object> weak_ GUARDED_BY(allow_disallow_lock_);
+};
+
+static bool CollectorDoesAllowOrBroadcast() {
+  CollectorType type = Runtime::Current()->GetHeap()->CurrentCollectorType();
+  switch (type) {
+    case CollectorType::kCollectorTypeCMS:
+    case CollectorType::kCollectorTypeCC:
+      return true;
+
+    default:
+      return false;
+  }
+}
+
+static bool CollectorDoesDisallow() {
+  CollectorType type = Runtime::Current()->GetHeap()->CurrentCollectorType();
+  switch (type) {
+    case CollectorType::kCollectorTypeCMS:
+      return true;
+
+    default:
+      return false;
+  }
+}
+
+TEST_F(SystemWeakTest, Keep) {
+  CountingSystemWeakHolder cswh;
+  Runtime::Current()->AddSystemWeakHolder(&cswh);
+
+  ScopedObjectAccess soa(Thread::Current());
+
+  StackHandleScope<1> hs(soa.Self());
+
+  // We use Strings because they are very easy to allocate.
+  Handle<mirror::String> s(hs.NewHandle(mirror::String::AllocFromModifiedUtf8(soa.Self(), "ABC")));
+  cswh.Set(GcRoot<mirror::Object>(s.Get()));
+
+  // Trigger a GC.
+  Runtime::Current()->GetHeap()->CollectGarbage(false);
+
+  // Expect the holder to have been called.
+  EXPECT_EQ(CollectorDoesAllowOrBroadcast() ? 1U : 0U, cswh.allow_count_);
+  EXPECT_EQ(CollectorDoesDisallow() ? 1U : 0U, cswh.disallow_count_);
+  EXPECT_EQ(1U, cswh.sweep_count_);
+
+  // Expect the weak to not be cleared.
+  EXPECT_FALSE(cswh.Get().IsNull());
+  EXPECT_EQ(cswh.Get().Read(), s.Get());
+}
+
+TEST_F(SystemWeakTest, Discard) {
+  CountingSystemWeakHolder cswh;
+  Runtime::Current()->AddSystemWeakHolder(&cswh);
+
+  ScopedObjectAccess soa(Thread::Current());
+
+  cswh.Set(GcRoot<mirror::Object>(mirror::String::AllocFromModifiedUtf8(soa.Self(), "ABC")));
+
+  // Trigger a GC.
+  Runtime::Current()->GetHeap()->CollectGarbage(false);
+
+  // Expect the holder to have been called.
+  EXPECT_EQ(CollectorDoesAllowOrBroadcast() ? 1U : 0U, cswh.allow_count_);
+  EXPECT_EQ(CollectorDoesDisallow() ? 1U : 0U, cswh.disallow_count_);
+  EXPECT_EQ(1U, cswh.sweep_count_);
+
+  // Expect the weak to be cleared.
+  EXPECT_TRUE(cswh.Get().IsNull());
+}
+
+TEST_F(SystemWeakTest, Remove) {
+  CountingSystemWeakHolder cswh;
+  Runtime::Current()->AddSystemWeakHolder(&cswh);
+
+  ScopedObjectAccess soa(Thread::Current());
+
+  StackHandleScope<1> hs(soa.Self());
+
+  // We use Strings because they are very easy to allocate.
+  Handle<mirror::String> s(hs.NewHandle(mirror::String::AllocFromModifiedUtf8(soa.Self(), "ABC")));
+  cswh.Set(GcRoot<mirror::Object>(s.Get()));
+
+  // Trigger a GC.
+  Runtime::Current()->GetHeap()->CollectGarbage(false);
+
+  // Expect the holder to have been called.
+  ASSERT_EQ(CollectorDoesAllowOrBroadcast() ? 1U : 0U, cswh.allow_count_);
+  ASSERT_EQ(CollectorDoesDisallow() ? 1U : 0U, cswh.disallow_count_);
+  ASSERT_EQ(1U, cswh.sweep_count_);
+
+  // Expect the weak to not be cleared.
+  ASSERT_FALSE(cswh.Get().IsNull());
+  ASSERT_EQ(cswh.Get().Read(), s.Get());
+
+  // Remove the holder.
+  Runtime::Current()->RemoveSystemWeakHolder(&cswh);
+
+  // Trigger another GC.
+  Runtime::Current()->GetHeap()->CollectGarbage(false);
+
+  // Expectation: no change in the numbers.
+  EXPECT_EQ(CollectorDoesAllowOrBroadcast() ? 1U : 0U, cswh.allow_count_);
+  EXPECT_EQ(CollectorDoesDisallow() ? 1U : 0U, cswh.disallow_count_);
+  EXPECT_EQ(1U, cswh.sweep_count_);
+}
+
+}  // namespace gc
+}  // namespace art
diff --git a/runtime/globals.h b/runtime/globals.h
index aba5661..691bf55 100644
--- a/runtime/globals.h
+++ b/runtime/globals.h
@@ -166,6 +166,12 @@
 
 static constexpr bool kArm32QuickCodeUseSoftFloat = false;
 
+#ifdef ART_ENABLE_VDEX
+static constexpr bool kIsVdexEnabled = true;
+#else
+static constexpr bool kIsVdexEnabled = false;
+#endif
+
 }  // namespace art
 
 #endif  // ART_RUNTIME_GLOBALS_H_
diff --git a/runtime/image.h b/runtime/image.h
index 3a4fa79..da9976a 100644
--- a/runtime/image.h
+++ b/runtime/image.h
@@ -168,13 +168,11 @@
   }
 
   static std::string GetOatLocationFromImageLocation(const std::string& image) {
-    std::string oat_filename = image;
-    if (oat_filename.length() <= 3) {
-      oat_filename += ".oat";
-    } else {
-      oat_filename.replace(oat_filename.length() - 3, 3, "oat");
-    }
-    return oat_filename;
+    return GetLocationFromImageLocation(image, "oat");
+  }
+
+  static std::string GetVdexLocationFromImageLocation(const std::string& image) {
+    return GetLocationFromImageLocation(image, "vdex");
   }
 
   enum ImageMethod {
@@ -299,6 +297,17 @@
   static const uint8_t kImageMagic[4];
   static const uint8_t kImageVersion[4];
 
+  static std::string GetLocationFromImageLocation(const std::string& image,
+                                                  const std::string& extension) {
+    std::string filename = image;
+    if (filename.length() <= 3) {
+      filename += "." + extension;
+    } else {
+      filename.replace(filename.length() - 3, 3, extension);
+    }
+    return filename;
+  }
+
   uint8_t magic_[4];
   uint8_t version_[4];
 
diff --git a/runtime/instrumentation.cc b/runtime/instrumentation.cc
index 388561b..ff43389 100644
--- a/runtime/instrumentation.cc
+++ b/runtime/instrumentation.cc
@@ -966,7 +966,7 @@
                                                    ArtMethod* callee) const {
   // We cannot have thread suspension since that would cause the this_object parameter to
   // potentially become a dangling pointer. An alternative could be to put it in a handle instead.
-  ScopedAssertNoThreadSuspension ants(thread, __FUNCTION__);
+  ScopedAssertNoThreadSuspension ants(__FUNCTION__);
   for (InstrumentationListener* listener : invoke_virtual_or_interface_listeners_) {
     if (listener != nullptr) {
       listener->InvokeVirtualOrInterface(thread, this_object, caller, dex_pc, callee);
diff --git a/runtime/intern_table.cc b/runtime/intern_table.cc
index 1940d67..be061be 100644
--- a/runtime/intern_table.cc
+++ b/runtime/intern_table.cc
@@ -316,8 +316,14 @@
 
 mirror::String* InternTable::InternStrong(int32_t utf16_length, const char* utf8_data) {
   DCHECK(utf8_data != nullptr);
+  Thread* self = Thread::Current();
+  // Try to avoid allocation.
+  mirror::String* s = LookupStrong(self, utf16_length, utf8_data);
+  if (s != nullptr) {
+    return s;
+  }
   return InternStrong(mirror::String::AllocFromModifiedUtf8(
-      Thread::Current(), utf16_length, utf8_data));
+      self, utf16_length, utf8_data));
 }
 
 mirror::String* InternTable::InternStrong(const char* utf8_data) {
diff --git a/runtime/interpreter/interpreter_common.h b/runtime/interpreter/interpreter_common.h
index 9d76685..814adf7 100644
--- a/runtime/interpreter/interpreter_common.h
+++ b/runtime/interpreter/interpreter_common.h
@@ -147,8 +147,7 @@
     jit::Jit* jit = Runtime::Current()->GetJit();
     if (jit != nullptr) {
       if (type == kVirtual || type == kInterface) {
-        jit->InvokeVirtualOrInterface(
-            self, receiver, sf_method, shadow_frame.GetDexPC(), called_method);
+        jit->InvokeVirtualOrInterface(receiver, sf_method, shadow_frame.GetDexPC(), called_method);
       }
       jit->AddSamples(self, sf_method, 1, /*with_backedges*/false);
     }
@@ -195,7 +194,7 @@
     jit::Jit* jit = Runtime::Current()->GetJit();
     if (jit != nullptr) {
       jit->InvokeVirtualOrInterface(
-          self, receiver, shadow_frame.GetMethod(), shadow_frame.GetDexPC(), called_method);
+          receiver, shadow_frame.GetMethod(), shadow_frame.GetDexPC(), called_method);
       jit->AddSamples(self, shadow_frame.GetMethod(), 1, /*with_backedges*/false);
     }
     instrumentation::Instrumentation* instrumentation = Runtime::Current()->GetInstrumentation();
diff --git a/runtime/interpreter/unstarted_runtime.cc b/runtime/interpreter/unstarted_runtime.cc
index c614408..d505aea 100644
--- a/runtime/interpreter/unstarted_runtime.cc
+++ b/runtime/interpreter/unstarted_runtime.cc
@@ -402,7 +402,7 @@
   if (klass->IsProxyClass() || klass->GetDexCache() == nullptr) {
     result->SetL(nullptr);
   }
-  result->SetL(klass->GetDexFile().GetEnclosingClass(klass));
+  result->SetL(annotations::GetEnclosingClass(klass));
 }
 
 void UnstartedRuntime::UnstartedClassGetInnerClassFlags(
diff --git a/runtime/jit/jit.cc b/runtime/jit/jit.cc
index cff2354..d984f45 100644
--- a/runtime/jit/jit.cc
+++ b/runtime/jit/jit.cc
@@ -431,7 +431,7 @@
   const uint8_t* native_pc = nullptr;
 
   {
-    ScopedAssertNoThreadSuspension sts(thread, "Holding OSR method");
+    ScopedAssertNoThreadSuspension sts("Holding OSR method");
     const OatQuickMethodHeader* osr_method = jit->GetCodeCache()->LookupOsrMethodHeader(method);
     if (osr_method == nullptr) {
       // No osr method yet, just return to the interpreter.
@@ -683,12 +683,11 @@
   }
 }
 
-void Jit::InvokeVirtualOrInterface(Thread* thread,
-                                   mirror::Object* this_object,
+void Jit::InvokeVirtualOrInterface(mirror::Object* this_object,
                                    ArtMethod* caller,
                                    uint32_t dex_pc,
                                    ArtMethod* callee ATTRIBUTE_UNUSED) {
-  ScopedAssertNoThreadSuspension ants(thread, __FUNCTION__);
+  ScopedAssertNoThreadSuspension ants(__FUNCTION__);
   DCHECK(this_object != nullptr);
   ProfilingInfo* info = caller->GetProfilingInfo(kRuntimePointerSize);
   if (info != nullptr) {
diff --git a/runtime/jit/jit.h b/runtime/jit/jit.h
index 417a185..35656cd 100644
--- a/runtime/jit/jit.h
+++ b/runtime/jit/jit.h
@@ -30,6 +30,7 @@
 namespace art {
 
 class ArtMethod;
+class ClassLinker;
 struct RuntimeArgumentMap;
 union JValue;
 
@@ -108,8 +109,7 @@
   void AddSamples(Thread* self, ArtMethod* method, uint16_t samples, bool with_backedges)
       REQUIRES_SHARED(Locks::mutator_lock_);
 
-  void InvokeVirtualOrInterface(Thread* thread,
-                                mirror::Object* this_object,
+  void InvokeVirtualOrInterface(mirror::Object* this_object,
                                 ArtMethod* caller,
                                 uint32_t dex_pc,
                                 ArtMethod* callee)
diff --git a/runtime/mirror/abstract_method.h b/runtime/mirror/abstract_method.h
index 22a3ea8..9c20613 100644
--- a/runtime/mirror/abstract_method.h
+++ b/runtime/mirror/abstract_method.h
@@ -63,8 +63,8 @@
 
   HeapReference<mirror::Class> declaring_class_;
   HeapReference<mirror::Class> declaring_class_of_overridden_method_;
-  uint32_t access_flags_;
   uint64_t art_method_;
+  uint32_t access_flags_;
   uint32_t dex_method_index_;
 
   friend struct art::AbstractMethodOffsets;  // for verifying offset information
diff --git a/runtime/mirror/accessible_object.h b/runtime/mirror/accessible_object.h
index 1d934a8..2581ac2 100644
--- a/runtime/mirror/accessible_object.h
+++ b/runtime/mirror/accessible_object.h
@@ -47,9 +47,8 @@
 
  private:
   uint8_t flag_;
-  // Padding required for now since "packed" will cause reflect.Field fields to not be aligned
-  // otherwise.
-  uint8_t padding_[3];
+  // Padding required for correct alignment of subclasses like Executable, Field, etc.
+  uint8_t padding_[1];
 
   DISALLOW_IMPLICIT_CONSTRUCTORS(AccessibleObject);
 };
diff --git a/runtime/mirror/class-inl.h b/runtime/mirror/class-inl.h
index d1d8caa..5a5f717 100644
--- a/runtime/mirror/class-inl.h
+++ b/runtime/mirror/class-inl.h
@@ -371,8 +371,21 @@
     // class rather than the declaring class itself.
     DexCache* referrer_dex_cache = use_referrers_cache ? this->GetDexCache() : dex_cache;
     uint32_t class_idx = referrer_dex_cache->GetDexFile()->GetFieldId(field_idx).class_idx_;
-    // The referenced class has already been resolved with the field, get it from the dex cache.
-    Class* dex_access_to = referrer_dex_cache->GetResolvedType(class_idx);
+    // The referenced class has already been resolved with the field, but may not be in the dex
+    // cache. Using ResolveType here without handles in the caller should be safe since there
+    // should be no thread suspension due to the class being resolved.
+    // TODO: Clean this up to use handles in the caller.
+    Class* dex_access_to;
+    {
+      StackHandleScope<2> hs(Thread::Current());
+      Handle<mirror::DexCache> h_dex_cache(hs.NewHandle(referrer_dex_cache));
+      Handle<mirror::ClassLoader> h_class_loader(hs.NewHandle(access_to->GetClassLoader()));
+      dex_access_to = Runtime::Current()->GetClassLinker()->ResolveType(
+          *referrer_dex_cache->GetDexFile(),
+          class_idx,
+          h_dex_cache,
+          h_class_loader);
+    }
     DCHECK(dex_access_to != nullptr);
     if (UNLIKELY(!this->CanAccess(dex_access_to))) {
       if (throw_on_failure) {
@@ -401,8 +414,21 @@
     // class rather than the declaring class itself.
     DexCache* referrer_dex_cache = use_referrers_cache ? this->GetDexCache() : dex_cache;
     uint32_t class_idx = referrer_dex_cache->GetDexFile()->GetMethodId(method_idx).class_idx_;
-    // The referenced class has already been resolved with the method, get it from the dex cache.
-    Class* dex_access_to = referrer_dex_cache->GetResolvedType(class_idx);
+    // The referenced class has already been resolved with the method, but may not be in the dex
+    // cache. Using ResolveType here without handles in the caller should be safe since there
+    // should be no thread suspension due to the class being resolved.
+    // TODO: Clean this up to use handles in the caller.
+    Class* dex_access_to;
+    {
+      StackHandleScope<2> hs(Thread::Current());
+      Handle<mirror::DexCache> h_dex_cache(hs.NewHandle(referrer_dex_cache));
+      Handle<mirror::ClassLoader> h_class_loader(hs.NewHandle(access_to->GetClassLoader()));
+      dex_access_to = Runtime::Current()->GetClassLinker()->ResolveType(
+          *referrer_dex_cache->GetDexFile(),
+          class_idx,
+          h_dex_cache,
+          h_class_loader);
+    }
     DCHECK(dex_access_to != nullptr);
     if (UNLIKELY(!this->CanAccess(dex_access_to))) {
       if (throw_on_failure) {
diff --git a/runtime/mirror/class.cc b/runtime/mirror/class.cc
index c979c28..f21baed 100644
--- a/runtime/mirror/class.cc
+++ b/runtime/mirror/class.cc
@@ -23,6 +23,7 @@
 #include "class-inl.h"
 #include "dex_cache.h"
 #include "dex_file-inl.h"
+#include "dex_file_annotations.h"
 #include "gc/accounting/card_table-inl.h"
 #include "handle_scope-inl.h"
 #include "method.h"
@@ -784,7 +785,7 @@
     }
     // Though GetDirectInterface() should not cause thread suspension when called
     // from here, it takes a Handle as an argument, so we need to wrap `k`.
-    ScopedAssertNoThreadSuspension ants(self, __FUNCTION__);
+    ScopedAssertNoThreadSuspension ants(__FUNCTION__);
     StackHandleScope<1> hs(self);
     Handle<mirror::Class> h_k(hs.NewHandle(k));
     // Is this field in any of this class' interfaces?
@@ -1214,7 +1215,7 @@
     return default_value;
   }
   uint32_t flags;
-  if (!h_this->GetDexFile().GetInnerClassFlags(h_this, &flags)) {
+  if (!annotations::GetInnerClassFlags(h_this, &flags)) {
     return default_value;
   }
   return flags;
diff --git a/runtime/mirror/class.h b/runtime/mirror/class.h
index 99b7769..548087e 100644
--- a/runtime/mirror/class.h
+++ b/runtime/mirror/class.h
@@ -1505,6 +1505,7 @@
   // java.lang.Class
   static GcRoot<Class> java_lang_Class_;
 
+  ART_FRIEND_TEST(DexCacheTest, TestResolvedFieldAccess);  // For ResolvedFieldAccessTest
   friend struct art::ClassOffsets;  // for verifying offset information
   friend class Object;  // For VisitReferences
   DISALLOW_IMPLICIT_CONSTRUCTORS(Class);
diff --git a/runtime/mirror/dex_cache_test.cc b/runtime/mirror/dex_cache_test.cc
index 175997c..43ba362 100644
--- a/runtime/mirror/dex_cache_test.cc
+++ b/runtime/mirror/dex_cache_test.cc
@@ -64,5 +64,33 @@
   EXPECT_TRUE(linear_alloc->Contains(klass->GetDexCache()->GetResolvedMethods()));
 }
 
+TEST_F(DexCacheTest, TestResolvedFieldAccess) {
+  ScopedObjectAccess soa(Thread::Current());
+  jobject jclass_loader(LoadDex("Packages"));
+  ASSERT_TRUE(jclass_loader != nullptr);
+  Runtime* const runtime = Runtime::Current();
+  ClassLinker* const class_linker = runtime->GetClassLinker();
+  StackHandleScope<3> hs(soa.Self());
+  Handle<mirror::ClassLoader> class_loader(hs.NewHandle(
+      soa.Decode<mirror::ClassLoader*>(jclass_loader)));
+  Handle<mirror::Class> klass1 =
+      hs.NewHandle(class_linker->FindClass(soa.Self(), "Lpackage1/Package1;", class_loader));
+  ASSERT_TRUE(klass1.Get() != nullptr);
+  Handle<mirror::Class> klass2 =
+      hs.NewHandle(class_linker->FindClass(soa.Self(), "Lpackage2/Package2;", class_loader));
+  ASSERT_TRUE(klass2.Get() != nullptr);
+  EXPECT_EQ(klass1->GetDexCache(), klass2->GetDexCache());
+
+  EXPECT_NE(klass1->NumStaticFields(), 0u);
+  for (ArtField& field : klass2->GetSFields()) {
+    EXPECT_FALSE((
+        klass1->ResolvedFieldAccessTest</*throw_on_failure*/ false,
+            /*use_referrers_cache*/ false>(klass2.Get(),
+                                           &field,
+                                           field.GetDexFieldIndex(),
+                                           klass1->GetDexCache())));
+  }
+}
+
 }  // namespace mirror
 }  // namespace art
diff --git a/runtime/mirror/executable.h b/runtime/mirror/executable.h
index 8786657..232fce8 100644
--- a/runtime/mirror/executable.h
+++ b/runtime/mirror/executable.h
@@ -33,6 +33,9 @@
 // C++ mirror of java.lang.reflect.Executable.
 class MANAGED Executable : public AccessibleObject {
  private:
+  uint16_t has_real_parameter_data_;
+  HeapReference<mirror::Array> parameters_;
+
   friend struct art::ExecutableOffsets;  // for verifying offset information
   DISALLOW_IMPLICIT_CONSTRUCTORS(Executable);
 };
diff --git a/runtime/mirror/field.h b/runtime/mirror/field.h
index 7eb9da4..f378568 100644
--- a/runtime/mirror/field.h
+++ b/runtime/mirror/field.h
@@ -99,6 +99,9 @@
       REQUIRES_SHARED(Locks::mutator_lock_) REQUIRES(!Roles::uninterruptible_);
 
  private:
+  // Padding required for matching alignment with the Java peer.
+  uint8_t padding_[2];
+
   HeapReference<mirror::Class> declaring_class_;
   HeapReference<mirror::Class> type_;
   int32_t access_flags_;
diff --git a/runtime/mirror/object_reference.h b/runtime/mirror/object_reference.h
index 583cfc3..f4a3580 100644
--- a/runtime/mirror/object_reference.h
+++ b/runtime/mirror/object_reference.h
@@ -55,7 +55,7 @@
   }
 
  protected:
-  ObjectReference<kPoisonReferences, MirrorType>(MirrorType* mirror_ptr)
+  explicit ObjectReference(MirrorType* mirror_ptr)
       REQUIRES_SHARED(Locks::mutator_lock_)
       : reference_(Compress(mirror_ptr)) {
   }
@@ -87,7 +87,7 @@
     return HeapReference<MirrorType>(mirror_ptr);
   }
  private:
-  HeapReference<MirrorType>(MirrorType* mirror_ptr) REQUIRES_SHARED(Locks::mutator_lock_)
+  explicit HeapReference(MirrorType* mirror_ptr) REQUIRES_SHARED(Locks::mutator_lock_)
       : ObjectReference<kPoisonHeapReferences, MirrorType>(mirror_ptr) {}
 };
 
@@ -104,7 +104,7 @@
   }
 
  private:
-  CompressedReference<MirrorType>(MirrorType* p) REQUIRES_SHARED(Locks::mutator_lock_)
+  explicit CompressedReference(MirrorType* p) REQUIRES_SHARED(Locks::mutator_lock_)
       : mirror::ObjectReference<false, MirrorType>(p) {}
 };
 
diff --git a/runtime/mirror/string-inl.h b/runtime/mirror/string-inl.h
index 86e5139..aea6ff1 100644
--- a/runtime/mirror/string-inl.h
+++ b/runtime/mirror/string-inl.h
@@ -245,8 +245,9 @@
 
 template <bool kIsInstrumented>
 inline String* String::AllocEmptyString(Thread* self, gc::AllocatorType allocator_type) {
-  SetStringCountVisitor visitor(0);
-  return Alloc<kIsInstrumented>(self, 0, allocator_type, visitor);
+  const int32_t length_with_flag = String::GetFlaggedCount(0);
+  SetStringCountVisitor visitor(length_with_flag);
+  return Alloc<kIsInstrumented>(self, length_with_flag, allocator_type, visitor);
 }
 
 template <bool kIsInstrumented>
diff --git a/runtime/native/java_lang_Class.cc b/runtime/native/java_lang_Class.cc
index d89a334..af9b68f 100644
--- a/runtime/native/java_lang_Class.cc
+++ b/runtime/native/java_lang_Class.cc
@@ -23,6 +23,7 @@
 #include "class_linker.h"
 #include "common_throws.h"
 #include "dex_file-inl.h"
+#include "dex_file_annotations.h"
 #include "jni_internal.h"
 #include "nth_caller_visitor.h"
 #include "mirror/class-inl.h"
@@ -454,7 +455,7 @@
   }
   Handle<mirror::Class> annotation_class(hs.NewHandle(soa.Decode<mirror::Class*>(annotationClass)));
   return soa.AddLocalReference<jobject>(
-      klass->GetDexFile().GetAnnotationForClass(klass, annotation_class));
+      annotations::GetAnnotationForClass(klass, annotation_class));
 }
 
 static jobjectArray Class_getDeclaredAnnotations(JNIEnv* env, jobject javaThis) {
@@ -469,7 +470,7 @@
         mirror::ObjectArray<mirror::Object>::Alloc(soa.Self(), annotation_array_class, 0);
     return soa.AddLocalReference<jobjectArray>(empty_array);
   }
-  return soa.AddLocalReference<jobjectArray>(klass->GetDexFile().GetAnnotationsForClass(klass));
+  return soa.AddLocalReference<jobjectArray>(annotations::GetAnnotationsForClass(klass));
 }
 
 static jobjectArray Class_getDeclaredClasses(JNIEnv* env, jobject javaThis) {
@@ -478,7 +479,7 @@
   Handle<mirror::Class> klass(hs.NewHandle(DecodeClass(soa, javaThis)));
   mirror::ObjectArray<mirror::Class>* classes = nullptr;
   if (!klass->IsProxyClass() && klass->GetDexCache() != nullptr) {
-    classes = klass->GetDexFile().GetDeclaredClasses(klass);
+    classes = annotations::GetDeclaredClasses(klass);
   }
   if (classes == nullptr) {
     // Return an empty array instead of a null pointer.
@@ -506,7 +507,7 @@
   if (klass->IsProxyClass() || klass->GetDexCache() == nullptr) {
     return nullptr;
   }
-  return soa.AddLocalReference<jclass>(klass->GetDexFile().GetEnclosingClass(klass));
+  return soa.AddLocalReference<jclass>(annotations::GetEnclosingClass(klass));
 }
 
 static jobject Class_getEnclosingConstructorNative(JNIEnv* env, jobject javaThis) {
@@ -516,7 +517,7 @@
   if (klass->IsProxyClass() || klass->GetDexCache() == nullptr) {
     return nullptr;
   }
-  mirror::Object* method = klass->GetDexFile().GetEnclosingMethod(klass);
+  mirror::Object* method = annotations::GetEnclosingMethod(klass);
   if (method != nullptr) {
     if (method->GetClass() ==
         soa.Decode<mirror::Class*>(WellKnownClasses::java_lang_reflect_Constructor)) {
@@ -533,7 +534,7 @@
   if (klass->IsProxyClass() || klass->GetDexCache() == nullptr) {
     return nullptr;
   }
-  mirror::Object* method = klass->GetDexFile().GetEnclosingMethod(klass);
+  mirror::Object* method = annotations::GetEnclosingMethod(klass);
   if (method != nullptr) {
     if (method->GetClass() ==
         soa.Decode<mirror::Class*>(WellKnownClasses::java_lang_reflect_Method)) {
@@ -558,7 +559,7 @@
     return nullptr;
   }
   mirror::String* class_name = nullptr;
-  if (!klass->GetDexFile().GetInnerClass(klass, &class_name)) {
+  if (!annotations::GetInnerClass(klass, &class_name)) {
     return nullptr;
   }
   return soa.AddLocalReference<jstring>(class_name);
@@ -572,7 +573,7 @@
     return nullptr;
   }
   return soa.AddLocalReference<jobjectArray>(
-      klass->GetDexFile().GetSignatureAnnotationForClass(klass));
+      annotations::GetSignatureAnnotationForClass(klass));
 }
 
 static jboolean Class_isAnonymousClass(JNIEnv* env, jobject javaThis) {
@@ -583,7 +584,7 @@
     return false;
   }
   mirror::String* class_name = nullptr;
-  if (!klass->GetDexFile().GetInnerClass(klass, &class_name)) {
+  if (!annotations::GetInnerClass(klass, &class_name)) {
     return false;
   }
   return class_name == nullptr;
@@ -598,7 +599,7 @@
     return false;
   }
   Handle<mirror::Class> annotation_class(hs.NewHandle(soa.Decode<mirror::Class*>(annotationType)));
-  return klass->GetDexFile().IsClassAnnotationPresent(klass, annotation_class);
+  return annotations::IsClassAnnotationPresent(klass, annotation_class);
 }
 
 static jclass Class_getDeclaringClass(JNIEnv* env, jobject javaThis) {
@@ -612,7 +613,7 @@
   if (Class_isAnonymousClass(env, javaThis)) {
     return nullptr;
   }
-  return soa.AddLocalReference<jclass>(klass->GetDexFile().GetDeclaringClass(klass));
+  return soa.AddLocalReference<jclass>(annotations::GetDeclaringClass(klass));
 }
 
 static jobject Class_newInstance(JNIEnv* env, jobject javaThis) {
@@ -668,8 +669,7 @@
       caller.Assign(GetCallingClass(soa.Self(), 1));
     }
     if (UNLIKELY(caller.Get() != nullptr && !VerifyAccess(
-        soa.Self(), receiver.Get(), declaring_class, constructor->GetAccessFlags(),
-        caller.Get()))) {
+        receiver.Get(), declaring_class, constructor->GetAccessFlags(), caller.Get()))) {
       soa.Self()->ThrowNewExceptionF(
           "Ljava/lang/IllegalAccessException;", "%s is not accessible from %s",
           PrettyMethod(constructor).c_str(), PrettyClass(caller.Get()).c_str());
diff --git a/runtime/native/java_lang_reflect_AbstractMethod.cc b/runtime/native/java_lang_reflect_AbstractMethod.cc
index 33e0dae..254f8db 100644
--- a/runtime/native/java_lang_reflect_AbstractMethod.cc
+++ b/runtime/native/java_lang_reflect_AbstractMethod.cc
@@ -17,6 +17,7 @@
 #include "java_lang_reflect_AbstractMethod.h"
 
 #include "art_method-inl.h"
+#include "dex_file_annotations.h"
 #include "jni_internal.h"
 #include "mirror/class-inl.h"
 #include "mirror/object-inl.h"
@@ -38,7 +39,7 @@
         mirror::ObjectArray<mirror::Object>::Alloc(soa.Self(), annotation_array_class, 0);
     return soa.AddLocalReference<jobjectArray>(empty_array);
   }
-  return soa.AddLocalReference<jobjectArray>(method->GetDexFile()->GetAnnotationsForMethod(method));
+  return soa.AddLocalReference<jobjectArray>(annotations::GetAnnotationsForMethod(method));
 }
 
 static jobject AbstractMethod_getAnnotationNative(JNIEnv* env,
@@ -51,8 +52,7 @@
     return nullptr;
   } else {
     Handle<mirror::Class> klass(hs.NewHandle(soa.Decode<mirror::Class*>(annotationType)));
-    return soa.AddLocalReference<jobject>(
-        method->GetDexFile()->GetAnnotationForMethod(method, klass));
+    return soa.AddLocalReference<jobject>(annotations::GetAnnotationForMethod(method, klass));
   }
 }
 
@@ -63,8 +63,7 @@
     return nullptr;
   }
   StackHandleScope<1> hs(soa.Self());
-  return soa.AddLocalReference<jobjectArray>(
-      method->GetDexFile()->GetSignatureAnnotationForMethod(method));
+  return soa.AddLocalReference<jobjectArray>(annotations::GetSignatureAnnotationForMethod(method));
 }
 
 
@@ -74,8 +73,7 @@
   if (method->IsProxyMethod()) {
     return nullptr;
   } else {
-    return soa.AddLocalReference<jobjectArray>(
-        method->GetDexFile()->GetParameterAnnotations(method));
+    return soa.AddLocalReference<jobjectArray>(annotations::GetParameterAnnotations(method));
   }
 }
 
@@ -89,7 +87,7 @@
   }
   StackHandleScope<1> hs(soa.Self());
   Handle<mirror::Class> klass(hs.NewHandle(soa.Decode<mirror::Class*>(annotationType)));
-  return method->GetDexFile()->IsMethodAnnotationPresent(method, klass);
+  return annotations::IsMethodAnnotationPresent(method, klass);
 }
 
 static JNINativeMethod gMethods[] = {
diff --git a/runtime/native/java_lang_reflect_Constructor.cc b/runtime/native/java_lang_reflect_Constructor.cc
index f699d6b..d001d0c 100644
--- a/runtime/native/java_lang_reflect_Constructor.cc
+++ b/runtime/native/java_lang_reflect_Constructor.cc
@@ -20,6 +20,7 @@
 #include "base/enums.h"
 #include "class_linker.h"
 #include "class_linker-inl.h"
+#include "dex_file_annotations.h"
 #include "jni_internal.h"
 #include "mirror/class-inl.h"
 #include "mirror/method.h"
@@ -35,7 +36,7 @@
   ArtMethod* method = ArtMethod::FromReflectedMethod(soa, javaMethod)
       ->GetInterfaceMethodIfProxy(kRuntimePointerSize);
   mirror::ObjectArray<mirror::Class>* result_array =
-      method->GetDexFile()->GetExceptionTypesForMethod(method);
+      annotations::GetExceptionTypesForMethod(method);
   if (result_array == nullptr) {
     // Return an empty array instead of a null pointer.
     mirror::Class* class_class = mirror::Class::GetJavaLangClass();
diff --git a/runtime/native/java_lang_reflect_Field.cc b/runtime/native/java_lang_reflect_Field.cc
index 5a4ced2..412445f 100644
--- a/runtime/native/java_lang_reflect_Field.cc
+++ b/runtime/native/java_lang_reflect_Field.cc
@@ -20,6 +20,7 @@
 #include "class_linker-inl.h"
 #include "common_throws.h"
 #include "dex_file-inl.h"
+#include "dex_file_annotations.h"
 #include "jni_internal.h"
 #include "mirror/class-inl.h"
 #include "mirror/field.h"
@@ -423,7 +424,7 @@
     return nullptr;
   }
   Handle<mirror::Class> klass(hs.NewHandle(soa.Decode<mirror::Class*>(annotationType)));
-  return soa.AddLocalReference<jobject>(field->GetDexFile()->GetAnnotationForField(field, klass));
+  return soa.AddLocalReference<jobject>(annotations::GetAnnotationForField(field, klass));
 }
 
 static jobjectArray Field_getDeclaredAnnotations(JNIEnv* env, jobject javaField) {
@@ -437,7 +438,7 @@
         mirror::ObjectArray<mirror::Object>::Alloc(soa.Self(), annotation_array_class, 0);
     return soa.AddLocalReference<jobjectArray>(empty_array);
   }
-  return soa.AddLocalReference<jobjectArray>(field->GetDexFile()->GetAnnotationsForField(field));
+  return soa.AddLocalReference<jobjectArray>(annotations::GetAnnotationsForField(field));
 }
 
 static jobjectArray Field_getSignatureAnnotation(JNIEnv* env, jobject javaField) {
@@ -446,8 +447,7 @@
   if (field->GetDeclaringClass()->IsProxyClass()) {
     return nullptr;
   }
-  return soa.AddLocalReference<jobjectArray>(
-      field->GetDexFile()->GetSignatureAnnotationForField(field));
+  return soa.AddLocalReference<jobjectArray>(annotations::GetSignatureAnnotationForField(field));
 }
 
 static jboolean Field_isAnnotationPresentNative(JNIEnv* env, jobject javaField,
@@ -459,7 +459,7 @@
     return false;
   }
   Handle<mirror::Class> klass(hs.NewHandle(soa.Decode<mirror::Class*>(annotationType)));
-  return field->GetDexFile()->IsFieldAnnotationPresent(field, klass);
+  return annotations::IsFieldAnnotationPresent(field, klass);
 }
 
 static JNINativeMethod gMethods[] = {
diff --git a/runtime/native/java_lang_reflect_Method.cc b/runtime/native/java_lang_reflect_Method.cc
index 3360f41..b8efb14 100644
--- a/runtime/native/java_lang_reflect_Method.cc
+++ b/runtime/native/java_lang_reflect_Method.cc
@@ -20,6 +20,7 @@
 #include "base/enums.h"
 #include "class_linker.h"
 #include "class_linker-inl.h"
+#include "dex_file_annotations.h"
 #include "jni_internal.h"
 #include "mirror/class-inl.h"
 #include "mirror/object-inl.h"
@@ -36,7 +37,7 @@
   if (!method->GetDeclaringClass()->IsAnnotation()) {
     return nullptr;
   }
-  return soa.AddLocalReference<jobject>(method->GetDexFile()->GetAnnotationDefaultValue(method));
+  return soa.AddLocalReference<jobject>(annotations::GetAnnotationDefaultValue(method));
 }
 
 static jobjectArray Method_getExceptionTypes(JNIEnv* env, jobject javaMethod) {
@@ -58,7 +59,7 @@
     return soa.AddLocalReference<jobjectArray>(declared_exceptions->Clone(soa.Self()));
   } else {
     mirror::ObjectArray<mirror::Class>* result_array =
-        method->GetDexFile()->GetExceptionTypesForMethod(method);
+        annotations::GetExceptionTypesForMethod(method);
     if (result_array == nullptr) {
       // Return an empty array instead of a null pointer
       mirror::Class* class_class = mirror::Class::GetJavaLangClass();
diff --git a/runtime/native/java_lang_reflect_Parameter.cc b/runtime/native/java_lang_reflect_Parameter.cc
new file mode 100644
index 0000000..c2a803c
--- /dev/null
+++ b/runtime/native/java_lang_reflect_Parameter.cc
@@ -0,0 +1,71 @@
+/*
+ * 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 "java_lang_reflect_Parameter.h"
+
+#include "art_method-inl.h"
+#include "common_throws.h"
+#include "dex_file-inl.h"
+#include "dex_file_annotations.h"
+#include "jni_internal.h"
+#include "scoped_fast_native_object_access.h"
+#include "utils.h"
+
+namespace art {
+
+static jobject Parameter_getAnnotationNative(JNIEnv* env,
+                                             jclass,
+                                             jobject javaMethod,
+                                             jint parameterIndex,
+                                             jclass annotationType) {
+  ScopedFastNativeObjectAccess soa(env);
+  if (UNLIKELY(javaMethod == nullptr)) {
+    ThrowNullPointerException("javaMethod == null");
+    return nullptr;
+  }
+
+  ArtMethod* method = ArtMethod::FromReflectedMethod(soa, javaMethod);
+  if (method->IsProxyMethod()) {
+    return nullptr;
+  }
+
+  uint32_t parameter_count = method->GetParameterTypeList()->Size();
+  if (UNLIKELY(parameterIndex < 0 || static_cast<uint32_t>(parameterIndex) >= parameter_count)) {
+    ThrowIllegalArgumentException(
+        StringPrintf("Illegal parameterIndex %d for %s, parameter_count is %d",
+                     parameterIndex,
+                     PrettyMethod(method).c_str(),
+                     parameter_count).c_str());
+    return nullptr;
+  }
+
+  StackHandleScope<1> hs(soa.Self());
+  Handle<mirror::Class> klass(hs.NewHandle(soa.Decode<mirror::Class*>(annotationType)));
+  return soa.AddLocalReference<jobject>(
+      annotations::GetAnnotationForMethodParameter(method, parameterIndex, klass));
+}
+
+static JNINativeMethod gMethods[] = {
+  NATIVE_METHOD(Parameter,
+                getAnnotationNative,
+                "!(Ljava/lang/reflect/Executable;ILjava/lang/Class;)Ljava/lang/annotation/Annotation;"),
+};
+
+void register_java_lang_reflect_Parameter(JNIEnv* env) {
+  REGISTER_NATIVE_METHODS("java/lang/reflect/Parameter");
+}
+
+}  // namespace art
diff --git a/runtime/native/java_lang_reflect_Parameter.h b/runtime/native/java_lang_reflect_Parameter.h
new file mode 100644
index 0000000..f6322b1
--- /dev/null
+++ b/runtime/native/java_lang_reflect_Parameter.h
@@ -0,0 +1,28 @@
+/*
+ * 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.
+ */
+
+#ifndef ART_RUNTIME_NATIVE_JAVA_LANG_REFLECT_PARAMETER_H_
+#define ART_RUNTIME_NATIVE_JAVA_LANG_REFLECT_PARAMETER_H_
+
+#include <jni.h>
+
+namespace art {
+
+void register_java_lang_reflect_Parameter(JNIEnv* env);
+
+}  // namespace art
+
+#endif  // ART_RUNTIME_NATIVE_JAVA_LANG_REFLECT_PARAMETER_H_
diff --git a/runtime/oat.h b/runtime/oat.h
index 35d0c92..12a8298 100644
--- a/runtime/oat.h
+++ b/runtime/oat.h
@@ -171,7 +171,7 @@
 
 class PACKED(4) OatMethodOffsets {
  public:
-  OatMethodOffsets(uint32_t code_offset = 0);
+  explicit OatMethodOffsets(uint32_t code_offset = 0);
 
   ~OatMethodOffsets();
 
diff --git a/runtime/oat_file.cc b/runtime/oat_file.cc
index 5752fd9..76b71a3 100644
--- a/runtime/oat_file.cc
+++ b/runtime/oat_file.cc
@@ -83,7 +83,8 @@
   virtual ~OatFileBase() {}
 
   template <typename kOatFileBaseSubType>
-  static OatFileBase* OpenOatFile(const std::string& elf_filename,
+  static OatFileBase* OpenOatFile(const std::string& vdex_filename,
+                                  const std::string& elf_filename,
                                   const std::string& location,
                                   uint8_t* requested_base,
                                   uint8_t* oat_file_begin,
@@ -101,6 +102,11 @@
 
   virtual void PreLoad() = 0;
 
+  bool LoadVdex(const std::string& vdex_filename,
+                bool writable,
+                bool low_4gb,
+                std::string* error_msg);
+
   virtual bool Load(const std::string& elf_filename,
                     uint8_t* oat_file_begin,
                     bool writable,
@@ -126,12 +132,17 @@
     end_ = end;
   }
 
+  void SetVdex(VdexFile* vdex) {
+    vdex_.reset(vdex);
+  }
+
  private:
   DISALLOW_COPY_AND_ASSIGN(OatFileBase);
 };
 
 template <typename kOatFileBaseSubType>
-OatFileBase* OatFileBase::OpenOatFile(const std::string& elf_filename,
+OatFileBase* OatFileBase::OpenOatFile(const std::string& vdex_filename,
+                                      const std::string& elf_filename,
                                       const std::string& location,
                                       uint8_t* requested_base,
                                       uint8_t* oat_file_begin,
@@ -144,6 +155,10 @@
 
   ret->PreLoad();
 
+  if (kIsVdexEnabled && !ret->LoadVdex(vdex_filename, writable, low_4gb, error_msg)) {
+    return nullptr;
+  }
+
   if (!ret->Load(elf_filename,
                  oat_file_begin,
                  writable,
@@ -166,6 +181,20 @@
   return ret.release();
 }
 
+bool OatFileBase::LoadVdex(const std::string& vdex_filename,
+                           bool writable,
+                           bool low_4gb,
+                           std::string* error_msg) {
+  vdex_.reset(VdexFile::Open(vdex_filename, writable, low_4gb, error_msg));
+  if (vdex_.get() == nullptr) {
+    *error_msg = StringPrintf("Failed to load vdex file '%s' %s",
+                              vdex_filename.c_str(),
+                              error_msg->c_str());
+    return false;
+  }
+  return true;
+}
+
 bool OatFileBase::ComputeFields(uint8_t* requested_base,
                                 const std::string& file_path,
                                 std::string* error_msg) {
@@ -321,29 +350,29 @@
                                 dex_file_location.c_str());
       return false;
     }
-    if (UNLIKELY(dex_file_offset > Size())) {
+    if (UNLIKELY(dex_file_offset > DexSize())) {
       *error_msg = StringPrintf("In oat file '%s' found OatDexFile #%zu for '%s' with dex file "
                                     "offset %u > %zu",
                                 GetLocation().c_str(),
                                 i,
                                 dex_file_location.c_str(),
                                 dex_file_offset,
-                                Size());
+                                DexSize());
       return false;
     }
-    if (UNLIKELY(Size() - dex_file_offset < sizeof(DexFile::Header))) {
+    if (UNLIKELY(DexSize() - dex_file_offset < sizeof(DexFile::Header))) {
       *error_msg = StringPrintf("In oat file '%s' found OatDexFile #%zu for '%s' with dex file "
                                     "offset %u of %zu but the size of dex file header is %zu",
                                 GetLocation().c_str(),
                                 i,
                                 dex_file_location.c_str(),
                                 dex_file_offset,
-                                Size(),
+                                DexSize(),
                                 sizeof(DexFile::Header));
       return false;
     }
 
-    const uint8_t* dex_file_pointer = Begin() + dex_file_offset;
+    const uint8_t* dex_file_pointer = DexBegin() + dex_file_offset;
     if (UNLIKELY(!DexFile::IsMagicValid(dex_file_pointer))) {
       *error_msg = StringPrintf("In oat file '%s' found OatDexFile #%zu for '%s' with invalid "
                                     "dex file magic '%s'",
@@ -363,7 +392,7 @@
       return false;
     }
     const DexFile::Header* header = reinterpret_cast<const DexFile::Header*>(dex_file_pointer);
-    if (Size() - dex_file_offset < header->file_size_) {
+    if (DexSize() - dex_file_offset < header->file_size_) {
       *error_msg = StringPrintf("In oat file '%s' found OatDexFile #%zu for '%s' with dex file "
                                     "offset %u and size %u truncated at %zu",
                                 GetLocation().c_str(),
@@ -371,7 +400,7 @@
                                 dex_file_location.c_str(),
                                 dex_file_offset,
                                 header->file_size_,
-                                Size());
+                                DexSize());
       return false;
     }
 
@@ -768,6 +797,7 @@
                                  std::string* error_msg);
 
   bool InitializeFromElfFile(ElfFile* elf_file,
+                             VdexFile* vdex_file,
                              const char* abs_dex_location,
                              std::string* error_msg);
 
@@ -844,6 +874,7 @@
 }
 
 bool ElfOatFile::InitializeFromElfFile(ElfFile* elf_file,
+                                       VdexFile* vdex_file,
                                        const char* abs_dex_location,
                                        std::string* error_msg) {
   ScopedTrace trace(__PRETTY_FUNCTION__);
@@ -852,6 +883,7 @@
     return false;
   }
   elf_file_.reset(elf_file);
+  SetVdex(vdex_file);
   uint64_t offset, size;
   bool has_section = elf_file->GetSectionOffsetAndSize(".rodata", &offset, &size);
   CHECK(has_section);
@@ -933,40 +965,47 @@
 }
 
 OatFile* OatFile::OpenWithElfFile(ElfFile* elf_file,
+                                  VdexFile* vdex_file,
                                   const std::string& location,
                                   const char* abs_dex_location,
                                   std::string* error_msg) {
   std::unique_ptr<ElfOatFile> oat_file(new ElfOatFile(location, false /* executable */));
-  return oat_file->InitializeFromElfFile(elf_file, abs_dex_location, error_msg)
+  return oat_file->InitializeFromElfFile(elf_file, vdex_file, abs_dex_location, error_msg)
       ? oat_file.release()
       : nullptr;
 }
 
-OatFile* OatFile::Open(const std::string& filename,
-                       const std::string& location,
+OatFile* OatFile::Open(const std::string& oat_filename,
+                       const std::string& oat_location,
                        uint8_t* requested_base,
                        uint8_t* oat_file_begin,
                        bool executable,
                        bool low_4gb,
                        const char* abs_dex_location,
                        std::string* error_msg) {
-  ScopedTrace trace("Open oat file " + location);
-  CHECK(!filename.empty()) << location;
-  CheckLocation(location);
+  ScopedTrace trace("Open oat file " + oat_location);
+  CHECK(!oat_filename.empty()) << oat_location;
+  CheckLocation(oat_location);
 
-  // Check that the file even exists, fast-fail.
-  if (!OS::FileExists(filename.c_str())) {
-    *error_msg = StringPrintf("File %s does not exist.", filename.c_str());
+  std::string vdex_filename = ReplaceFileExtension(oat_filename, "vdex");
+
+  // Check that the files even exist, fast-fail.
+  if (kIsVdexEnabled && !OS::FileExists(vdex_filename.c_str())) {
+    *error_msg = StringPrintf("File %s does not exist.", vdex_filename.c_str());
+    return nullptr;
+  } else if (!OS::FileExists(oat_filename.c_str())) {
+    *error_msg = StringPrintf("File %s does not exist.", oat_filename.c_str());
     return nullptr;
   }
 
   // Try dlopen first, as it is required for native debuggability. This will fail fast if dlopen is
   // disabled.
-  OatFile* with_dlopen = OatFileBase::OpenOatFile<DlOpenOatFile>(filename,
-                                                                 location,
+  OatFile* with_dlopen = OatFileBase::OpenOatFile<DlOpenOatFile>(vdex_filename,
+                                                                 oat_filename,
+                                                                 oat_location,
                                                                  requested_base,
                                                                  oat_file_begin,
-                                                                 false,
+                                                                 false /* writable */,
                                                                  executable,
                                                                  low_4gb,
                                                                  abs_dex_location,
@@ -975,7 +1014,7 @@
     return with_dlopen;
   }
   if (kPrintDlOpenErrorMessage) {
-    LOG(ERROR) << "Failed to dlopen: " << filename << " with error " << *error_msg;
+    LOG(ERROR) << "Failed to dlopen: " << oat_filename << " with error " << *error_msg;
   }
   // If we aren't trying to execute, we just use our own ElfFile loader for a couple reasons:
   //
@@ -990,11 +1029,12 @@
   //
   // Another independent reason is the absolute placement of boot.oat. dlopen on the host usually
   // does honor the virtual address encoded in the ELF file only for ET_EXEC files, not ET_DYN.
-  OatFile* with_internal = OatFileBase::OpenOatFile<ElfOatFile>(filename,
-                                                                location,
+  OatFile* with_internal = OatFileBase::OpenOatFile<ElfOatFile>(vdex_filename,
+                                                                oat_filename,
+                                                                oat_location,
                                                                 requested_base,
                                                                 oat_file_begin,
-                                                                false,
+                                                                false /* writable */,
                                                                 executable,
                                                                 low_4gb,
                                                                 abs_dex_location,
@@ -1036,6 +1076,7 @@
 
 OatFile::OatFile(const std::string& location, bool is_executable)
     : location_(location),
+      vdex_(nullptr),
       begin_(nullptr),
       end_(nullptr),
       bss_begin_(nullptr),
@@ -1071,6 +1112,14 @@
   return bss_end_;
 }
 
+const uint8_t* OatFile::DexBegin() const {
+  return kIsVdexEnabled ? vdex_->Begin() : Begin();
+}
+
+const uint8_t* OatFile::DexEnd() const {
+  return kIsVdexEnabled ? vdex_->End() : End();
+}
+
 const OatFile::OatDexFile* OatFile::GetOatDexFile(const char* dex_location,
                                                   const uint32_t* dex_location_checksum,
                                                   std::string* error_msg) const {
diff --git a/runtime/oat_file.h b/runtime/oat_file.h
index f5ab9dc..a48791e 100644
--- a/runtime/oat_file.h
+++ b/runtime/oat_file.h
@@ -30,6 +30,7 @@
 #include "oat.h"
 #include "os.h"
 #include "utils.h"
+#include "vdex_file.h"
 
 namespace art {
 
@@ -46,6 +47,14 @@
 }  // namespace collector
 }  // namespace gc
 
+// Runtime representation of the OAT file format which holds compiler output.
+// The class opens an OAT file from storage and maps it to memory, typically with
+// dlopen and provides access to its internal data structures (see OatWriter for
+// for more details about the OAT format).
+// In the process of loading OAT, the class also loads the associated VDEX file
+// with the input DEX files (see VdexFile for details about the VDEX format).
+// The raw DEX data are accessible transparently through the OatDexFile objects.
+
 class OatFile {
  public:
   // Special classpath that skips shared library check.
@@ -55,7 +64,9 @@
 
   // Opens an oat file contained within the given elf file. This is always opened as
   // non-executable at the moment.
-  static OatFile* OpenWithElfFile(ElfFile* elf_file, const std::string& location,
+  static OatFile* OpenWithElfFile(ElfFile* elf_file,
+                                  VdexFile* vdex_file,
+                                  const std::string& location,
                                   const char* abs_dex_location,
                                   std::string* error_msg);
   // Open an oat file. Returns null on failure.  Requested base can
@@ -240,12 +251,19 @@
     return BssEnd() - BssBegin();
   }
 
+  size_t DexSize() const {
+    return DexEnd() - DexBegin();
+  }
+
   const uint8_t* Begin() const;
   const uint8_t* End() const;
 
   const uint8_t* BssBegin() const;
   const uint8_t* BssEnd() const;
 
+  const uint8_t* DexBegin() const;
+  const uint8_t* DexEnd() const;
+
   // Returns the absolute dex location for the encoded relative dex location.
   //
   // If not null, abs_dex_location is used to resolve the absolute dex
@@ -279,6 +297,9 @@
   // The image will embed this to link its associated oat file.
   const std::string location_;
 
+  // Pointer to the Vdex file with the Dex files for this Oat file.
+  std::unique_ptr<VdexFile> vdex_;
+
   // Pointer to OatHeader.
   const uint8_t* begin_;
 
diff --git a/runtime/oat_file_assistant.cc b/runtime/oat_file_assistant.cc
index fe6332d..415f991 100644
--- a/runtime/oat_file_assistant.cc
+++ b/runtime/oat_file_assistant.cc
@@ -345,17 +345,6 @@
   return odex_.CompilerFilter();
 }
 
-static std::string ArtFileName(const OatFile* oat_file) {
-  const std::string oat_file_location = oat_file->GetLocation();
-  // Replace extension with .art
-  const size_t last_ext = oat_file_location.find_last_of('.');
-  if (last_ext == std::string::npos) {
-    LOG(ERROR) << "No extension in oat file " << oat_file_location;
-    return std::string();
-  }
-  return oat_file_location.substr(0, last_ext) + ".art";
-}
-
 const std::string* OatFileAssistant::OatFileName() {
   return oat_.Filename();
 }
@@ -565,6 +554,7 @@
     return kUpdateNotAttempted;
   }
   const std::string& oat_file_name = *oat_.Filename();
+  const std::string& vdex_file_name = ReplaceFileExtension(oat_file_name, "vdex");
 
   // dex2oat ignores missing dex files and doesn't report an error.
   // Check explicitly here so we can detect the error properly.
@@ -574,8 +564,22 @@
     return kUpdateNotAttempted;
   }
 
-  std::unique_ptr<File> oat_file;
-  oat_file.reset(OS::CreateEmptyFile(oat_file_name.c_str()));
+  std::unique_ptr<File> vdex_file(OS::CreateEmptyFile(vdex_file_name.c_str()));
+  if (vdex_file.get() == nullptr) {
+    *error_msg = "Generation of oat file " + oat_file_name
+      + " not attempted because the vdex file " + vdex_file_name
+      + " could not be opened.";
+    return kUpdateNotAttempted;
+  }
+
+  if (fchmod(vdex_file->Fd(), 0644) != 0) {
+    *error_msg = "Generation of oat file " + oat_file_name
+      + " not attempted because the vdex file " + vdex_file_name
+      + " could not be made world readable.";
+    return kUpdateNotAttempted;
+  }
+
+  std::unique_ptr<File> oat_file(OS::CreateEmptyFile(oat_file_name.c_str()));
   if (oat_file.get() == nullptr) {
     *error_msg = "Generation of oat file " + oat_file_name
       + " not attempted because the oat file could not be created.";
@@ -591,17 +595,26 @@
 
   std::vector<std::string> args;
   args.push_back("--dex-file=" + dex_location_);
+  args.push_back("--vdex-fd=" + std::to_string(vdex_file->Fd()));
   args.push_back("--oat-fd=" + std::to_string(oat_file->Fd()));
   args.push_back("--oat-location=" + oat_file_name);
 
   if (!Dex2Oat(args, error_msg)) {
-    // Manually delete the file. This ensures there is no garbage left over if
-    // the process unexpectedly died.
+    // Manually delete the oat and vdex files. This ensures there is no garbage
+    // left over if the process unexpectedly died.
+    vdex_file->Erase();
+    unlink(vdex_file_name.c_str());
     oat_file->Erase();
     unlink(oat_file_name.c_str());
     return kUpdateFailed;
   }
 
+  if (vdex_file->FlushCloseOrErase() != 0) {
+    *error_msg = "Unable to close vdex file " + vdex_file_name;
+    unlink(vdex_file_name.c_str());
+    return kUpdateFailed;
+  }
+
   if (oat_file->FlushCloseOrErase() != 0) {
     *error_msg = "Unable to close oat file " + oat_file_name;
     unlink(oat_file_name.c_str());
@@ -830,7 +843,7 @@
 
 std::unique_ptr<gc::space::ImageSpace> OatFileAssistant::OpenImageSpace(const OatFile* oat_file) {
   DCHECK(oat_file != nullptr);
-  std::string art_file = ArtFileName(oat_file);
+  std::string art_file = ReplaceFileExtension(oat_file->GetLocation(), "art");
   if (art_file.empty()) {
     return nullptr;
   }
diff --git a/runtime/oat_quick_method_header.h b/runtime/oat_quick_method_header.h
index abddc6d..ee5002f 100644
--- a/runtime/oat_quick_method_header.h
+++ b/runtime/oat_quick_method_header.h
@@ -30,11 +30,11 @@
 // OatQuickMethodHeader precedes the raw code chunk generated by the compiler.
 class PACKED(4) OatQuickMethodHeader {
  public:
-  OatQuickMethodHeader(uint32_t vmap_table_offset = 0U,
-                       uint32_t frame_size_in_bytes = 0U,
-                       uint32_t core_spill_mask = 0U,
-                       uint32_t fp_spill_mask = 0U,
-                       uint32_t code_size = 0U);
+  explicit OatQuickMethodHeader(uint32_t vmap_table_offset = 0U,
+                                uint32_t frame_size_in_bytes = 0U,
+                                uint32_t core_spill_mask = 0U,
+                                uint32_t fp_spill_mask = 0U,
+                                uint32_t code_size = 0U);
 
   ~OatQuickMethodHeader();
 
diff --git a/runtime/openjdkjvmti/OpenjdkJvmTi.cc b/runtime/openjdkjvmti/OpenjdkJvmTi.cc
index 339c457..d3561c1 100644
--- a/runtime/openjdkjvmti/OpenjdkJvmTi.cc
+++ b/runtime/openjdkjvmti/OpenjdkJvmTi.cc
@@ -32,6 +32,7 @@
 #include <jni.h>
 #include "openjdkjvmti/jvmti.h"
 
+#include "art_jvmti.h"
 #include "gc_root-inl.h"
 #include "globals.h"
 #include "jni_env_ext-inl.h"
@@ -44,25 +45,6 @@
 
 namespace openjdkjvmti {
 
-extern const jvmtiInterface_1 gJvmtiInterface;
-
-// A structure that is a jvmtiEnv with additional information for the runtime.
-struct ArtJvmTiEnv : public jvmtiEnv {
-  art::JavaVMExt* art_vm;
-  void* local_data;
-
-  explicit ArtJvmTiEnv(art::JavaVMExt* runtime) : art_vm(runtime), local_data(nullptr) {
-    functions = &gJvmtiInterface;
-  }
-};
-
-// Macro and constexpr to make error values less annoying to write.
-#define ERR(e) JVMTI_ERROR_ ## e
-static constexpr jvmtiError OK = JVMTI_ERROR_NONE;
-
-// Special error code for unimplemented functions in JVMTI
-static constexpr jvmtiError ERR(NOT_IMPLEMENTED) = JVMTI_ERROR_NOT_AVAILABLE;
-
 class JvmtiFunctions {
  private:
   static bool IsValidEnv(jvmtiEnv* env) {
diff --git a/runtime/openjdkjvmti/art_jvmti.h b/runtime/openjdkjvmti/art_jvmti.h
new file mode 100644
index 0000000..a2c6882
--- /dev/null
+++ b/runtime/openjdkjvmti/art_jvmti.h
@@ -0,0 +1,74 @@
+/* Copyright (C) 2016 The Android Open Source Project
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This file implements interfaces from the file jvmti.h. This implementation
+ * is licensed under the same terms as the file jvmti.h.  The
+ * copyright and license information for the file jvmti.h follows.
+ *
+ * Copyright (c) 2003, 2011, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+#ifndef ART_RUNTIME_OPENJDKJVMTI_ART_JVMTI_H_
+#define ART_RUNTIME_OPENJDKJVMTI_ART_JVMTI_H_
+
+#include <jni.h>
+
+#include "java_vm_ext.h"
+#include "jni_env_ext.h"
+#include "jvmti.h"
+
+namespace openjdkjvmti {
+
+extern const jvmtiInterface_1 gJvmtiInterface;
+
+// A structure that is a jvmtiEnv with additional information for the runtime.
+struct ArtJvmTiEnv : public jvmtiEnv {
+  art::JavaVMExt* art_vm;
+  void* local_data;
+
+  explicit ArtJvmTiEnv(art::JavaVMExt* runtime) : art_vm(runtime), local_data(nullptr) {
+    functions = &gJvmtiInterface;
+  }
+};
+
+// Macro and constexpr to make error values less annoying to write.
+#define ERR(e) JVMTI_ERROR_ ## e
+static constexpr jvmtiError OK = JVMTI_ERROR_NONE;
+
+// Special error code for unimplemented functions in JVMTI
+static constexpr jvmtiError ERR(NOT_IMPLEMENTED) = JVMTI_ERROR_NOT_AVAILABLE;
+
+static inline JNIEnv* GetJniEnv(jvmtiEnv* env) {
+  JNIEnv* ret_value = nullptr;
+  jint res = reinterpret_cast<ArtJvmTiEnv*>(env)->art_vm->GetEnv(
+      reinterpret_cast<void**>(&ret_value), JNI_VERSION_1_1);
+  if (res != JNI_OK) {
+    return nullptr;
+  }
+  return ret_value;
+}
+
+}  // namespace openjdkjvmti
+
+#endif  // ART_RUNTIME_OPENJDKJVMTI_ART_JVMTI_H_
diff --git a/runtime/quick/inline_method_analyser.h b/runtime/quick/inline_method_analyser.h
index 356e290..2df2ced 100644
--- a/runtime/quick/inline_method_analyser.h
+++ b/runtime/quick/inline_method_analyser.h
@@ -33,6 +33,7 @@
 namespace verifier {
 class MethodVerifier;
 }  // namespace verifier
+class ArtMethod;
 
 enum InlineMethodOpcode : uint16_t {
   kIntrinsicDoubleCvt,
diff --git a/runtime/quick_exception_handler.cc b/runtime/quick_exception_handler.cc
index 55aba2b..b3f29c2 100644
--- a/runtime/quick_exception_handler.cc
+++ b/runtime/quick_exception_handler.cc
@@ -160,8 +160,8 @@
       LOG(INFO) << "Handler is upcall";
     }
     if (handler_method_ != nullptr) {
-      const DexFile& dex_file = *handler_method_->GetDeclaringClass()->GetDexCache()->GetDexFile();
-      int line_number = dex_file.GetLineNumFromPC(handler_method_, handler_dex_pc_);
+      const DexFile* dex_file = handler_method_->GetDeclaringClass()->GetDexCache()->GetDexFile();
+      int line_number = annotations::GetLineNumFromPC(dex_file, handler_method_, handler_dex_pc_);
       LOG(INFO) << "Handler: " << PrettyMethod(handler_method_) << " (line: " << line_number << ")";
     }
   }
diff --git a/runtime/reflection.cc b/runtime/reflection.cc
index f2af3da..67e3fe8 100644
--- a/runtime/reflection.cc
+++ b/runtime/reflection.cc
@@ -625,8 +625,12 @@
 
   // If method is not set to be accessible, verify it can be accessed by the caller.
   mirror::Class* calling_class = nullptr;
-  if (!accessible && !VerifyAccess(soa.Self(), receiver, declaring_class, m->GetAccessFlags(),
-                                   &calling_class, num_frames)) {
+  if (!accessible && !VerifyAccess(soa.Self(),
+                                   receiver,
+                                   declaring_class,
+                                   m->GetAccessFlags(),
+                                   &calling_class,
+                                   num_frames)) {
     ThrowIllegalAccessException(
         StringPrintf("Class %s cannot access %s method %s of class %s",
             calling_class == nullptr ? "null" : PrettyClass(calling_class).c_str(),
@@ -857,15 +861,17 @@
     return false;
   }
   *calling_class = klass;
-  return VerifyAccess(self, obj, declaring_class, access_flags, klass);
+  return VerifyAccess(obj, declaring_class, access_flags, klass);
 }
 
-bool VerifyAccess(Thread* self, mirror::Object* obj, mirror::Class* declaring_class,
-                  uint32_t access_flags, mirror::Class* calling_class) {
+bool VerifyAccess(mirror::Object* obj,
+                  mirror::Class* declaring_class,
+                  uint32_t access_flags,
+                  mirror::Class* calling_class) {
   if (calling_class == declaring_class) {
     return true;
   }
-  ScopedAssertNoThreadSuspension sants(self, "verify-access");
+  ScopedAssertNoThreadSuspension sants("verify-access");
   if ((access_flags & kAccPrivate) != 0) {
     return false;
   }
diff --git a/runtime/reflection.h b/runtime/reflection.h
index 579c6b1..208b533 100644
--- a/runtime/reflection.h
+++ b/runtime/reflection.h
@@ -74,8 +74,10 @@
     REQUIRES_SHARED(Locks::mutator_lock_);
 
 // This version takes a known calling class.
-bool VerifyAccess(Thread* self, mirror::Object* obj, mirror::Class* declaring_class,
-                  uint32_t access_flags, mirror::Class* calling_class)
+bool VerifyAccess(mirror::Object* obj,
+                  mirror::Class* declaring_class,
+                  uint32_t access_flags,
+                  mirror::Class* calling_class)
     REQUIRES_SHARED(Locks::mutator_lock_);
 
 // Get the calling class by using a stack visitor, may return null for unattached native threads.
diff --git a/runtime/runtime.cc b/runtime/runtime.cc
index ba12d33..97911d4 100644
--- a/runtime/runtime.cc
+++ b/runtime/runtime.cc
@@ -71,8 +71,10 @@
 #include "fault_handler.h"
 #include "gc/accounting/card_table-inl.h"
 #include "gc/heap.h"
+#include "gc/scoped_gc_critical_section.h"
 #include "gc/space/image_space.h"
 #include "gc/space/space-inl.h"
+#include "gc/system_weak.h"
 #include "handle_scope-inl.h"
 #include "image-inl.h"
 #include "instrumentation.h"
@@ -111,6 +113,7 @@
 #include "native/java_lang_reflect_Constructor.h"
 #include "native/java_lang_reflect_Field.h"
 #include "native/java_lang_reflect_Method.h"
+#include "native/java_lang_reflect_Parameter.h"
 #include "native/java_lang_reflect_Proxy.h"
 #include "native/java_util_concurrent_atomic_AtomicLong.h"
 #include "native/libcore_util_CharsetUtils.h"
@@ -473,6 +476,11 @@
   GetMonitorList()->SweepMonitorList(visitor);
   GetJavaVM()->SweepJniWeakGlobals(visitor);
   GetHeap()->SweepAllocationRecords(visitor);
+
+  // All other generic system-weak holders.
+  for (gc::AbstractSystemWeakHolder* holder : system_weak_holders_) {
+    holder->Sweep(visitor);
+  }
 }
 
 bool Runtime::ParseOptions(const RuntimeOptions& raw_options,
@@ -829,6 +837,8 @@
 
     // We are falling back to non-executable use of the oat file because patching failed, presumably
     // due to lack of space.
+    std::string vdex_filename =
+        ImageHeader::GetVdexLocationFromImageLocation(system_filename.c_str());
     std::string oat_filename =
         ImageHeader::GetOatLocationFromImageLocation(system_filename.c_str());
     std::string oat_location =
@@ -838,22 +848,34 @@
     if (EndsWith(oat_location, ".jar")) {
       oat_location.replace(oat_location.length() - 3, 3, "oat");
     }
+    std::string error_msg;
+
+    std::unique_ptr<VdexFile> vdex_file(VdexFile::Open(vdex_filename,
+                                                       false /* writable */,
+                                                       false /* low_4gb */,
+                                                       &error_msg));
+    if (vdex_file.get() == nullptr) {
+      return false;
+    }
 
     std::unique_ptr<File> file(OS::OpenFileForReading(oat_filename.c_str()));
     if (file.get() == nullptr) {
       return false;
     }
-    std::string error_msg;
     std::unique_ptr<ElfFile> elf_file(ElfFile::Open(file.release(),
-                                                    false,
-                                                    false,
-                                                    /*low_4gb*/false,
+                                                    false /* writable */,
+                                                    false /* program_header_only */,
+                                                    false /* low_4gb */,
                                                     &error_msg));
     if (elf_file.get() == nullptr) {
       return false;
     }
     std::unique_ptr<const OatFile> oat_file(
-        OatFile::OpenWithElfFile(elf_file.release(), oat_location, nullptr, &error_msg));
+        OatFile::OpenWithElfFile(elf_file.release(),
+                                 vdex_file.release(),
+                                 oat_location,
+                                 nullptr,
+                                 &error_msg));
     if (oat_file == nullptr) {
       LOG(WARNING) << "Unable to use '" << oat_filename << "' because " << error_msg;
       return false;
@@ -1404,6 +1426,7 @@
   register_java_lang_reflect_Constructor(env);
   register_java_lang_reflect_Field(env);
   register_java_lang_reflect_Method(env);
+  register_java_lang_reflect_Parameter(env);
   register_java_lang_reflect_Proxy(env);
   register_java_lang_ref_Reference(env);
   register_java_lang_String(env);
@@ -1708,6 +1731,11 @@
   intern_table_->ChangeWeakRootState(gc::kWeakRootStateNoReadsOrWrites);
   java_vm_->DisallowNewWeakGlobals();
   heap_->DisallowNewAllocationRecords();
+
+  // All other generic system-weak holders.
+  for (gc::AbstractSystemWeakHolder* holder : system_weak_holders_) {
+    holder->Disallow();
+  }
 }
 
 void Runtime::AllowNewSystemWeaks() {
@@ -1716,6 +1744,11 @@
   intern_table_->ChangeWeakRootState(gc::kWeakRootStateNormal);  // TODO: Do this in the sweeping.
   java_vm_->AllowNewWeakGlobals();
   heap_->AllowNewAllocationRecords();
+
+  // All other generic system-weak holders.
+  for (gc::AbstractSystemWeakHolder* holder : system_weak_holders_) {
+    holder->Allow();
+  }
 }
 
 void Runtime::BroadcastForNewSystemWeaks() {
@@ -1726,6 +1759,11 @@
   intern_table_->BroadcastForNewInterns();
   java_vm_->BroadcastForNewWeakGlobals();
   heap_->BroadcastForNewAllocationRecords();
+
+  // All other generic system-weak holders.
+  for (gc::AbstractSystemWeakHolder* holder : system_weak_holders_) {
+    holder->Broadcast();
+  }
 }
 
 void Runtime::SetInstructionSet(InstructionSet instruction_set) {
@@ -2070,4 +2108,21 @@
   return c_env_vector_.get();
 }
 
+void Runtime::AddSystemWeakHolder(gc::AbstractSystemWeakHolder* holder) {
+  gc::ScopedGCCriticalSection gcs(Thread::Current(),
+                                  gc::kGcCauseAddRemoveSystemWeakHolder,
+                                  gc::kCollectorTypeAddRemoveSystemWeakHolder);
+  system_weak_holders_.push_back(holder);
+}
+
+void Runtime::RemoveSystemWeakHolder(gc::AbstractSystemWeakHolder* holder) {
+  gc::ScopedGCCriticalSection gcs(Thread::Current(),
+                                  gc::kGcCauseAddRemoveSystemWeakHolder,
+                                  gc::kCollectorTypeAddRemoveSystemWeakHolder);
+  auto it = std::find(system_weak_holders_.begin(), system_weak_holders_.end(), holder);
+  if (it != system_weak_holders_.end()) {
+    system_weak_holders_.erase(it);
+  }
+}
+
 }  // namespace art
diff --git a/runtime/runtime.h b/runtime/runtime.h
index dc14c04..58068eb 100644
--- a/runtime/runtime.h
+++ b/runtime/runtime.h
@@ -43,6 +43,7 @@
 namespace art {
 
 namespace gc {
+  class AbstractSystemWeakHolder;
   class Heap;
   namespace collector {
     class GarbageCollector;
@@ -651,6 +652,9 @@
     return env_snapshot_.GetSnapshot();
   }
 
+  void AddSystemWeakHolder(gc::AbstractSystemWeakHolder* holder);
+  void RemoveSystemWeakHolder(gc::AbstractSystemWeakHolder* holder);
+
  private:
   static void InitPlatformSignalHandlers();
 
@@ -887,6 +891,9 @@
     DISALLOW_COPY_AND_ASSIGN(EnvSnapshot);
   } env_snapshot_;
 
+  // Generic system-weak holders.
+  std::vector<gc::AbstractSystemWeakHolder*> system_weak_holders_;
+
   DISALLOW_COPY_AND_ASSIGN(Runtime);
 };
 std::ostream& operator<<(std::ostream& os, const Runtime::CalleeSaveType& rhs);
diff --git a/runtime/stack.cc b/runtime/stack.cc
index 4678ac6..3b5360c 100644
--- a/runtime/stack.cc
+++ b/runtime/stack.cc
@@ -325,6 +325,14 @@
     reg = (kind == kDoubleHiVReg) ? (2 * reg + 1) : (2 * reg);
   }
 
+  // MIPS32 float registers are used as 64-bit (for MIPS32r2 it is pair
+  // F(2n)-F(2n+1), and for MIPS32r6 it is 64-bit register F(2n)). When
+  // accessing upper 32-bits from double, reg + 1 should be used.
+  if ((kRuntimeISA == InstructionSet::kMips) && (kind == kDoubleHiVReg)) {
+    DCHECK_ALIGNED(reg, 2);
+    reg++;
+  }
+
   if (!IsAccessibleRegister(reg, is_float)) {
     return false;
   }
diff --git a/runtime/thread.cc b/runtime/thread.cc
index dde3640..8940354 100644
--- a/runtime/thread.cc
+++ b/runtime/thread.cc
@@ -40,6 +40,7 @@
 #include "class_linker-inl.h"
 #include "debugger.h"
 #include "dex_file-inl.h"
+#include "dex_file_annotations.h"
 #include "entrypoints/entrypoint_utils.h"
 #include "entrypoints/quick/quick_alloc_entrypoints.h"
 #include "gc/accounting/card_table-inl.h"
@@ -1388,8 +1389,8 @@
     mirror::DexCache* dex_cache = c->GetDexCache();
     int line_number = -1;
     if (dex_cache != nullptr) {  // be tolerant of bad input
-      const DexFile& dex_file = *dex_cache->GetDexFile();
-      line_number = dex_file.GetLineNumFromPC(m, GetDexPc(false));
+      const DexFile* dex_file = dex_cache->GetDexFile();
+      line_number = annotations::GetLineNumFromPC(dex_file, m, GetDexPc(false));
     }
     if (line_number == last_line_number && last_method == m) {
       ++repetition_count;
@@ -2548,7 +2549,6 @@
   QUICK_ENTRY_POINT_INFO(pDeliverException)
   QUICK_ENTRY_POINT_INFO(pThrowArrayBounds)
   QUICK_ENTRY_POINT_INFO(pThrowDivZero)
-  QUICK_ENTRY_POINT_INFO(pThrowNoSuchMethod)
   QUICK_ENTRY_POINT_INFO(pThrowNullPointer)
   QUICK_ENTRY_POINT_INFO(pThrowStackOverflow)
   QUICK_ENTRY_POINT_INFO(pDeoptimize)
@@ -2835,6 +2835,14 @@
       for (size_t i = 0; i < BitSizeOf<uint32_t>(); ++i) {
         if (register_mask & (1 << i)) {
           mirror::Object** ref_addr = reinterpret_cast<mirror::Object**>(GetGPRAddress(i));
+          if (kIsDebugBuild && ref_addr == nullptr) {
+            std::string thread_name;
+            GetThread()->GetThreadName(thread_name);
+            LOG(INTERNAL_FATAL) << "On thread " << thread_name;
+            DescribeStack(GetThread());
+            LOG(FATAL) << "Found an unsaved callee-save register " << i << " (null GPRAddress) "
+                       << "set in register_mask=" << register_mask << " at " << DescribeLocation();
+          }
           if (*ref_addr != nullptr) {
             visitor_(ref_addr, -1, this);
           }
diff --git a/runtime/thread.h b/runtime/thread.h
index d248123..016c2bc 100644
--- a/runtime/thread.h
+++ b/runtime/thread.h
@@ -1363,12 +1363,12 @@
       instrumentation_stack(nullptr), debug_invoke_req(nullptr), single_step_control(nullptr),
       stacked_shadow_frame_record(nullptr), deoptimization_context_stack(nullptr),
       frame_id_to_shadow_frame(nullptr), name(nullptr), pthread_self(0),
-      last_no_thread_suspension_cause(nullptr), thread_local_start(nullptr),
-      thread_local_objects(0), thread_local_pos(nullptr), thread_local_end(nullptr),
-      mterp_current_ibase(nullptr), mterp_default_ibase(nullptr), mterp_alt_ibase(nullptr),
-      thread_local_alloc_stack_top(nullptr), thread_local_alloc_stack_end(nullptr),
-      nested_signal_state(nullptr), flip_function(nullptr), method_verifier(nullptr),
-      thread_local_mark_stack(nullptr) {
+      last_no_thread_suspension_cause(nullptr), checkpoint_function(nullptr),
+      thread_local_start(nullptr), thread_local_pos(nullptr), thread_local_end(nullptr),
+      thread_local_objects(0), mterp_current_ibase(nullptr), mterp_default_ibase(nullptr),
+      mterp_alt_ibase(nullptr), thread_local_alloc_stack_top(nullptr),
+      thread_local_alloc_stack_end(nullptr), nested_signal_state(nullptr),
+      flip_function(nullptr), method_verifier(nullptr), thread_local_mark_stack(nullptr) {
       std::fill(held_mutexes, held_mutexes + kLockLevelCount, nullptr);
     }
 
@@ -1480,11 +1480,11 @@
 
     // Thread-local allocation pointer.
     uint8_t* thread_local_start;
-    size_t thread_local_objects;
     // thread_local_pos and thread_local_end must be consecutive for ldrd and are 8 byte aligned for
     // potentially better performance.
     uint8_t* thread_local_pos;
     uint8_t* thread_local_end;
+    size_t thread_local_objects;
 
     // Mterp jump table bases.
     void* mterp_current_ibase;
@@ -1546,19 +1546,25 @@
 
 class SCOPED_CAPABILITY ScopedAssertNoThreadSuspension {
  public:
-  ScopedAssertNoThreadSuspension(Thread* self, const char* cause) ACQUIRE(Roles::uninterruptible_)
-      : self_(self), old_cause_(self->StartAssertNoThreadSuspension(cause)) {
+  ALWAYS_INLINE ScopedAssertNoThreadSuspension(const char* cause) ACQUIRE(Roles::uninterruptible_) {
+    if (kIsDebugBuild) {
+      self_ = Thread::Current();
+      old_cause_ = self_->StartAssertNoThreadSuspension(cause);
+    } else {
+      Roles::uninterruptible_.Acquire();  // No-op.
+    }
   }
-  ~ScopedAssertNoThreadSuspension() RELEASE(Roles::uninterruptible_) {
-    self_->EndAssertNoThreadSuspension(old_cause_);
-  }
-  Thread* Self() {
-    return self_;
+  ALWAYS_INLINE ~ScopedAssertNoThreadSuspension() RELEASE(Roles::uninterruptible_) {
+    if (kIsDebugBuild) {
+      self_->EndAssertNoThreadSuspension(old_cause_);
+    } else {
+      Roles::uninterruptible_.Release();  // No-op.
+    }
   }
 
  private:
-  Thread* const self_;
-  const char* const old_cause_;
+  Thread* self_;
+  const char* old_cause_;
 };
 
 class ScopedStackedShadowFramePusher {
diff --git a/runtime/thread_list.h b/runtime/thread_list.h
index 5880085..cef4ed1 100644
--- a/runtime/thread_list.h
+++ b/runtime/thread_list.h
@@ -209,7 +209,7 @@
 // Helper for suspending all threads and
 class ScopedSuspendAll : public ValueObject {
  public:
-  ScopedSuspendAll(const char* cause, bool long_suspend = false)
+  explicit ScopedSuspendAll(const char* cause, bool long_suspend = false)
      EXCLUSIVE_LOCK_FUNCTION(Locks::mutator_lock_)
      REQUIRES(!Locks::thread_list_lock_,
               !Locks::thread_suspend_count_lock_,
diff --git a/runtime/utils.cc b/runtime/utils.cc
index 313190c..d48edcf 100644
--- a/runtime/utils.cc
+++ b/runtime/utils.cc
@@ -1213,6 +1213,15 @@
   return buffer.st_size > 0;
 }
 
+std::string ReplaceFileExtension(const std::string& filename, const std::string& new_extension) {
+  const size_t last_ext = filename.find_last_of('.');
+  if (last_ext == std::string::npos) {
+    return filename + "." + new_extension;
+  } else {
+    return filename.substr(0, last_ext + 1) + new_extension;
+  }
+}
+
 std::string PrettyDescriptor(Primitive::Type type) {
   return PrettyDescriptor(Primitive::Descriptor(type));
 }
diff --git a/runtime/utils.h b/runtime/utils.h
index 958f0a3..f3284e8 100644
--- a/runtime/utils.h
+++ b/runtime/utils.h
@@ -279,6 +279,13 @@
 bool FileExists(const std::string& filename);
 bool FileExistsAndNotEmpty(const std::string& filename);
 
+// Returns `filename` with the text after the last occurrence of '.' replaced with
+// `extension`. If `filename` does not contain a period, returns a string containing `filename`,
+// a period, and `new_extension`.
+// Example: ReplaceFileExtension("foo.bar", "abc") == "foo.abc"
+//          ReplaceFileExtension("foo", "abc") == "foo.abc"
+std::string ReplaceFileExtension(const std::string& filename, const std::string& new_extension);
+
 class VoidFunctor {
  public:
   template <typename A>
diff --git a/runtime/vdex_file.cc b/runtime/vdex_file.cc
new file mode 100644
index 0000000..a71578b
--- /dev/null
+++ b/runtime/vdex_file.cc
@@ -0,0 +1,88 @@
+/*
+ * 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 "vdex_file.h"
+
+#include <memory>
+
+#include "base/logging.h"
+#include "base/unix_file/fd_file.h"
+
+namespace art {
+
+constexpr uint8_t VdexFile::Header::kVdexMagic[4];
+constexpr uint8_t VdexFile::Header::kVdexVersion[4];
+
+bool VdexFile::Header::IsMagicValid() const {
+  return (memcmp(magic_, kVdexMagic, sizeof(kVdexMagic)) == 0);
+}
+
+bool VdexFile::Header::IsVersionValid() const {
+  return (memcmp(version_, kVdexVersion, sizeof(kVdexVersion)) == 0);
+}
+
+VdexFile::Header::Header() {
+  memcpy(magic_, kVdexMagic, sizeof(kVdexMagic));
+  memcpy(version_, kVdexVersion, sizeof(kVdexVersion));
+  DCHECK(IsMagicValid());
+  DCHECK(IsVersionValid());
+}
+
+VdexFile* VdexFile::Open(const std::string& vdex_filename,
+                         bool writable,
+                         bool low_4gb,
+                         std::string* error_msg) {
+  if (!OS::FileExists(vdex_filename.c_str())) {
+    *error_msg = "File " + vdex_filename + " does not exist.";
+    return nullptr;
+  }
+
+  std::unique_ptr<File> vdex_file;
+  if (writable) {
+    vdex_file.reset(OS::OpenFileReadWrite(vdex_filename.c_str()));
+  } else {
+    vdex_file.reset(OS::OpenFileForReading(vdex_filename.c_str()));
+  }
+  if (vdex_file == nullptr) {
+    *error_msg = "Could not open file " + vdex_filename +
+                 (writable ? " for read/write" : "for reading");
+    return nullptr;
+  }
+
+  int64_t vdex_length = vdex_file->GetLength();
+  if (vdex_length == -1) {
+    *error_msg = "Could not read the length of file " + vdex_filename;
+    return nullptr;
+  }
+
+  std::unique_ptr<MemMap> mmap(MemMap::MapFile(vdex_length,
+                                               writable ? PROT_READ | PROT_WRITE : PROT_READ,
+                                               MAP_SHARED,
+                                               vdex_file->Fd(),
+                                               0 /* start offset */,
+                                               low_4gb,
+                                               vdex_filename.c_str(),
+                                               error_msg));
+  if (mmap == nullptr) {
+    *error_msg = "Failed to mmap file " + vdex_filename + " : " + *error_msg;
+    return nullptr;
+  }
+
+  *error_msg = "Success";
+  return new VdexFile(mmap.release());
+}
+
+}  // namespace art
diff --git a/runtime/vdex_file.h b/runtime/vdex_file.h
new file mode 100644
index 0000000..9215e52
--- /dev/null
+++ b/runtime/vdex_file.h
@@ -0,0 +1,77 @@
+/*
+ * 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.
+ */
+
+#ifndef ART_RUNTIME_VDEX_FILE_H_
+#define ART_RUNTIME_VDEX_FILE_H_
+
+#include <stdint.h>
+#include <string>
+
+#include "base/macros.h"
+#include "mem_map.h"
+#include "os.h"
+
+namespace art {
+
+// VDEX files contain extracted DEX files. The VdexFile class maps the file to
+// memory and provides tools for accessing its individual sections.
+//
+// File format:
+//   VdexFile::Header    fixed-length header
+//
+//   DEX[0]              array of the input DEX files
+//   DEX[1]              the bytecode may have been quickened
+//   ...
+//   DEX[D]
+//
+
+class VdexFile {
+ public:
+  struct Header {
+   public:
+    Header();
+
+    bool IsMagicValid() const;
+    bool IsVersionValid() const;
+
+   private:
+    static constexpr uint8_t kVdexMagic[] = { 'v', 'd', 'e', 'x' };
+    static constexpr uint8_t kVdexVersion[] = { '0', '0', '0', '\0' };
+
+    uint8_t magic_[4];
+    uint8_t version_[4];
+  };
+
+  static VdexFile* Open(const std::string& vdex_filename,
+                        bool writable,
+                        bool low_4gb,
+                        std::string* error_msg);
+
+  const uint8_t* Begin() const { return mmap_->Begin(); }
+  const uint8_t* End() const { return mmap_->End(); }
+  size_t Size() const { return mmap_->Size(); }
+
+ private:
+  explicit VdexFile(MemMap* mmap) : mmap_(mmap) {}
+
+  std::unique_ptr<MemMap> mmap_;
+
+  DISALLOW_COPY_AND_ASSIGN(VdexFile);
+};
+
+}  // namespace art
+
+#endif  // ART_RUNTIME_VDEX_FILE_H_
diff --git a/runtime/verifier/method_verifier.cc b/runtime/verifier/method_verifier.cc
index 589e71c..6b1170b 100644
--- a/runtime/verifier/method_verifier.cc
+++ b/runtime/verifier/method_verifier.cc
@@ -123,7 +123,7 @@
                                                         mirror::Class* klass,
                                                         CompilerCallbacks* callbacks,
                                                         bool allow_soft_failures,
-                                                        LogSeverity log_level,
+                                                        HardFailLogMode log_level,
                                                         std::string* error) {
   if (klass->IsVerified()) {
     return kNoFailure;
@@ -196,7 +196,7 @@
                                                           Handle<mirror::ClassLoader> class_loader,
                                                           CompilerCallbacks* callbacks,
                                                           bool allow_soft_failures,
-                                                          LogSeverity log_level,
+                                                          HardFailLogMode log_level,
                                                           bool need_precise_constants,
                                                           std::string* error_string) {
   DCHECK(it != nullptr);
@@ -267,7 +267,7 @@
                                                         const DexFile::ClassDef& class_def,
                                                         CompilerCallbacks* callbacks,
                                                         bool allow_soft_failures,
-                                                        LogSeverity log_level,
+                                                        HardFailLogMode log_level,
                                                         std::string* error) {
   ScopedTrace trace(__FUNCTION__);
 
@@ -360,7 +360,7 @@
                                                          uint32_t method_access_flags,
                                                          CompilerCallbacks* callbacks,
                                                          bool allow_soft_failures,
-                                                         LogSeverity log_level,
+                                                         HardFailLogMode log_level,
                                                          bool need_precise_constants,
                                                          std::string* hard_failure_msg) {
   MethodVerifier::FailureData result;
@@ -420,11 +420,26 @@
     } else {
       CHECK(verifier.have_pending_hard_failure_);
       if (VLOG_IS_ON(verifier)) {
-        log_level = LogSeverity::VERBOSE;
+        log_level = std::max(HardFailLogMode::kLogVerbose, log_level);
       }
-      if (log_level > LogSeverity::VERBOSE) {
-        verifier.DumpFailures(LOG(log_level) << "Verification error in "
-                                             << PrettyMethod(method_idx, *dex_file) << "\n");
+      if (log_level >= HardFailLogMode::kLogVerbose) {
+        LogSeverity severity;
+        switch (log_level) {
+          case HardFailLogMode::kLogVerbose:
+            severity = LogSeverity::VERBOSE;
+            break;
+          case HardFailLogMode::kLogWarning:
+            severity = LogSeverity::WARNING;
+            break;
+          case HardFailLogMode::kLogInternalFatal:
+            severity = LogSeverity::INTERNAL_FATAL;
+            break;
+          default:
+            LOG(FATAL) << "Unsupported log-level " << static_cast<uint32_t>(log_level);
+            UNREACHABLE();
+        }
+        verifier.DumpFailures(LOG(severity) << "Verification error in "
+                                            << PrettyMethod(method_idx, *dex_file) << "\n");
       }
       if (hard_failure_msg != nullptr) {
         CHECK(!verifier.failure_messages_.empty());
diff --git a/runtime/verifier/method_verifier.h b/runtime/verifier/method_verifier.h
index d4e12f7..c4b1c6e 100644
--- a/runtime/verifier/method_verifier.h
+++ b/runtime/verifier/method_verifier.h
@@ -32,6 +32,7 @@
 #include "method_reference.h"
 #include "register_line.h"
 #include "reg_type_cache.h"
+#include "verifier_log_mode.h"
 
 namespace art {
 
@@ -152,7 +153,7 @@
                                  mirror::Class* klass,
                                  CompilerCallbacks* callbacks,
                                  bool allow_soft_failures,
-                                 LogSeverity log_level,
+                                 HardFailLogMode log_level,
                                  std::string* error)
       REQUIRES_SHARED(Locks::mutator_lock_);
   static FailureKind VerifyClass(Thread* self,
@@ -162,7 +163,7 @@
                                  const DexFile::ClassDef& class_def,
                                  CompilerCallbacks* callbacks,
                                  bool allow_soft_failures,
-                                 LogSeverity log_level,
+                                 HardFailLogMode log_level,
                                  std::string* error)
       REQUIRES_SHARED(Locks::mutator_lock_);
 
@@ -336,7 +337,7 @@
                                    Handle<mirror::ClassLoader> class_loader,
                                    CompilerCallbacks* callbacks,
                                    bool allow_soft_failures,
-                                   LogSeverity log_level,
+                                   HardFailLogMode log_level,
                                    bool need_precise_constants,
                                    std::string* error_string)
       REQUIRES_SHARED(Locks::mutator_lock_);
@@ -362,7 +363,7 @@
                                   uint32_t method_access_flags,
                                   CompilerCallbacks* callbacks,
                                   bool allow_soft_failures,
-                                  LogSeverity log_level,
+                                  HardFailLogMode log_level,
                                   bool need_precise_constants,
                                   std::string* hard_failure_msg)
       REQUIRES_SHARED(Locks::mutator_lock_);
diff --git a/runtime/verifier/method_verifier_test.cc b/runtime/verifier/method_verifier_test.cc
index 4fd581d..646987a 100644
--- a/runtime/verifier/method_verifier_test.cc
+++ b/runtime/verifier/method_verifier_test.cc
@@ -23,6 +23,7 @@
 #include "common_runtime_test.h"
 #include "dex_file.h"
 #include "scoped_thread_state_change.h"
+#include "verifier_log_mode.h"
 
 namespace art {
 namespace verifier {
@@ -37,12 +38,8 @@
 
     // Verify the class
     std::string error_msg;
-    MethodVerifier::FailureKind failure = MethodVerifier::VerifyClass(self,
-                                                                      klass,
-                                                                      nullptr,
-                                                                      true,
-                                                                      LogSeverity::WARNING,
-                                                                      &error_msg);
+    MethodVerifier::FailureKind failure = MethodVerifier::VerifyClass(
+        self, klass, nullptr, true, HardFailLogMode::kLogWarning, &error_msg);
     ASSERT_TRUE(failure == MethodVerifier::kNoFailure) << error_msg;
   }
 
diff --git a/runtime/verifier/verifier_log_mode.h b/runtime/verifier/verifier_log_mode.h
new file mode 100644
index 0000000..3744b9b
--- /dev/null
+++ b/runtime/verifier/verifier_log_mode.h
@@ -0,0 +1,33 @@
+/*
+ * 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.
+ */
+
+#ifndef ART_RUNTIME_VERIFIER_VERIFIER_LOG_MODE_H_
+#define ART_RUNTIME_VERIFIER_VERIFIER_LOG_MODE_H_
+
+namespace art {
+namespace verifier {
+
+enum class HardFailLogMode {
+  kLogNone,                               // Don't log hard failures at all.
+  kLogVerbose,                            // Log with severity VERBOSE.
+  kLogWarning,                            // Log with severity WARNING.
+  kLogInternalFatal,                      // Log with severity INTERNAL_FATAL
+};
+
+}  // namespace verifier
+}  // namespace art
+
+#endif  // ART_RUNTIME_VERIFIER_VERIFIER_LOG_MODE_H_
diff --git a/test/439-npe/expected.txt b/test/439-npe/expected.txt
index 34855ee..b4fd6bb 100644
--- a/test/439-npe/expected.txt
+++ b/test/439-npe/expected.txt
@@ -52,3 +52,73 @@
 $opt$noinline$getBooleanElement
 $opt$noinline$getCharElement
 $opt$noinline$getShortElement
+i0=4
+i1=8
+i2=12
+i3=16
+i4=20
+i5=24
+i6=28
+i7=32
+i8=36
+i9=40
+i10=44
+i11=48
+i12=52
+i13=56
+i14=44
+i15=57
+l0=84
+l1=88
+l2=92
+l3=96
+l4=100
+l5=104
+l6=108
+l7=112
+l8=116
+l9=120
+l10=124
+l11=128
+l12=132
+l13=136
+l14=104
+l15=146
+f0=164.0
+f1=168.0
+f2=172.0
+f3=176.0
+f4=180.0
+f5=184.0
+f6=188.0
+f7=192.0
+f8=196.0
+f9=200.0
+f10=204.0
+f11=208.0
+f12=212.0
+f13=216.0
+f14=164.0
+f15=55.5
+d0=244.0
+d1=248.0
+d2=252.0
+d3=256.0
+d4=260.0
+d5=264.0
+d6=268.0
+d7=272.0
+d8=276.0
+d9=280.0
+d10=284.0
+d11=288.0
+d12=292.0
+d13=296.0
+d14=224.0
+d15=75.125
+addInt=42
+addLong=111
+addFloat=0.5
+addDouble=0.125
+m=null
+i=2
diff --git a/test/439-npe/src/Main.java b/test/439-npe/src/Main.java
index 8f66da0..bc044a4 100644
--- a/test/439-npe/src/Main.java
+++ b/test/439-npe/src/Main.java
@@ -634,12 +634,246 @@
     } catch (NullPointerException npe) {
       check(npe, thisLine += 6, methodLine += 5, "$opt$noinline$getShortElement");
     }
+
+    $opt$noinline$testRegisterRetrieval();
   }
 
-  static void check(NullPointerException npe, int mainLine, int medthodLine, String methodName) {
+  static void $opt$noinline$testRegisterRetrieval() {
+    Main[] array = $noinline$PrepareArray();
+    int i0 = 0;
+    int i1 = 1;
+    int i2 = 2;
+    int i3 = 3;
+    int i4 = 4;
+    int i5 = 5;
+    int i6 = 6;
+    int i7 = 7;
+    int i8 = 8;
+    int i9 = 9;
+    int i10 = 10;
+    int i11 = 11;
+    int i12 = 12;
+    int i13 = 13;
+    int i14 = 14;
+    int i15 = 15;
+    long l0 = 20L;
+    long l1 = 21L;
+    long l2 = 22L;
+    long l3 = 23L;
+    long l4 = 24L;
+    long l5 = 25L;
+    long l6 = 26L;
+    long l7 = 27L;
+    long l8 = 28L;
+    long l9 = 29L;
+    long l10 = 30L;
+    long l11 = 31L;
+    long l12 = 32L;
+    long l13 = 33L;
+    long l14 = 34L;
+    long l15 = 35L;
+    float f0 = 40.0f;
+    float f1 = 41.0f;
+    float f2 = 42.0f;
+    float f3 = 43.0f;
+    float f4 = 44.0f;
+    float f5 = 45.0f;
+    float f6 = 46.0f;
+    float f7 = 47.0f;
+    float f8 = 48.0f;
+    float f9 = 49.0f;
+    float f10 = 50.0f;
+    float f11 = 51.0f;
+    float f12 = 52.0f;
+    float f13 = 53.0f;
+    float f14 = 54.0f;
+    float f15 = 55.0f;
+    double d0 = 60.0;
+    double d1 = 61.0;
+    double d2 = 62.0;
+    double d3 = 63.0;
+    double d4 = 64.0;
+    double d5 = 65.0;
+    double d6 = 66.0;
+    double d7 = 67.0;
+    double d8 = 68.0;
+    double d9 = 69.0;
+    double d10 = 70.0;
+    double d11 = 71.0;
+    double d12 = 72.0;
+    double d13 = 73.0;
+    double d14 = 74.0;
+    double d15 = 75.0;
+    int addInt = -1;
+    long addLong = -2L;
+    float addFloat = -3.0f;
+    double addDouble = -4.0;
+    Main m = null;
+    int i = 0;
+    try {
+      for (i = 0; i < array.length; ++i) {
+        m = array[i];
+        // We have 16 ints, 16 longs, 16 floats, 16 doubles and a few helper variables here,
+        // none of them anonymous. Hopefully, all available physical registers will be allocated
+        // to these variables, so that when `m.intField` throws NPE during the third iteration,
+        // we will fully test retrieval of values from all physical registers.
+        addInt = m.intField;
+        addLong = m.longField;
+        addFloat = m.floatField;
+        addDouble = m.doubleField;
+        i0 += i1;
+        i1 += i2;
+        i2 += i3;
+        i3 += i4;
+        i4 += i5;
+        i5 += i6;
+        i6 += i7;
+        i7 += i8;
+        i8 += i9;
+        i9 += i10;
+        i10 += i11;
+        i11 += i12;
+        i12 += i13;
+        i13 += i14;
+        i14 += i15;
+        i15 += addInt;
+        l0 += l1;
+        l1 += l2;
+        l2 += l3;
+        l3 += l4;
+        l4 += l5;
+        l5 += l6;
+        l6 += l7;
+        l7 += l8;
+        l8 += l9;
+        l9 += l10;
+        l10 += l11;
+        l11 += l12;
+        l12 += l13;
+        l13 += l14;
+        l14 += l15;
+        l15 += addLong;
+        f0 += f1;
+        f1 += f2;
+        f2 += f3;
+        f3 += f4;
+        f4 += f5;
+        f5 += f6;
+        f6 += f7;
+        f7 += f8;
+        f8 += f9;
+        f9 += f10;
+        f10 += f11;
+        f11 += f12;
+        f12 += f13;
+        f13 += f14;
+        f14 += f15;
+        f15 += addFloat;
+        d0 += d1;
+        d1 += d2;
+        d2 += d3;
+        d3 += d4;
+        d4 += d5;
+        d5 += d6;
+        d6 += d7;
+        d7 += d8;
+        d8 += d9;
+        d9 += d10;
+        d10 += d11;
+        d11 += d12;
+        d12 += d13;
+        d13 += d14;
+        d14 += d15;
+        d15 += addDouble;
+      }
+    } catch (NullPointerException npe) {
+      System.out.println("i0=" + i0);
+      System.out.println("i1=" + i1);
+      System.out.println("i2=" + i2);
+      System.out.println("i3=" + i3);
+      System.out.println("i4=" + i4);
+      System.out.println("i5=" + i5);
+      System.out.println("i6=" + i6);
+      System.out.println("i7=" + i7);
+      System.out.println("i8=" + i8);
+      System.out.println("i9=" + i9);
+      System.out.println("i10=" + i10);
+      System.out.println("i11=" + i11);
+      System.out.println("i12=" + i12);
+      System.out.println("i13=" + i13);
+      System.out.println("i14=" + i14);
+      System.out.println("i15=" + i15);
+      System.out.println("l0=" + l0);
+      System.out.println("l1=" + l1);
+      System.out.println("l2=" + l2);
+      System.out.println("l3=" + l3);
+      System.out.println("l4=" + l4);
+      System.out.println("l5=" + l5);
+      System.out.println("l6=" + l6);
+      System.out.println("l7=" + l7);
+      System.out.println("l8=" + l8);
+      System.out.println("l9=" + l9);
+      System.out.println("l10=" + l10);
+      System.out.println("l11=" + l11);
+      System.out.println("l12=" + l12);
+      System.out.println("l13=" + l13);
+      System.out.println("l14=" + l14);
+      System.out.println("l15=" + l15);
+      System.out.println("f0=" + f0);
+      System.out.println("f1=" + f1);
+      System.out.println("f2=" + f2);
+      System.out.println("f3=" + f3);
+      System.out.println("f4=" + f4);
+      System.out.println("f5=" + f5);
+      System.out.println("f6=" + f6);
+      System.out.println("f7=" + f7);
+      System.out.println("f8=" + f8);
+      System.out.println("f9=" + f9);
+      System.out.println("f10=" + f10);
+      System.out.println("f11=" + f11);
+      System.out.println("f12=" + f12);
+      System.out.println("f13=" + f13);
+      System.out.println("f14=" + f14);
+      System.out.println("f15=" + f15);
+      System.out.println("d0=" + d0);
+      System.out.println("d1=" + d1);
+      System.out.println("d2=" + d2);
+      System.out.println("d3=" + d3);
+      System.out.println("d4=" + d4);
+      System.out.println("d5=" + d5);
+      System.out.println("d6=" + d6);
+      System.out.println("d7=" + d7);
+      System.out.println("d8=" + d8);
+      System.out.println("d9=" + d9);
+      System.out.println("d10=" + d10);
+      System.out.println("d11=" + d11);
+      System.out.println("d12=" + d12);
+      System.out.println("d13=" + d13);
+      System.out.println("d14=" + d14);
+      System.out.println("d15=" + d15);
+      System.out.println("addInt=" + addInt);
+      System.out.println("addLong=" + addLong);
+      System.out.println("addFloat=" + addFloat);
+      System.out.println("addDouble=" + addDouble);
+      System.out.println("m=" + m);
+      System.out.println("i=" + i);
+    }
+  }
+
+  static Main[] $noinline$PrepareArray() {
+    if (doThrow) { throw new Error(); }
+    Main[] array = new Main[] { new Main(), new Main(), null, new Main() };
+    array[1].intField = 42;
+    array[1].longField = 111L;
+    array[1].floatField = 0.5f;
+    array[1].doubleField = 0.125;
+    return array;
+  }
+
+  static void check(NullPointerException npe, int mainLine, int methodLine, String methodName) {
     System.out.println(methodName);
     StackTraceElement[] trace = npe.getStackTrace();
-    checkElement(trace[0], "Main", methodName, "Main.java", medthodLine);
+    checkElement(trace[0], "Main", methodName, "Main.java", methodLine);
     checkElement(trace[1], "Main", "main", "Main.java", mainLine);
   }
 
diff --git a/test/529-checker-unresolved/src/Main.java b/test/529-checker-unresolved/src/Main.java
index 7b5cbc1..5fd51e1 100644
--- a/test/529-checker-unresolved/src/Main.java
+++ b/test/529-checker-unresolved/src/Main.java
@@ -122,6 +122,16 @@
     expectEquals(123456789123456789f, c.instanceFloat);
     expectEquals(123456789123456789d, c.instanceDouble);
     expectEquals(o, c.instanceObject);
+
+    // Check "large" values.
+
+    c.instanceByte = (byte)-1;
+    c.instanceChar = (char)32768;
+    c.instanceInt = -1;
+
+    expectEquals((byte)-1, c.instanceByte);
+    expectEquals((char)32768, c.instanceChar);
+    expectEquals(-1, c.instanceInt);
   }
 
   /// CHECK-START: void Main.callUnresolvedNull(UnresolvedClass) register (before)
diff --git a/test/960-default-smali/expected.txt b/test/960-default-smali/expected.txt
index f3db93f..8153d7d 100644
--- a/test/960-default-smali/expected.txt
+++ b/test/960-default-smali/expected.txt
@@ -98,3 +98,34 @@
 M-virtual           L.bar()='BAZ!'
 M-virtual           M.bar()='BAZ!'
 End testing for type M
+Testing for type N
+N-interface       Foo.bar()='foobar'
+N-virtual           N.bar()='foobar'
+End testing for type N
+Testing for type O
+O-interface       Foo.bar()='foobar foobar'
+O-interface      Foo2.bar()='foobar foobar'
+O-virtual           N.bar()='foobar foobar'
+O-virtual           O.bar()='foobar foobar'
+End testing for type O
+Testing for type P
+P-interface       Foo.bar()='not foobar!'
+P-interface      Foo2.bar()='not foobar!'
+P-virtual           N.bar()='not foobar!'
+P-virtual           O.bar()='not foobar!'
+P-virtual           P.bar()='not foobar!'
+End testing for type P
+Testing for type Q
+Q-interface on Foo: bar() threw exception!
+Exception is of type java.lang.IncompatibleClassChangeError
+Q-interface on Foo2: bar() threw exception!
+Exception is of type java.lang.IncompatibleClassChangeError
+Q-interface on Foo3: bar() threw exception!
+Exception is of type java.lang.IncompatibleClassChangeError
+Q-virtual on N: bar() threw exception!
+Exception is of type java.lang.IncompatibleClassChangeError
+Q-virtual on O: bar() threw exception!
+Exception is of type java.lang.IncompatibleClassChangeError
+Q-virtual on Q: bar() threw exception!
+Exception is of type java.lang.IncompatibleClassChangeError
+End testing for type Q
diff --git a/test/960-default-smali/src/Foo2.java b/test/960-default-smali/src/Foo2.java
new file mode 100644
index 0000000..2a1bbc0
--- /dev/null
+++ b/test/960-default-smali/src/Foo2.java
@@ -0,0 +1,25 @@
+/*
+ * 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.
+ */
+
+/**
+ * Regression test for b/31280371
+ */
+interface Foo2 extends Foo {
+  @Override
+  public default String bar() {
+    return "foobar foobar";
+  }
+}
diff --git a/test/960-default-smali/src/Foo3.java b/test/960-default-smali/src/Foo3.java
new file mode 100644
index 0000000..4c00425
--- /dev/null
+++ b/test/960-default-smali/src/Foo3.java
@@ -0,0 +1,22 @@
+/*
+ * 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.
+ */
+
+/**
+ * Regression test for b/31280371
+ */
+interface Foo3 extends Foo {
+  default void doNothing() {}
+}
diff --git a/test/960-default-smali/src/N.java b/test/960-default-smali/src/N.java
new file mode 100644
index 0000000..9d33320
--- /dev/null
+++ b/test/960-default-smali/src/N.java
@@ -0,0 +1,21 @@
+/*
+ * 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.
+ */
+
+/**
+ * Regression test for b/31280371
+ */
+class N implements Foo {
+}
diff --git a/test/960-default-smali/src/O.java b/test/960-default-smali/src/O.java
new file mode 100644
index 0000000..55126af
--- /dev/null
+++ b/test/960-default-smali/src/O.java
@@ -0,0 +1,21 @@
+/*
+ * 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.
+ */
+
+/**
+ * Regression test for b/31280371
+ */
+class O extends N implements Foo2 {
+}
diff --git a/test/960-default-smali/src/P.java b/test/960-default-smali/src/P.java
new file mode 100644
index 0000000..1ee6c26
--- /dev/null
+++ b/test/960-default-smali/src/P.java
@@ -0,0 +1,25 @@
+/*
+ * 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.
+ */
+
+/**
+ * Regression test for b/31280371
+ */
+class P extends O implements Foo2 {
+  @Override
+  public String bar() {
+    return "not foobar!";
+  }
+}
diff --git a/test/960-default-smali/src/Q.java b/test/960-default-smali/src/Q.java
new file mode 100644
index 0000000..bc1e164
--- /dev/null
+++ b/test/960-default-smali/src/Q.java
@@ -0,0 +1,21 @@
+/*
+ * 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.
+ */
+
+/**
+ * Regression test for b/31280371
+ */
+class Q extends O implements Foo2, Foo3 {
+}
diff --git a/test/960-default-smali/src/classes.xml b/test/960-default-smali/src/classes.xml
index f3e50c5..c66d35b 100644
--- a/test/960-default-smali/src/classes.xml
+++ b/test/960-default-smali/src/classes.xml
@@ -102,6 +102,37 @@
         <method>bar</method>
       </methods>
     </class>
+
+    <class name="N" super="java/lang/Object">
+      <implements>
+        <item>Foo</item>
+      </implements>
+      <methods> </methods>
+    </class>
+
+    <class name="O" super="N">
+      <implements>
+        <item>Foo2</item>
+      </implements>
+      <methods> </methods>
+    </class>
+
+    <class name="P" super="O">
+      <implements>
+        <item>Foo2</item>
+      </implements>
+      <methods>
+        <method>bar</method>
+      </methods>
+    </class>
+
+    <class name="Q" super="O">
+      <implements>
+        <item>Foo2</item>
+        <item>Foo3</item>
+      </implements>
+      <methods> </methods>
+    </class>
   </classes>
 
   <interfaces>
@@ -153,6 +184,24 @@
       </methods>
     </interface>
 
+    <interface name="Foo2" super="java/lang/Object">
+      <implements>
+        <item>Foo</item>
+      </implements>
+      <methods>
+        <method type="default">bar</method>
+      </methods>
+    </interface>
+
+    <interface name="Foo3" super="java/lang/Object">
+      <implements>
+        <item>Foo</item>
+      </implements>
+      <methods>
+        <method type="default">bar</method>
+      </methods>
+    </interface>
+
     <interface name="Fooer" super="java/lang/Object">
       <implements>
         <item>Foo</item>
diff --git a/test/960-default-smali/src2/Foo.java b/test/960-default-smali/src2/Foo.java
new file mode 100644
index 0000000..ed5b35f
--- /dev/null
+++ b/test/960-default-smali/src2/Foo.java
@@ -0,0 +1,20 @@
+/*
+ * 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.
+ */
+interface Foo {
+  public default String bar() {
+    return "foobar";
+  }
+}
diff --git a/test/960-default-smali/src2/Foo3.java b/test/960-default-smali/src2/Foo3.java
new file mode 100644
index 0000000..e96f98a
--- /dev/null
+++ b/test/960-default-smali/src2/Foo3.java
@@ -0,0 +1,25 @@
+/*
+ * 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.
+ */
+
+/**
+ * Regression test for b/31280371
+ */
+interface Foo3 extends Foo {
+  @Override
+  public default String bar() {
+    return "I'm in conflict";
+  }
+}
diff --git a/test/Android.bp b/test/Android.bp
new file mode 100644
index 0000000..54c85eb
--- /dev/null
+++ b/test/Android.bp
@@ -0,0 +1,188 @@
+//
+// 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.
+//
+
+art_cc_defaults {
+    name: "art_test_defaults",
+    host_supported: true,
+    test_per_src: true,
+    // These really are gtests, but the gtest library comes from libart-gtest.so
+    gtest: false,
+    defaults: [
+        "art_defaults",
+        "art_debug_defaults",
+    ],
+
+    shared_libs: [
+        "libartd",
+        "libartd-disassembler",
+        "libvixld-arm",
+        "libvixld-arm64",
+        "libart-gtest",
+
+        "libicuuc",
+        "libicui18n",
+        "libnativehelper",
+    ],
+    whole_static_libs: [
+        "libsigchain",
+    ],
+    include_dirs: [
+        "art",
+        "art/cmdline",
+    ],
+
+    target: {
+        linux: {
+            ldflags: [
+                // Allow jni_compiler_test to find Java_MyClassNatives_bar
+                // within itself using dlopen(NULL, ...).
+                // Mac OS linker doesn't understand --export-dynamic.
+                "-Wl,--export-dynamic",
+                "-Wl,-u,Java_MyClassNatives_bar",
+                "-Wl,-u,Java_MyClassNatives_sbar",
+            ],
+            shared_libs: [
+                "libziparchive",
+                "libz-host",
+            ],
+            host_ldlibs: [
+                "-ldl",
+                "-lpthread",
+            ],
+            cflags: [
+                // gtest issue
+                "-Wno-used-but-marked-unused",
+                "-Wno-deprecated",
+                "-Wno-missing-noreturn",
+            ],
+        },
+        darwin: {
+            enabled: false,
+        },
+        android: {
+            ldflags: [
+                // Allow jni_compiler_test to find Java_MyClassNatives_bar
+                // within itself using dlopen(NULL, ...).
+                "-Wl,--export-dynamic",
+                "-Wl,-u,Java_MyClassNatives_bar",
+                "-Wl,-u,Java_MyClassNatives_sbar",
+            ],
+            shared_libs: [
+                "libcutils",
+                "libdl",
+                "libz",
+            ],
+            cflags: [
+                // gtest issue
+                "-Wno-used-but-marked-unused",
+                "-Wno-deprecated",
+                "-Wno-missing-noreturn",
+            ],
+        },
+
+        android_arm: {
+            relative_install_path: "art/arm",
+        },
+        android_arm64: {
+            relative_install_path: "art/arm64",
+        },
+        android_mips: {
+            relative_install_path: "art/mips",
+        },
+        android_mips64: {
+            relative_install_path: "art/mips64",
+        },
+        android_x86: {
+            relative_install_path: "art/x86",
+        },
+        android_x86_64: {
+            relative_install_path: "art/x86_64",
+        },
+    },
+}
+
+art_cc_defaults {
+    name: "libart-gtest-defaults",
+    host_supported: true,
+    defaults: [
+        "art_defaults",
+        "art_debug_defaults",
+    ],
+    shared_libs: [
+        "libartd",
+        "libartd-compiler",
+    ],
+    static_libs: [
+        "libgtest",
+    ],
+    target: {
+        android32: {
+            cflags: ["-DART_TARGET_NATIVETEST_DIR=/data/nativetest/art"],
+        },
+        android64: {
+            cflags: ["-DART_TARGET_NATIVETEST_DIR=/data/nativetest64/art"],
+        },
+        android: {
+            cflags: [
+                // gtest issue
+                "-Wno-used-but-marked-unused",
+                "-Wno-deprecated",
+                "-Wno-missing-noreturn",
+            ],
+        },
+        linux: {
+            cflags: [
+                // gtest issue
+                "-Wno-used-but-marked-unused",
+                "-Wno-deprecated",
+                "-Wno-missing-noreturn",
+            ],
+        },
+        darwin: {
+            enabled: false,
+        },
+    },
+}
+
+art_cc_library {
+    name: "libart-gtest",
+    host_supported: true,
+    whole_static_libs: [
+        "libart-compiler-gtest",
+        "libart-runtime-gtest",
+        "libgtest",
+    ],
+    shared_libs: [
+        "libartd",
+        "libartd-compiler",
+    ],
+    target: {
+        android: {
+            shared_libs: [
+                "libdl",
+            ],
+        },
+        host: {
+            host_ldlibs: [
+                "-ldl",
+                "-lpthread",
+            ],
+        },
+        darwin: {
+            enabled: false,
+        },
+    },
+}
diff --git a/test/Android.run-test.mk b/test/Android.run-test.mk
index b554f59..e12fd28 100644
--- a/test/Android.run-test.mk
+++ b/test/Android.run-test.mk
@@ -153,17 +153,17 @@
 ifeq ($(ART_TEST_JNI_FORCECOPY),true)
   JNI_TYPES += forcecopy
 endif
-IMAGE_TYPES := image
+IMAGE_TYPES := picimage
 ifeq ($(ART_TEST_RUN_TEST_NO_IMAGE),true)
   IMAGE_TYPES += no-image
 endif
 ifeq ($(ART_TEST_RUN_TEST_MULTI_IMAGE),true)
-  IMAGE_TYPES := multiimage
+  IMAGE_TYPES := multipicimage
 endif
-ifeq ($(ART_TEST_PIC_IMAGE),true)
-  IMAGE_TYPES += picimage
+ifeq ($(ART_TEST_NPIC_IMAGE),true)
+  IMAGE_TYPES += npicimage
   ifeq ($(ART_TEST_RUN_TEST_MULTI_IMAGE),true)
-    IMAGE_TYPES := multipicimage
+    IMAGE_TYPES := multinpicimage
   endif
 endif
 PICTEST_TYPES := npictest
@@ -338,7 +338,9 @@
 TEST_ART_BROKEN_NO_RELOCATE_TESTS :=
 
 # Temporarily disable some broken tests when forcing access checks in interpreter b/22414682
+# 004-JniTest is disabled because @CriticalNative is unsupported by generic JNI b/31400248
 TEST_ART_BROKEN_INTERPRETER_ACCESS_CHECK_TESTS := \
+  004-JniTest \
   137-cfi
 
 ifneq (,$(filter interp-ac,$(COMPILER_TYPES)))
@@ -504,7 +506,6 @@
 
 # Known broken tests for the mips32 optimizing compiler backend.
 TEST_ART_BROKEN_OPTIMIZING_MIPS_RUN_TESTS := \
-    510-checker-try-catch \
 
 ifeq (mips,$(TARGET_ARCH))
   ifneq (,$(filter $(OPTIMIZING_COMPILER_TYPES),$(COMPILER_TYPES)))
@@ -895,6 +896,11 @@
   ifeq ($(4),regalloc_gc)
     # Graph coloring tests share the image_suffix with optimizing tests.
     image_suffix := optimizing
+  else
+    ifeq ($(4),jit)
+      # JIT tests share the image_suffix with interpreter tests.
+      image_suffix := interpreter
+    endif
   endif
   ifeq ($(9),no-image)
     test_groups += ART_RUN_TEST_$$(uc_host_or_target)_NO_IMAGE_RULES
@@ -906,8 +912,9 @@
       prereq_rule += $$(TARGET_CORE_IMAGE_$$(image_suffix)_no-pic_$(13))
     endif
   else
-    ifeq ($(9),image)
+    ifeq ($(9),npicimage)
       test_groups += ART_RUN_TEST_$$(uc_host_or_target)_IMAGE_RULES
+      run_test_options += --npic-image
       # Add the core dependency.
       ifeq ($(1),host)
         prereq_rule += $$(HOST_CORE_IMAGE_$$(image_suffix)_no-pic_$(13))
@@ -917,16 +924,15 @@
     else
       ifeq ($(9),picimage)
         test_groups += ART_RUN_TEST_$$(uc_host_or_target)_PICIMAGE_RULES
-        run_test_options += --pic-image
         ifeq ($(1),host)
           prereq_rule += $$(HOST_CORE_IMAGE_$$(image_suffix)_pic_$(13))
         else
           prereq_rule += $$(TARGET_CORE_IMAGE_$$(image_suffix)_pic_$(13))
         endif
       else
-        ifeq ($(9),multiimage)
+        ifeq ($(9),multinpicimage)
           test_groups += ART_RUN_TEST_$$(uc_host_or_target)_IMAGE_RULES
-          run_test_options += --multi-image
+          run_test_options += --npic-image --multi-image
                 ifeq ($(1),host)
                         prereq_rule += $$(HOST_CORE_IMAGE_$$(image_suffix)_no-pic_multi_$(13))
                 else
@@ -935,7 +941,7 @@
         else
           ifeq ($(9),multipicimage)
             test_groups += ART_RUN_TEST_$$(uc_host_or_target)_PICIMAGE_RULES
-                        run_test_options += --pic-image --multi-image
+                        run_test_options += --multi-image
                         ifeq ($(1),host)
                         prereq_rule += $$(HOST_CORE_IMAGE_$$(image_suffix)_pic_multi_$(13))
                         else
diff --git a/test/Packages/Package1.java b/test/Packages/Package1.java
new file mode 100644
index 0000000..6d58246
--- /dev/null
+++ b/test/Packages/Package1.java
@@ -0,0 +1,20 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package package1;
+class Package1 {
+    static int someField;
+}
diff --git a/test/Packages/Package2.java b/test/Packages/Package2.java
new file mode 100644
index 0000000..9ae370a
--- /dev/null
+++ b/test/Packages/Package2.java
@@ -0,0 +1,20 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package package2;
+class Package2 {
+    static int someField;
+}
diff --git a/test/run-test b/test/run-test
index 4c29420..8fb2adf 100755
--- a/test/run-test
+++ b/test/run-test
@@ -132,7 +132,7 @@
 android_root="/system"
 # By default we will use optimizing.
 image_args=""
-image_suffix="-optimizing"
+image_suffix=""
 
 while true; do
     if [ "x$1" = "x--host" ]; then
@@ -180,8 +180,8 @@
     elif [ "x$1" = "x--no-image" ]; then
         have_image="no"
         shift
-    elif [ "x$1" = "x--pic-image" ]; then
-        pic_image_suffix="-pic"
+    elif [ "x$1" = "x--npic-image" ]; then
+        pic_image_suffix="-npic"
         shift
     elif [ "x$1" = "x--multi-image" ]; then
         multi_image_suffix="-multi"
@@ -258,11 +258,10 @@
         shift
     elif [ "x$1" = "x--jit" ]; then
         image_args="--jit"
-        image_suffix="-jit"
+        image_suffix="-interpreter"
         shift
     elif [ "x$1" = "x--optimizing" ]; then
         image_args="-Xcompiler-option --compiler-backend=Optimizing"
-        image_suffix="-optimizing"
         shift
     elif [ "x$1" = "x--no-verify" ]; then
         run_args="${run_args} --no-verify"
@@ -608,8 +607,8 @@
         echo "    --dex2oat-swap        Use a dex2oat swap file."
         echo "    --instruction-set-features [string]"
         echo "                          Set instruction-set-features for compilation."
-        echo "    --pic-image           Use an image compiled with position independent code for the"
-        echo "                          boot class path."
+        echo "    --npic-image          Use an image compiled with non-position independent code "
+        echo "                          for the boot class path."
         echo "    --multi-image         Use a set of images compiled with dex2oat multi-image for"
         echo "                          the boot class path."
         echo "    --pic-test            Compile the test code position independent."
@@ -678,7 +677,7 @@
 # Tests named '<number>-checker-*' will also have their CFGs verified with
 # Checker when compiled with Optimizing on host.
 if [[ "$TEST_NAME" =~ ^[0-9]+-checker- ]]; then
-  if [ "$runtime" = "art" -a "$image_suffix" = "-optimizing" -a "$USE_JACK" = "true" ]; then
+  if [ "$runtime" = "art" -a "$image_suffix" = "" -a "$USE_JACK" = "true" ]; then
     # Optimizing has read barrier support for certain architectures
     # only. On other architectures, compiling is disabled when read
     # barriers are enabled, meaning that we do not produce a CFG file
diff --git a/test/utils/python/generate_java_main.py b/test/utils/python/generate_java_main.py
index f66d0dd..1c76b06 100755
--- a/test/utils/python/generate_java_main.py
+++ b/test/utils/python/generate_java_main.py
@@ -175,7 +175,11 @@
       return;
     }} catch (Error e) {{
       System.out.printf("%s-{invoke_type} on {farg}: {callfunc}() threw exception!\\n", s);
-      e.printStackTrace(System.out);
+      if (e instanceof IncompatibleClassChangeError) {{
+        System.out.printf("Exception is of type %s\\n", e.getClass().getName());
+      }} else {{
+        e.printStackTrace(System.out);
+      }}
     }}
   }}
 """
diff --git a/tools/art b/tools/art
index 1a3bba7..1394a46 100644
--- a/tools/art
+++ b/tools/art
@@ -100,7 +100,7 @@
   $invoke_with $ANDROID_ROOT/bin/$DALVIKVM $lib \
     -XXlib:$LIBART \
     -Xnorelocate \
-    -Ximage:$ANDROID_ROOT/framework/core-optimizing-pic.art \
+    -Ximage:$ANDROID_ROOT/framework/core.art \
     $DEBUG_OPTION \
     "$@"
 
diff --git a/tools/bisection_search/README.md b/tools/bisection_search/README.md
index a7485c2..64ccb20 100644
--- a/tools/bisection_search/README.md
+++ b/tools/bisection_search/README.md
@@ -15,29 +15,54 @@
 How to run Bisection Bug Search
 ===============================
 
+There are two supported invocation modes:
+
+1. Regular invocation, dalvikvm command is constructed internally:
+
+        ./bisection_search.py -cp classes.dex --expected-output out_int --class Test
+
+2. Raw-cmd invocation, dalvikvm command is accepted as an argument. The command
+   has to start with an executable.
+
+   Extra dalvikvm arguments will be placed on second position in the command
+   by default. {ARGS} tag can be used to specify a custom position.
+
+        ./bisection_search.py --raw-cmd='run.sh -cp classes.dex Test' --expected-retcode SUCCESS
+        ./bisection_search.py --raw-cmd='/bin/sh art {ARGS} -cp classes.dex Test' --expected-retcode SUCCESS
+
+Help:
+
     bisection_search.py [-h] [-cp CLASSPATH] [--class CLASSNAME] [--lib LIB]
-                               [--dalvikvm-option [OPT [OPT ...]]] [--arg [ARG [ARG ...]]]
-                               [--image IMAGE] [--raw-cmd RAW_CMD]
-                               [--64] [--device] [--expected-output EXPECTED_OUTPUT]
-                               [--check-script CHECK_SCRIPT] [--verbose]
+                             [--dalvikvm-option [OPT [OPT ...]]] [--arg [ARG [ARG ...]]]
+                             [--image IMAGE] [--raw-cmd RAW_CMD]
+                             [--64] [--device] [--device-serial DEVICE_SERIAL]
+                             [--expected-output EXPECTED_OUTPUT]
+                             [--expected-retcode {SUCCESS,TIMEOUT,ERROR}]
+                             [--check-script CHECK_SCRIPT] [--logfile LOGFILE] [--cleanup]
+                             [--timeout TIMEOUT] [--verbose]
 
     Tool for finding compiler bugs. Either --raw-cmd or both -cp and --class are required.
 
     optional arguments:
-      -h, --help                            show this help message and exit
+      -h, --help                                  show this help message and exit
 
     dalvikvm command options:
-      -cp CLASSPATH, --classpath CLASSPATH  classpath
-      --class CLASSNAME                     name of main class
-      --lib LIB                             lib to use, default: libart.so
-      --dalvikvm-option [OPT [OPT ...]]     additional dalvikvm option
-      --arg [ARG [ARG ...]]                 argument passed to test
-      --image IMAGE                         path to image
-      --raw-cmd RAW_CMD                     bisect with this command, ignore other command options
+      -cp CLASSPATH, --classpath CLASSPATH        classpath
+      --class CLASSNAME                           name of main class
+      --lib LIB                                   lib to use, default: libart.so
+      --dalvikvm-option [OPT [OPT ...]]           additional dalvikvm option
+      --arg [ARG [ARG ...]]                       argument passed to test
+      --image IMAGE                               path to image
+      --raw-cmd RAW_CMD                           bisect with this command, ignore other command options
 
     bisection options:
-      --64                                  x64 mode
-      --device                              run on device
-      --expected-output EXPECTED_OUTPUT     file containing expected output
-      --check-script CHECK_SCRIPT           script comparing output and expected output
-      --verbose                             enable verbose output
+      --64                                        x64 mode
+      --device                                    run on device
+      --device-serial DEVICE_SERIAL               device serial number, implies --device
+      --expected-output EXPECTED_OUTPUT           file containing expected output
+      --expected-retcode {SUCCESS,TIMEOUT,ERROR}  expected normalized return code
+      --check-script CHECK_SCRIPT                 script comparing output and expected output
+      --logfile LOGFILE                           custom logfile location
+      --cleanup                                   clean up after bisecting
+      --timeout TIMEOUT                           if timeout seconds pass assume test failed
+      --verbose                                   enable verbose output
diff --git a/tools/bisection_search/bisection_search.py b/tools/bisection_search/bisection_search.py
index 110ef82..0d36aa4 100755
--- a/tools/bisection_search/bisection_search.py
+++ b/tools/bisection_search/bisection_search.py
@@ -34,6 +34,7 @@
 from common import FatalError
 from common import GetEnvVariableOrError
 from common import HostTestEnv
+from common import RetCode
 
 
 # Passes that are never disabled during search process because disabling them
@@ -51,6 +52,10 @@
 NON_PASSES = ['builder', 'prepare_for_register_allocation',
               'liveness', 'register']
 
+# If present in raw cmd, this tag will be replaced with runtime arguments
+# controlling the bisection search. Otherwise arguments will be placed on second
+# position in the command.
+RAW_CMD_RUNTIME_ARGS_TAG = '{ARGS}'
 
 class Dex2OatWrapperTestable(object):
   """Class representing a testable compilation.
@@ -58,21 +63,29 @@
   Accepts filters on compiled methods and optimization passes.
   """
 
-  def __init__(self, base_cmd, test_env, output_checker=None, verbose=False):
+  def __init__(self, base_cmd, test_env, expected_retcode=None,
+               output_checker=None, verbose=False):
     """Constructor.
 
     Args:
       base_cmd: list of strings, base command to run.
       test_env: ITestEnv.
+      expected_retcode: RetCode, expected normalized return code.
       output_checker: IOutputCheck, output checker.
       verbose: bool, enable verbose output.
     """
     self._base_cmd = base_cmd
     self._test_env = test_env
+    self._expected_retcode = expected_retcode
     self._output_checker = output_checker
     self._compiled_methods_path = self._test_env.CreateFile('compiled_methods')
     self._passes_to_run_path = self._test_env.CreateFile('run_passes')
     self._verbose = verbose
+    if RAW_CMD_RUNTIME_ARGS_TAG in self._base_cmd:
+      self._arguments_position = self._base_cmd.index(RAW_CMD_RUNTIME_ARGS_TAG)
+      self._base_cmd.pop(self._arguments_position)
+    else:
+      self._arguments_position = 1
 
   def Test(self, compiled_methods, passes_to_run=None):
     """Tests compilation with compiled_methods and run_passes switches active.
@@ -95,8 +108,11 @@
                            verbose_compiler=False)
     (output, ret_code) = self._test_env.RunCommand(
         cmd, {'ANDROID_LOG_TAGS': '*:e'})
-    res = ((self._output_checker is None and ret_code == 0)
-           or self._output_checker.Check(output))
+    res = True
+    if self._expected_retcode:
+      res = self._expected_retcode == ret_code
+    if self._output_checker:
+      res = res and self._output_checker.Check(output)
     if self._verbose:
       print('Test passed: {0}.'.format(res))
     return res
@@ -142,8 +158,8 @@
   def _PrepareCmd(self, compiled_methods=None, passes_to_run=None,
                   verbose_compiler=False):
     """Prepare command to run."""
-    cmd = [self._base_cmd[0]]
-    # insert additional arguments
+    cmd = self._base_cmd[0:self._arguments_position]
+    # insert additional arguments before the first argument
     if compiled_methods is not None:
       self._test_env.WriteLines(self._compiled_methods_path, compiled_methods)
       cmd += ['-Xcompiler-option', '--compiled-methods={0}'.format(
@@ -155,7 +171,7 @@
     if verbose_compiler:
       cmd += ['-Xcompiler-option', '--runtime-arg', '-Xcompiler-option',
               '-verbose:compiler', '-Xcompiler-option', '-j1']
-    cmd += self._base_cmd[1:]
+    cmd += self._base_cmd[self._arguments_position:]
     return cmd
 
 
@@ -299,7 +315,7 @@
   command_opts.add_argument('-cp', '--classpath', type=str, help='classpath')
   command_opts.add_argument('--class', dest='classname', type=str,
                             help='name of main class')
-  command_opts.add_argument('--lib', dest='lib', type=str, default='libart.so',
+  command_opts.add_argument('--lib', type=str, default='libart.so',
                             help='lib to use, default: libart.so')
   command_opts.add_argument('--dalvikvm-option', dest='dalvikvm_opts',
                             metavar='OPT', nargs='*', default=[],
@@ -307,7 +323,7 @@
   command_opts.add_argument('--arg', dest='test_args', nargs='*', default=[],
                             metavar='ARG', help='argument passed to test')
   command_opts.add_argument('--image', type=str, help='path to image')
-  command_opts.add_argument('--raw-cmd', dest='raw_cmd', type=str,
+  command_opts.add_argument('--raw-cmd', type=str,
                             help='bisect with this command, ignore other '
                                  'command options')
   bisection_opts = parser.add_argument_group('bisection options')
@@ -315,11 +331,22 @@
                               default=False, help='x64 mode')
   bisection_opts.add_argument(
       '--device', action='store_true', default=False, help='run on device')
+  bisection_opts.add_argument(
+      '--device-serial', help='device serial number, implies --device')
   bisection_opts.add_argument('--expected-output', type=str,
                               help='file containing expected output')
   bisection_opts.add_argument(
-      '--check-script', dest='check_script', type=str,
+      '--expected-retcode', type=str, help='expected normalized return code',
+      choices=[RetCode.SUCCESS.name, RetCode.TIMEOUT.name, RetCode.ERROR.name])
+  bisection_opts.add_argument(
+      '--check-script', type=str,
       help='script comparing output and expected output')
+  bisection_opts.add_argument(
+      '--logfile', type=str, help='custom logfile location')
+  bisection_opts.add_argument('--cleanup', action='store_true',
+                              default=False, help='clean up after bisecting')
+  bisection_opts.add_argument('--timeout', type=int, default=60,
+                              help='if timeout seconds pass assume test failed')
   bisection_opts.add_argument('--verbose', action='store_true',
                               default=False, help='enable verbose output')
   return parser
@@ -351,15 +378,24 @@
   args = parser.parse_args()
   if not args.raw_cmd and (not args.classpath or not args.classname):
     parser.error('Either --raw-cmd or both -cp and --class are required')
+  if args.device_serial:
+    args.device = True
+  if args.expected_retcode:
+    args.expected_retcode = RetCode[args.expected_retcode]
+  if not args.expected_retcode and not args.check_script:
+    args.expected_retcode = RetCode.SUCCESS
 
   # Prepare environment
   classpath = args.classpath
   if args.device:
-    test_env = DeviceTestEnv()
+    test_env = DeviceTestEnv(
+        'bisection_search_', args.cleanup, args.logfile, args.timeout,
+        args.device_serial)
     if classpath:
       classpath = test_env.PushClasspath(classpath)
   else:
-    test_env = HostTestEnv(args.x64)
+    test_env = HostTestEnv(
+        'bisection_search_', args.cleanup, args.logfile, args.timeout, args.x64)
   base_cmd = PrepareBaseCommand(args, classpath)
   output_checker = None
   if args.expected_output:
@@ -372,11 +408,11 @@
 
   # Perform the search
   try:
-    testable = Dex2OatWrapperTestable(base_cmd, test_env, output_checker,
-                                      args.verbose)
+    testable = Dex2OatWrapperTestable(base_cmd, test_env, args.expected_retcode,
+                                      output_checker, args.verbose)
     (method, opt_pass) = BugSearch(testable)
   except Exception as e:
-    print('Error. Refer to logfile: {0}'.format(test_env.logfile.name))
+    print('Error occurred.\nLogfile: {0}'.format(test_env.logfile.name))
     test_env.logfile.write('Exception: {0}\n'.format(e))
     raise
 
diff --git a/tools/bisection_search/common.py b/tools/bisection_search/common.py
index d5029bb..b69b606 100755
--- a/tools/bisection_search/common.py
+++ b/tools/bisection_search/common.py
@@ -18,7 +18,9 @@
 
 import abc
 import os
+import signal
 import shlex
+import shutil
 
 from subprocess import check_call
 from subprocess import PIPE
@@ -29,6 +31,9 @@
 from tempfile import mkdtemp
 from tempfile import NamedTemporaryFile
 
+from enum import Enum
+from enum import unique
+
 # Temporary directory path on device.
 DEVICE_TMP_PATH = '/data/local/tmp'
 
@@ -36,6 +41,16 @@
 DALVIK_CACHE_ARCHS = ['arm', 'arm64', 'x86', 'x86_64']
 
 
+@unique
+class RetCode(Enum):
+  """Enum representing normalized return codes."""
+  SUCCESS = 0
+  TIMEOUT = 1
+  ERROR = 2
+  NOTCOMPILED = 3
+  NOTRUN = 4
+
+
 def GetEnvVariableOrError(variable_name):
   """Gets value of an environmental variable.
 
@@ -70,6 +85,37 @@
           for arch in DALVIK_CACHE_ARCHS)
 
 
+def RunCommandForOutput(cmd, env, stdout, stderr, timeout=60):
+  """Runs command piping output to files, stderr or stdout.
+
+  Args:
+    cmd: list of strings, command to run.
+    env: shell environment to run the command with.
+    stdout: file handle or one of Subprocess.PIPE, Subprocess.STDOUT,
+      Subprocess.DEVNULL, see Popen.
+    stderr: file handle or one of Subprocess.PIPE, Subprocess.STDOUT,
+      Subprocess.DEVNULL, see Popen.
+    timeout: int, timeout in seconds.
+
+  Returns:
+    tuple (string, string, RetCode) stdout output, stderr output, normalized
+      return code.
+  """
+  proc = Popen(cmd, stdout=stdout, stderr=stderr, env=env,
+               universal_newlines=True, start_new_session=True)
+  try:
+    (output, stderr_output) = proc.communicate(timeout=timeout)
+    if proc.returncode == 0:
+      retcode = RetCode.SUCCESS
+    else:
+      retcode = RetCode.ERROR
+  except TimeoutExpired:
+    os.killpg(os.getpgid(proc.pid), signal.SIGTERM)
+    (output, stderr_output) = proc.communicate()
+    retcode = RetCode.TIMEOUT
+  return (output, stderr_output, retcode)
+
+
 def _RunCommandForOutputAndLog(cmd, env, logfile, timeout=60):
   """Runs command and logs its output. Returns the output.
 
@@ -77,28 +123,19 @@
     cmd: list of strings, command to run.
     env: shell environment to run the command with.
     logfile: file handle to logfile.
-    timeout: int, timeout in seconds
+    timeout: int, timeout in seconds.
 
   Returns:
-   tuple (string, string, int) stdout output, stderr output, return code.
+    tuple (string, string, RetCode) stdout output, stderr output, normalized
+      return code.
   """
-  proc = Popen(cmd, stderr=STDOUT, stdout=PIPE, env=env,
-               universal_newlines=True)
-  timeouted = False
-  try:
-    (output, _) = proc.communicate(timeout=timeout)
-  except TimeoutExpired:
-    timeouted = True
-    proc.kill()
-    (output, _) = proc.communicate()
+  (output, _, retcode) = RunCommandForOutput(cmd, env, PIPE, STDOUT, timeout)
   logfile.write('Command:\n{0}\n{1}\nReturn code: {2}\n'.format(
-      _CommandListToCommandString(cmd), output,
-      'TIMEOUT' if timeouted else proc.returncode))
-  ret_code = 1 if timeouted else proc.returncode
-  return (output, ret_code)
+      CommandListToCommandString(cmd), output, retcode))
+  return (output, retcode)
 
 
-def _CommandListToCommandString(cmd):
+def CommandListToCommandString(cmd):
   """Converts shell command represented as list of strings to a single string.
 
   Each element of the list is wrapped in double quotes.
@@ -109,7 +146,7 @@
   Returns:
     string, shell command.
   """
-  return ' '.join(['"{0}"'.format(segment) for segment in cmd])
+  return ' '.join([shlex.quote(segment) for segment in cmd])
 
 
 class FatalError(Exception):
@@ -175,14 +212,24 @@
   For methods documentation see base class.
   """
 
-  def __init__(self, x64):
+  def __init__(self, directory_prefix, cleanup=True, logfile_path=None,
+               timeout=60, x64=False):
     """Constructor.
 
     Args:
+      directory_prefix: string, prefix for environment directory name.
+      cleanup: boolean, if True remove test directory in destructor.
+      logfile_path: string, can be used to specify custom logfile location.
+      timeout: int, seconds, time to wait for single test run to finish.
       x64: boolean, whether to setup in x64 mode.
     """
-    self._env_path = mkdtemp(dir='/tmp/', prefix='bisection_search_')
-    self._logfile = open('{0}/log'.format(self._env_path), 'w+')
+    self._cleanup = cleanup
+    self._timeout = timeout
+    self._env_path = mkdtemp(dir='/tmp/', prefix=directory_prefix)
+    if logfile_path is None:
+      self._logfile = open('{0}/log'.format(self._env_path), 'w+')
+    else:
+      self._logfile = open(logfile_path, 'w+')
     os.mkdir('{0}/dalvik-cache'.format(self._env_path))
     for arch_cache_path in _DexArchCachePaths(self._env_path):
       os.mkdir(arch_cache_path)
@@ -199,6 +246,10 @@
     # Using dlopen requires load bias on the host.
     self._shell_env['LD_USE_LOAD_BIAS'] = '1'
 
+  def __del__(self):
+    if self._cleanup:
+      shutil.rmtree(self._env_path)
+
   def CreateFile(self, name=None):
     if name is None:
       f = NamedTemporaryFile(dir=self._env_path, delete=False)
@@ -217,7 +268,7 @@
     self._EmptyDexCache()
     env = self._shell_env.copy()
     env.update(env_updates)
-    return _RunCommandForOutputAndLog(cmd, env, self._logfile)
+    return _RunCommandForOutputAndLog(cmd, env, self._logfile, self._timeout)
 
   @property
   def logfile(self):
@@ -239,16 +290,28 @@
 class DeviceTestEnv(ITestEnv):
   """Device test environment. Concrete implementation of ITestEnv.
 
-  Makes use of HostTestEnv to maintain a test directory on host. Creates an
-  on device test directory which is kept in sync with the host one.
-
   For methods documentation see base class.
   """
 
-  def __init__(self):
-    """Constructor."""
-    self._host_env_path = mkdtemp(dir='/tmp/', prefix='bisection_search_')
-    self._logfile = open('{0}/log'.format(self._host_env_path), 'w+')
+  def __init__(self, directory_prefix, cleanup=True, logfile_path=None,
+               timeout=60, specific_device=None):
+    """Constructor.
+
+    Args:
+      directory_prefix: string, prefix for environment directory name.
+      cleanup: boolean, if True remove test directory in destructor.
+      logfile_path: string, can be used to specify custom logfile location.
+      timeout: int, seconds, time to wait for single test run to finish.
+      specific_device: string, serial number of device to use.
+    """
+    self._cleanup = cleanup
+    self._timeout = timeout
+    self._specific_device = specific_device
+    self._host_env_path = mkdtemp(dir='/tmp/', prefix=directory_prefix)
+    if logfile_path is None:
+      self._logfile = open('{0}/log'.format(self._host_env_path), 'w+')
+    else:
+      self._logfile = open(logfile_path, 'w+')
     self._device_env_path = '{0}/{1}'.format(
         DEVICE_TMP_PATH, os.path.basename(self._host_env_path))
     self._shell_env = os.environ.copy()
@@ -257,6 +320,13 @@
     for arch_cache_path in _DexArchCachePaths(self._device_env_path):
       self._AdbMkdir(arch_cache_path)
 
+  def __del__(self):
+    if self._cleanup:
+      shutil.rmtree(self._host_env_path)
+      check_call(shlex.split(
+          'adb shell if [ -d "{0}" ]; then rm -rf "{0}"; fi'
+          .format(self._device_env_path)))
+
   def CreateFile(self, name=None):
     with NamedTemporaryFile(mode='w') as temp_file:
       self._AdbPush(temp_file.name, self._device_env_path)
@@ -279,11 +349,18 @@
       env_updates['ANDROID_DATA'] = self._device_env_path
     env_updates_cmd = ' '.join(['{0}={1}'.format(var, val) for var, val
                                 in env_updates.items()])
-    cmd = _CommandListToCommandString(cmd)
-    cmd = ('adb shell "logcat -c && {0} {1} ; logcat -d -s dex2oat:* dex2oatd:*'
-           '| grep -v "^---------" 1>&2"').format(env_updates_cmd, cmd)
-    return _RunCommandForOutputAndLog(
-        shlex.split(cmd), self._shell_env, self._logfile)
+    cmd = CommandListToCommandString(cmd)
+    adb = 'adb'
+    if self._specific_device:
+      adb += ' -s ' + self._specific_device
+    cmd = '{0} shell "logcat -c && {1} {2}"'.format(
+        adb, env_updates_cmd, cmd)
+    (output, retcode) = _RunCommandForOutputAndLog(
+        shlex.split(cmd), self._shell_env, self._logfile, self._timeout)
+    logcat_cmd = 'adb shell "logcat -d -s -b main dex2oat:* dex2oatd:*"'
+    (err_output, _) = _RunCommandForOutputAndLog(
+        shlex.split(logcat_cmd), self._shell_env, self._logfile)
+    return (output + err_output, retcode)
 
   @property
   def logfile(self):
diff --git a/tools/buildbot-build.sh b/tools/buildbot-build.sh
index 12e0338..5ef66d1 100755
--- a/tools/buildbot-build.sh
+++ b/tools/buildbot-build.sh
@@ -45,6 +45,16 @@
   fi
 done
 
+# Workaround for repo incompatibilities on the Chromium buildbot.
+# TODO: Remove this workaround once https://bugs.chromium.org/p/chromium/issues/detail?id=646329
+# is addressed.
+repo=$(which repo)
+if [[ $repo == *"depot_tools"* ]]; then
+  ln -s build/soong/root.bp Android.bp
+  ln -s build/soong/bootstrap.bash bootstrap.bash
+  echo "include build/core/main.mk" > Makefile
+fi
+
 if [[ $mode == "host" ]]; then
   make_command="make $j_arg $showcommands build-art-host-tests $common_targets"
   make_command+=" ${out_dir}/host/linux-x86/lib/libjavacoretests.so "
diff --git a/tools/javafuzz/README.md b/tools/javafuzz/README.md
index 68fc171..b08075a 100644
--- a/tools/javafuzz/README.md
+++ b/tools/javafuzz/README.md
@@ -39,9 +39,10 @@
 How to start the JavaFuzz tests
 ===============================
 
-    run_java_fuzz_test.py [--num_tests]
-                          [--device]
-                          [--mode1=mode] [--mode2=mode]
+    run_java_fuzz_test.py
+                          [--num_tests=#TESTS]
+                          [--device=DEVICE]
+                          [--mode1=MODE] [--mode2=MODE]
 
 where
 
diff --git a/tools/javafuzz/run_java_fuzz_test.py b/tools/javafuzz/run_java_fuzz_test.py
index 5f527b8..51d00be 100755
--- a/tools/javafuzz/run_java_fuzz_test.py
+++ b/tools/javafuzz/run_java_fuzz_test.py
@@ -1,4 +1,4 @@
-#!/usr/bin/env python2
+#!/usr/bin/env python3.4
 #
 # Copyright (C) 2016 The Android Open Source Project
 #
@@ -16,68 +16,71 @@
 
 import abc
 import argparse
+import filecmp
+
+from glob import glob
+
+import os
+import shlex
+import shutil
 import subprocess
 import sys
-import os
 
 from tempfile import mkdtemp
-from threading import Timer
 
-# Normalized return codes.
-EXIT_SUCCESS = 0
-EXIT_TIMEOUT = 1
-EXIT_NOTCOMPILED = 2
-EXIT_NOTRUN = 3
+sys.path.append(os.path.dirname(os.path.dirname(
+    os.path.realpath(__file__))))
+
+from bisection_search.common import RetCode
+from bisection_search.common import CommandListToCommandString
+from bisection_search.common import FatalError
+from bisection_search.common import GetEnvVariableOrError
+from bisection_search.common import RunCommandForOutput
+from bisection_search.common import DeviceTestEnv
+
+# Return codes supported by bisection bug search.
+BISECTABLE_RET_CODES = (RetCode.SUCCESS, RetCode.ERROR, RetCode.TIMEOUT)
 
 #
 # Utility methods.
 #
 
-def RunCommand(cmd, args, out, err, timeout = 5):
+
+def RunCommand(cmd, out, err, timeout=5):
   """Executes a command, and returns its return code.
 
   Args:
-    cmd: string, a command to execute
-    args: string, arguments to pass to command (or None)
+    cmd: list of strings, a command to execute
     out: string, file name to open for stdout (or None)
     err: string, file name to open for stderr (or None)
     timeout: int, time out in seconds
   Returns:
-    return code of running command (forced EXIT_TIMEOUT on timeout)
+    RetCode, return code of running command (forced RetCode.TIMEOUT
+    on timeout)
   """
-  cmd = 'exec ' + cmd  # preserve pid
-  if args != None:
-    cmd = cmd + ' ' + args
-  outf = None
-  if out != None:
+  devnull = subprocess.DEVNULL
+  outf = devnull
+  if out is not None:
     outf = open(out, mode='w')
-  errf = None
-  if err != None:
+  errf = devnull
+  if err is not None:
     errf = open(err, mode='w')
-  proc = subprocess.Popen(cmd, stdout=outf, stderr=errf, shell=True)
-  timer = Timer(timeout, proc.kill)  # enforces timeout
-  timer.start()
-  proc.communicate()
-  if timer.is_alive():
-    timer.cancel()
-    returncode = proc.returncode
-  else:
-    returncode = EXIT_TIMEOUT
-  if outf != None:
+  (_, _, retcode) = RunCommandForOutput(cmd, None, outf, errf, timeout)
+  if outf != devnull:
     outf.close()
-  if errf != None:
+  if errf != devnull:
     errf.close()
-  return returncode
+  return retcode
+
 
 def GetJackClassPath():
   """Returns Jack's classpath."""
-  top = os.environ.get('ANDROID_BUILD_TOP')
-  if top == None:
-    raise FatalError('Cannot find AOSP build top')
+  top = GetEnvVariableOrError('ANDROID_BUILD_TOP')
   libdir = top + '/out/host/common/obj/JAVA_LIBRARIES'
   return libdir + '/core-libart-hostdex_intermediates/classes.jack:' \
        + libdir + '/core-oj-hostdex_intermediates/classes.jack'
 
+
 def GetExecutionModeRunner(device, mode):
   """Returns a runner for the given execution mode.
 
@@ -92,49 +95,44 @@
   if mode == 'ri':
     return TestRunnerRIOnHost()
   if mode == 'hint':
-    return TestRunnerArtOnHost(True)
+    return TestRunnerArtIntOnHost()
   if mode == 'hopt':
-    return TestRunnerArtOnHost(False)
+    return TestRunnerArtOptOnHost()
   if mode == 'tint':
-    return TestRunnerArtOnTarget(device, True)
+    return TestRunnerArtIntOnTarget(device)
   if mode == 'topt':
-    return TestRunnerArtOnTarget(device, False)
+    return TestRunnerArtOptOnTarget(device)
   raise FatalError('Unknown execution mode')
 
-def GetReturnCode(retc):
-  """Returns a string representation of the given normalized return code.
-  Args:
-    retc: int, normalized return code
-  Returns:
-    string representation of normalized return code
-  Raises:
-    FatalError: error for unknown normalized return code
-  """
-  if retc == EXIT_SUCCESS:
-    return 'SUCCESS'
-  if retc == EXIT_TIMEOUT:
-    return 'TIMED-OUT'
-  if retc == EXIT_NOTCOMPILED:
-    return 'NOT-COMPILED'
-  if retc == EXIT_NOTRUN:
-    return 'NOT-RUN'
-  raise FatalError('Unknown normalized return code')
-
 #
 # Execution mode classes.
 #
 
+
 class TestRunner(object):
   """Abstraction for running a test in a particular execution mode."""
   __meta_class__ = abc.ABCMeta
 
-  def GetDescription(self):
+  @abc.abstractproperty
+  def description(self):
     """Returns a description string of the execution mode."""
-    return self._description
 
-  def GetId(self):
+  @abc.abstractproperty
+  def id(self):
     """Returns a short string that uniquely identifies the execution mode."""
-    return self._id
+
+  @property
+  def output_file(self):
+    return self.id + '_out.txt'
+
+  @abc.abstractmethod
+  def GetBisectionSearchArgs(self):
+    """Get arguments to pass to bisection search tool.
+
+    Returns:
+      list of strings - arguments for bisection search tool, or None if
+      runner is not bisectable
+    """
 
   @abc.abstractmethod
   def CompileAndRunTest(self):
@@ -142,8 +140,7 @@
 
     Ensures that the current Test.java in the temporary directory is compiled
     and executed under the current execution mode. On success, transfers the
-    generated output to the file GetId()_out.txt in the temporary directory.
-    Cleans up after itself.
+    generated output to the file self.output_file in the temporary directory.
 
     Most nonzero return codes are assumed non-divergent, since systems may
     exit in different ways. This is enforced by normalizing return codes.
@@ -151,112 +148,196 @@
     Returns:
       normalized return code
     """
-    pass
+
 
 class TestRunnerRIOnHost(TestRunner):
   """Concrete test runner of the reference implementation on host."""
 
-  def  __init__(self):
-    """Constructor for the RI tester."""
-    self._description = 'RI on host'
-    self._id = 'RI'
+  @property
+  def description(self):
+    return 'RI on host'
+
+  @property
+  def id(self):
+    return 'RI'
 
   def CompileAndRunTest(self):
-    if RunCommand('javac', 'Test.java',
-                  out=None, err=None, timeout=30) == EXIT_SUCCESS:
-      retc = RunCommand('java', 'Test', 'RI_run_out.txt', err=None)
-      if retc != EXIT_SUCCESS and retc != EXIT_TIMEOUT:
-        retc = EXIT_NOTRUN
+    if RunCommand(['javac', 'Test.java'],
+                  out=None, err=None, timeout=30) == RetCode.SUCCESS:
+      retc = RunCommand(['java', 'Test'], self.output_file, err=None)
     else:
-      retc = EXIT_NOTCOMPILED
-    # Cleanup and return.
-    RunCommand('rm', '-f Test.class', out=None, err=None)
+      retc = RetCode.NOTCOMPILED
     return retc
 
-class TestRunnerArtOnHost(TestRunner):
-  """Concrete test runner of Art on host (interpreter or optimizing)."""
+  def GetBisectionSearchArgs(self):
+    return None
 
-  def  __init__(self, interpreter):
+
+class TestRunnerArtOnHost(TestRunner):
+  """Abstract test runner of Art on host."""
+
+  def  __init__(self, extra_args=None):
     """Constructor for the Art on host tester.
 
     Args:
-      interpreter: boolean, selects between interpreter or optimizing
+      extra_args: list of strings, extra arguments for dalvikvm
     """
-    self._art_args = '-cp classes.dex Test'
-    if interpreter:
-      self._description = 'Art interpreter on host'
-      self._id = 'HInt'
-      self._art_args = '-Xint ' + self._art_args
-    else:
-      self._description = 'Art optimizing on host'
-      self._id = 'HOpt'
-    self._jack_args = '-cp ' + GetJackClassPath() + ' --output-dex . Test.java'
+    self._art_cmd = ['/bin/bash', 'art', '-cp', 'classes.dex']
+    if extra_args is not None:
+      self._art_cmd += extra_args
+    self._art_cmd.append('Test')
+    self._jack_args = ['-cp', GetJackClassPath(), '--output-dex', '.',
+                       'Test.java']
 
   def CompileAndRunTest(self):
-    if RunCommand('jack', self._jack_args,
-                  out=None, err='jackerr.txt', timeout=30) == EXIT_SUCCESS:
-      out = self.GetId() + '_run_out.txt'
-      retc = RunCommand('art', self._art_args, out, 'arterr.txt')
-      if retc != EXIT_SUCCESS and retc != EXIT_TIMEOUT:
-        retc = EXIT_NOTRUN
+    if RunCommand(['jack'] + self._jack_args, out=None, err='jackerr.txt',
+                  timeout=30) == RetCode.SUCCESS:
+      retc = RunCommand(self._art_cmd, self.output_file, 'arterr.txt')
     else:
-      retc = EXIT_NOTCOMPILED
-    # Cleanup and return.
-    RunCommand('rm', '-rf classes.dex jackerr.txt arterr.txt android-data*',
-               out=None, err=None)
+      retc = RetCode.NOTCOMPILED
     return retc
 
-# TODO: very rough first version without proper cache,
-#       reuse staszkiewicz' module for properly setting up dalvikvm on target.
-class TestRunnerArtOnTarget(TestRunner):
-  """Concrete test runner of Art on target (interpreter or optimizing)."""
 
-  def  __init__(self, device, interpreter):
+class TestRunnerArtIntOnHost(TestRunnerArtOnHost):
+  """Concrete test runner of interpreter mode Art on host."""
+
+  def  __init__(self):
+    """Constructor."""
+    super().__init__(['-Xint'])
+
+  @property
+  def description(self):
+    return 'Art interpreter on host'
+
+  @property
+  def id(self):
+    return 'HInt'
+
+  def GetBisectionSearchArgs(self):
+    return None
+
+
+class TestRunnerArtOptOnHost(TestRunnerArtOnHost):
+  """Concrete test runner of optimizing compiler mode Art on host."""
+
+  def  __init__(self):
+    """Constructor."""
+    super().__init__(None)
+
+  @property
+  def description(self):
+    return 'Art optimizing on host'
+
+  @property
+  def id(self):
+    return 'HOpt'
+
+  def GetBisectionSearchArgs(self):
+    cmd_str = CommandListToCommandString(
+        self._art_cmd[0:2] + ['{ARGS}'] + self._art_cmd[2:])
+    return ['--raw-cmd={0}'.format(cmd_str), '--timeout', str(30)]
+
+
+class TestRunnerArtOnTarget(TestRunner):
+  """Abstract test runner of Art on target."""
+
+  def  __init__(self, device, extra_args=None):
     """Constructor for the Art on target tester.
 
     Args:
       device: string, target device serial number (or None)
-      interpreter: boolean, selects between interpreter or optimizing
+      extra_args: list of strings, extra arguments for dalvikvm
     """
-    self._dalvik_args = 'shell dalvikvm -cp /data/local/tmp/classes.dex Test'
-    if interpreter:
-      self._description = 'Art interpreter on target'
-      self._id = 'TInt'
-      self._dalvik_args = '-Xint ' + self._dalvik_args
-    else:
-      self._description = 'Art optimizing on target'
-      self._id = 'TOpt'
-    self._adb = 'adb'
-    if device != None:
-      self._adb = self._adb + ' -s ' + device
-    self._jack_args = '-cp ' + GetJackClassPath() + ' --output-dex . Test.java'
+    self._test_env = DeviceTestEnv('javafuzz_', specific_device=device)
+    self._dalvik_cmd = ['dalvikvm']
+    if extra_args is not None:
+      self._dalvik_cmd += extra_args
+    self._device = device
+    self._jack_args = ['-cp', GetJackClassPath(), '--output-dex', '.',
+                       'Test.java']
+    self._device_classpath = None
 
   def CompileAndRunTest(self):
-    if RunCommand('jack', self._jack_args,
-                  out=None, err='jackerr.txt', timeout=30) == EXIT_SUCCESS:
-      if RunCommand(self._adb, 'push classes.dex /data/local/tmp/',
-                    'adb.txt', err=None) != EXIT_SUCCESS:
-        raise FatalError('Cannot push to target device')
-      out = self.GetId() + '_run_out.txt'
-      retc = RunCommand(self._adb, self._dalvik_args, out, err=None)
-      if retc != EXIT_SUCCESS and retc != EXIT_TIMEOUT:
-        retc = EXIT_NOTRUN
+    if RunCommand(['jack'] + self._jack_args, out=None, err='jackerr.txt',
+                   timeout=30) == RetCode.SUCCESS:
+      self._device_classpath = self._test_env.PushClasspath('classes.dex')
+      cmd = self._dalvik_cmd + ['-cp', self._device_classpath, 'Test']
+      (output, retc) = self._test_env.RunCommand(
+          cmd, {'ANDROID_LOG_TAGS': '*:s'})
+      with open(self.output_file, 'w') as run_out:
+        run_out.write(output)
     else:
-      retc = EXIT_NOTCOMPILED
-    # Cleanup and return.
-    RunCommand('rm', '-f classes.dex jackerr.txt adb.txt',
-               out=None, err=None)
-    RunCommand(self._adb, 'shell rm -f /data/local/tmp/classes.dex',
-               out=None, err=None)
+      retc = RetCode.NOTCOMPILED
     return retc
 
+  def GetBisectionSearchArgs(self):
+    cmd_str = CommandListToCommandString(
+        self._dalvik_cmd + ['-cp',self._device_classpath, 'Test'])
+    cmd = ['--raw-cmd={0}'.format(cmd_str), '--timeout', str(30)]
+    if self._device:
+      cmd += ['--device-serial', self._device]
+    else:
+      cmd.append('--device')
+    return cmd
+
+
+class TestRunnerArtIntOnTarget(TestRunnerArtOnTarget):
+  """Concrete test runner of interpreter mode Art on target."""
+
+  def  __init__(self, device):
+    """Constructor.
+
+    Args:
+      device: string, target device serial number (or None)
+    """
+    super().__init__(device, ['-Xint'])
+
+  @property
+  def description(self):
+    return 'Art interpreter on target'
+
+  @property
+  def id(self):
+    return 'TInt'
+
+  def GetBisectionSearchArgs(self):
+    return None
+
+
+class TestRunnerArtOptOnTarget(TestRunnerArtOnTarget):
+  """Concrete test runner of optimizing compiler mode Art on target."""
+
+  def  __init__(self, device):
+    """Constructor.
+
+    Args:
+      device: string, target device serial number (or None)
+    """
+    super().__init__(device, None)
+
+  @property
+  def description(self):
+    return 'Art optimizing on target'
+
+  @property
+  def id(self):
+    return 'TOpt'
+
+  def GetBisectionSearchArgs(self):
+    cmd_str = CommandListToCommandString(
+        self._dalvik_cmd + ['-cp', self._device_classpath, 'Test'])
+    cmd = ['--raw-cmd={0}'.format(cmd_str), '--timeout', str(30)]
+    if self._device:
+      cmd += ['--device-serial', self._device]
+    else:
+      cmd.append('--device')
+    return cmd
+
+
 #
 # Tester classes.
 #
 
-class FatalError(Exception):
-  """Fatal error in the tester."""
-  pass
 
 class JavaFuzzTester(object):
   """Tester that runs JavaFuzz many times and report divergences."""
@@ -265,10 +346,10 @@
     """Constructor for the tester.
 
     Args:
-    num_tests: int, number of tests to run
-    device: string, target device serial number (or None)
-    mode1: string, execution mode for first runner
-    mode2: string, execution mode for second runner
+      num_tests: int, number of tests to run
+      device: string, target device serial number (or None)
+      mode1: string, execution mode for first runner
+      mode2: string, execution mode for second runner
     """
     self._num_tests = num_tests
     self._device = device
@@ -291,8 +372,9 @@
       FatalError: error when temp directory cannot be constructed
     """
     self._save_dir = os.getcwd()
-    self._tmp_dir = mkdtemp(dir="/tmp/")
-    if self._tmp_dir == None:
+    self._results_dir = mkdtemp(dir='/tmp/')
+    self._tmp_dir = mkdtemp(dir=self._results_dir)
+    if self._tmp_dir is None or self._results_dir is None:
       raise FatalError('Cannot obtain temp directory')
     os.chdir(self._tmp_dir)
     return self
@@ -300,37 +382,38 @@
   def __exit__(self, etype, evalue, etraceback):
     """On exit, re-enters previously saved current directory and cleans up."""
     os.chdir(self._save_dir)
+    shutil.rmtree(self._tmp_dir)
     if self._num_divergences == 0:
-      RunCommand('rm', '-rf ' + self._tmp_dir, out=None, err=None)
+      shutil.rmtree(self._results_dir)
 
   def Run(self):
     """Runs JavaFuzz many times and report divergences."""
-    print
-    print '**\n**** JavaFuzz Testing\n**'
-    print
-    print '#Tests    :', self._num_tests
-    print 'Device    :', self._device
-    print 'Directory :', self._tmp_dir
-    print 'Exec-mode1:', self._runner1.GetDescription()
-    print 'Exec-mode2:', self._runner2.GetDescription()
-    print
+    print()
+    print('**\n**** JavaFuzz Testing\n**')
+    print()
+    print('#Tests    :', self._num_tests)
+    print('Device    :', self._device)
+    print('Directory :', self._results_dir)
+    print('Exec-mode1:', self._runner1.description)
+    print('Exec-mode2:', self._runner2.description)
+    print()
     self.ShowStats()
     for self._test in range(1, self._num_tests + 1):
       self.RunJavaFuzzTest()
       self.ShowStats()
     if self._num_divergences == 0:
-      print '\n\nsuccess (no divergences)\n'
+      print('\n\nsuccess (no divergences)\n')
     else:
-      print '\n\nfailure (divergences)\n'
+      print('\n\nfailure (divergences)\n')
 
   def ShowStats(self):
     """Shows current statistics (on same line) while tester is running."""
-    print '\rTests:', self._test, \
-        'Success:', self._num_success, \
-        'Not-compiled:', self._num_not_compiled, \
-        'Not-run:', self._num_not_run, \
-        'Timed-out:', self._num_timed_out, \
-        'Divergences:', self._num_divergences,
+    print('\rTests:', self._test, \
+          'Success:', self._num_success, \
+          'Not-compiled:', self._num_not_compiled, \
+          'Not-run:', self._num_not_run, \
+          'Timed-out:', self._num_timed_out, \
+          'Divergences:', self._num_divergences, end='')
     sys.stdout.flush()
 
   def RunJavaFuzzTest(self):
@@ -347,8 +430,7 @@
     Raises:
       FatalError: error when javafuzz fails
     """
-    if RunCommand('javafuzz', args=None,
-                  out='Test.java', err=None) != EXIT_SUCCESS:
+    if RunCommand(['javafuzz'], out='Test.java', err=None) != RetCode.SUCCESS:
       raise FatalError('Unexpected error while running JavaFuzz')
 
   def CheckForDivergence(self, retc1, retc2):
@@ -360,38 +442,85 @@
     """
     if retc1 == retc2:
       # Non-divergent in return code.
-      if retc1 == EXIT_SUCCESS:
+      if retc1 == RetCode.SUCCESS:
         # Both compilations and runs were successful, inspect generated output.
-        args = self._runner1.GetId() + '_run_out.txt ' \
-            + self._runner2.GetId() + '_run_out.txt'
-        if RunCommand('diff', args, out=None, err=None) != EXIT_SUCCESS:
-          self.ReportDivergence('divergence in output')
+        runner1_out = self._runner1.output_file
+        runner2_out = self._runner2.output_file
+        if not filecmp.cmp(runner1_out, runner2_out, shallow=False):
+          self.ReportDivergence(retc1, retc2, is_output_divergence=True)
         else:
           self._num_success += 1
-      elif retc1 == EXIT_TIMEOUT:
+      elif retc1 == RetCode.TIMEOUT:
         self._num_timed_out += 1
-      elif retc1 == EXIT_NOTCOMPILED:
+      elif retc1 == RetCode.NOTCOMPILED:
         self._num_not_compiled += 1
       else:
         self._num_not_run += 1
     else:
       # Divergent in return code.
-      self.ReportDivergence('divergence in return code: ' +
-                            GetReturnCode(retc1) + ' vs. ' +
-                            GetReturnCode(retc2))
+      self.ReportDivergence(retc1, retc2, is_output_divergence=False)
 
-  def ReportDivergence(self, reason):
+  def GetCurrentDivergenceDir(self):
+    return self._results_dir + '/divergence' + str(self._num_divergences)
+
+  def ReportDivergence(self, retc1, retc2, is_output_divergence):
     """Reports and saves a divergence."""
     self._num_divergences += 1
-    print '\n', self._test, reason
+    print('\n' + str(self._num_divergences), end='')
+    if is_output_divergence:
+      print(' divergence in output')
+    else:
+      print(' divergence in return code: ' + retc1.name + ' vs. ' +
+            retc2.name)
     # Save.
-    ddir = 'divergence' + str(self._test)
-    RunCommand('mkdir', ddir, out=None, err=None)
-    RunCommand('mv', 'Test.java *.txt ' + ddir, out=None, err=None)
+    ddir = self.GetCurrentDivergenceDir()
+    os.mkdir(ddir)
+    for f in glob('*.txt') + ['Test.java']:
+      shutil.copy(f, ddir)
+    # Maybe run bisection bug search.
+    if retc1 in BISECTABLE_RET_CODES and retc2 in BISECTABLE_RET_CODES:
+      self.MaybeBisectDivergence(retc1, retc2, is_output_divergence)
+
+  def RunBisectionSearch(self, args, expected_retcode, expected_output,
+                         runner_id):
+    ddir = self.GetCurrentDivergenceDir()
+    outfile_path = ddir + '/' + runner_id + '_bisection_out.txt'
+    logfile_path = ddir + '/' + runner_id + '_bisection_log.txt'
+    errfile_path = ddir + '/' + runner_id + '_bisection_err.txt'
+    args = list(args) + ['--logfile', logfile_path, '--cleanup']
+    args += ['--expected-retcode', expected_retcode.name]
+    if expected_output:
+      args += ['--expected-output', expected_output]
+    bisection_search_path = os.path.join(
+        GetEnvVariableOrError('ANDROID_BUILD_TOP'),
+        'art/tools/bisection_search/bisection_search.py')
+    if RunCommand([bisection_search_path] + args, out=outfile_path,
+                  err=errfile_path, timeout=300) == RetCode.TIMEOUT:
+      print('Bisection search TIMEOUT')
+
+  def MaybeBisectDivergence(self, retc1, retc2, is_output_divergence):
+    bisection_args1 = self._runner1.GetBisectionSearchArgs()
+    bisection_args2 = self._runner2.GetBisectionSearchArgs()
+    if is_output_divergence:
+      maybe_output1 = self._runner1.output_file
+      maybe_output2 = self._runner2.output_file
+    else:
+      maybe_output1 = maybe_output2 = None
+    if bisection_args1 is not None:
+      self.RunBisectionSearch(bisection_args1, retc2, maybe_output2,
+                              self._runner1.id)
+    if bisection_args2 is not None:
+      self.RunBisectionSearch(bisection_args2, retc1, maybe_output1,
+                              self._runner2.id)
 
   def CleanupTest(self):
     """Cleans up after a single test run."""
-    RunCommand('rm', '-f Test.java *.txt', out=None, err=None)
+    for file_name in os.listdir(self._tmp_dir):
+        file_path = os.path.join(self._tmp_dir, file_name)
+        if os.path.isfile(file_path):
+          os.unlink(file_path)
+        elif os.path.isdir(file_path):
+          shutil.rmtree(file_path)
 
 
 def main():
@@ -406,11 +535,11 @@
                       help='execution mode 2 (default: hopt)')
   args = parser.parse_args()
   if args.mode1 == args.mode2:
-    raise FatalError("Identical execution modes given")
+    raise FatalError('Identical execution modes given')
   # Run the JavaFuzz tester.
   with JavaFuzzTester(args.num_tests, args.device,
                       args.mode1, args.mode2) as fuzzer:
     fuzzer.Run()
 
-if __name__ == "__main__":
+if __name__ == '__main__':
   main()
diff --git a/tools/run-jdwp-tests.sh b/tools/run-jdwp-tests.sh
index 01dae43..74b0f16 100755
--- a/tools/run-jdwp-tests.sh
+++ b/tools/run-jdwp-tests.sh
@@ -43,7 +43,7 @@
 image_compiler_option=""
 debug="no"
 verbose="no"
-image="-Ximage:/data/art-test/core-optimizing-pic.art"
+image="-Ximage:/data/art-test/core.art"
 vm_args=""
 # By default, we run the whole JDWP test suite.
 test="org.apache.harmony.jpda.tests.share.AllTests"
diff --git a/tools/run-libcore-tests.sh b/tools/run-libcore-tests.sh
index 2a6e172..01c7f20 100755
--- a/tools/run-libcore-tests.sh
+++ b/tools/run-libcore-tests.sh
@@ -95,7 +95,7 @@
   if [[ "$1" == "--mode=device" ]]; then
     vogar_args="$vogar_args --device-dir=/data/local/tmp"
     vogar_args="$vogar_args --vm-command=/data/local/tmp/system/bin/art"
-    vogar_args="$vogar_args --vm-arg -Ximage:/data/art-test/core-optimizing.art"
+    vogar_args="$vogar_args --vm-arg -Ximage:/data/art-test/core.art"
     shift
   elif [[ "$1" == "--mode=host" ]]; then
     # We explicitly give a wrong path for the image, to ensure vogar