Merge "Remove unnecessary `static` specifiers in `common_arm64.h`."
diff --git a/Android.bp b/Android.bp
index 835048d..77b9ac3 100644
--- a/Android.bp
+++ b/Android.bp
@@ -1,6 +1,34 @@
+// TODO: These should be handled with transitive static library dependencies
+art_static_dependencies = [
+    // Note: the order is important because of static linking resolution.
+    "libziparchive",
+    "libnativehelper",
+    "libnativebridge",
+    "libnativeloader",
+    "libsigchain_dummy",
+    "liblog",
+    "libz",
+    "libbacktrace",
+    "libcutils",
+    "libunwindbacktrace",
+    "libutils",
+    "libbase",
+    "liblz4",
+    "liblzma",
+]
+
 subdirs = [
+    "benchmark",
     "build",
     "compiler",
+    "dalvikvm",
+    "dexdump",
+    "dexlayout",
+    "dexlist",
+    "disassembler",
+    "oatdump",
     "runtime",
     "sigchainlib",
+    "tools/cpp-define-generator",
+    "tools/dmtracedump",
 ]
diff --git a/Android.mk b/Android.mk
index 4ea169a..0ed5d87 100644
--- a/Android.mk
+++ b/Android.mk
@@ -76,20 +76,13 @@
 ########################################################################
 # product rules
 
-include $(art_path)/dexdump/Android.mk
-include $(art_path)/dexlayout/Android.mk
-include $(art_path)/dexlist/Android.mk
 include $(art_path)/dex2oat/Android.mk
-include $(art_path)/disassembler/Android.mk
-include $(art_path)/oatdump/Android.mk
 include $(art_path)/imgdiag/Android.mk
 include $(art_path)/patchoat/Android.mk
 include $(art_path)/profman/Android.mk
-include $(art_path)/dalvikvm/Android.mk
 include $(art_path)/tools/Android.mk
 include $(art_path)/tools/ahat/Android.mk
 include $(art_path)/tools/dexfuzz/Android.mk
-include $(art_path)/tools/dmtracedump/Android.mk
 include $(art_path)/libart_fake/Android.mk
 
 
@@ -114,7 +107,6 @@
 include $(art_path)/build/Android.common_test.mk
 include $(art_path)/build/Android.gtest.mk
 include $(art_path)/test/Android.run-test.mk
-include $(art_path)/benchmark/Android.mk
 
 TEST_ART_ADB_ROOT_AND_REMOUNT := \
     (adb root && \
diff --git a/benchmark/Android.bp b/benchmark/Android.bp
new file mode 100644
index 0000000..617f5b0
--- /dev/null
+++ b/benchmark/Android.bp
@@ -0,0 +1,43 @@
+//
+// Copyright (C) 2015 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_library {
+    name: "libartbenchmark",
+    host_supported: true,
+    defaults: ["art_defaults", "art_debug_defaults"],
+    srcs: [
+        "jobject-benchmark/jobject_benchmark.cc",
+        "jni-perf/perf_jni.cc",
+        "scoped-primitive-array/scoped_primitive_array.cc",
+    ],
+    shared_libs: [
+        "libart",
+        "libbacktrace",
+        "libnativehelper",
+    ],
+    clang: true,
+    target: {
+        android: {
+            shared_libs: ["libdl"],
+        },
+        host: {
+            host_ldlibs: ["-ldl", "-lpthread"],
+        },
+    },
+    cflags: [
+        "-Wno-frame-larger-than=",
+    ],
+}
diff --git a/benchmark/Android.mk b/benchmark/Android.mk
deleted file mode 100644
index 2360bcc..0000000
--- a/benchmark/Android.mk
+++ /dev/null
@@ -1,79 +0,0 @@
-#
-# Copyright (C) 2015 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.common_build.mk
-
-LIBARTBENCHMARK_COMMON_SRC_FILES := \
-  jobject-benchmark/jobject_benchmark.cc \
-  jni-perf/perf_jni.cc \
-  scoped-primitive-array/scoped_primitive_array.cc
-
-# $(1): target or host
-define build-libartbenchmark
-  ifneq ($(1),target)
-    ifneq ($(1),host)
-      $$(error expected target or host for argument 1, received $(1))
-    endif
-  endif
-
-  art_target_or_host := $(1)
-
-  include $(CLEAR_VARS)
-  LOCAL_CPP_EXTENSION := $(ART_CPP_EXTENSION)
-  LOCAL_MODULE := libartbenchmark
-  ifeq ($$(art_target_or_host),target)
-    LOCAL_MODULE_TAGS := tests
-  endif
-  LOCAL_SRC_FILES := $(LIBARTBENCHMARK_COMMON_SRC_FILES)
-  LOCAL_SHARED_LIBRARIES += libart libbacktrace libnativehelper
-  LOCAL_C_INCLUDES += $(ART_C_INCLUDES) art/runtime
-  LOCAL_ADDITIONAL_DEPENDENCIES := art/build/Android.common_build.mk
-  LOCAL_ADDITIONAL_DEPENDENCIES += $(LOCAL_PATH)/Android.mk
-  ifeq ($$(art_target_or_host),target)
-    LOCAL_CLANG := $(ART_TARGET_CLANG)
-    $(call set-target-local-cflags-vars,debug)
-    LOCAL_SHARED_LIBRARIES += libdl
-    LOCAL_MULTILIB := both
-    # LOCAL_MODULE_PATH_32 := $(ART_TARGET_OUT)/$(ART_TARGET_ARCH_32)
-    # LOCAL_MODULE_PATH_64 := $(ART_TARGET_OUT)/$(ART_TARGET_ARCH_64)
-    LOCAL_MODULE_TARGET_ARCH := $(ART_SUPPORTED_ARCH)
-    include $(BUILD_SHARED_LIBRARY)
-  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_LDLIBS := -ldl -lpthread
-    LOCAL_IS_HOST_MODULE := true
-    LOCAL_MULTILIB := both
-    include $(BUILD_HOST_SHARED_LIBRARY)
-  endif
-
-  # Clear locally used variables.
-  art_target_or_host :=
-endef
-
-ifeq ($(ART_BUILD_TARGET),true)
-  $(eval $(call build-libartbenchmark,target))
-endif
-ifeq ($(ART_BUILD_HOST),true)
-  $(eval $(call build-libartbenchmark,host))
-endif
-
-# Clear locally used variables.
-LOCAL_PATH :=
-LIBARTBENCHMARK_COMMON_SRC_FILES :=
diff --git a/build/Android.bp b/build/Android.bp
index ed9f308..630cf3c 100644
--- a/build/Android.bp
+++ b/build/Android.bp
@@ -101,6 +101,9 @@
                 // Apple, it's a pain.
                 "-Wmissing-noreturn",
             ],
+            host_ldlibs: [
+                "-lrt",
+            ],
         },
         host: {
             cflags: [
@@ -108,6 +111,10 @@
                 // clang/libunwind bugs that cause SEGVs in run-test-004-ThreadStress.
                 "-fno-omit-frame-pointer",
             ],
+            host_ldlibs: [
+                "-ldl",
+                "-lpthread",
+            ],
         },
     },
 
diff --git a/build/Android.common_build.mk b/build/Android.common_build.mk
index b5d41d9..04a0344 100644
--- a/build/Android.common_build.mk
+++ b/build/Android.common_build.mk
@@ -238,6 +238,12 @@
   art_cflags += -DART_USE_TLAB=1
 endif
 
+# Are additional statically-linked ART host binaries (dex2oats,
+# oatdumps, etc.) getting built?
+ifeq ($(ART_BUILD_HOST_STATIC),true)
+  art_cflags += -DART_BUILD_HOST_STATIC=1
+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 3f25ae1..e88d027 100644
--- a/build/Android.common_path.mk
+++ b/build/Android.common_path.mk
@@ -123,7 +123,7 @@
 
 # Depend on the -target or -host phony targets generated by the build system
 # for each module
-ART_TARGET_EXECUTABLES :=
+ART_TARGET_EXECUTABLES := dalvikvm-target
 ifneq ($(ART_BUILD_TARGET_NDEBUG),false)
 ART_TARGET_EXECUTABLES += $(foreach name,$(ART_CORE_EXECUTABLES),$(name)-target)
 endif
@@ -131,7 +131,7 @@
 ART_TARGET_EXECUTABLES += $(foreach name,$(ART_CORE_EXECUTABLES),$(name)d-target)
 endif
 
-ART_HOST_EXECUTABLES :=
+ART_HOST_EXECUTABLES := dalvikvm-host
 ifneq ($(ART_BUILD_HOST_NDEBUG),false)
 ART_HOST_EXECUTABLES += $(foreach name,$(ART_CORE_EXECUTABLES),$(name)-host)
 endif
diff --git a/build/Android.executable.mk b/build/Android.executable.mk
index f38a14d..c35833d 100644
--- a/build/Android.executable.mk
+++ b/build/Android.executable.mk
@@ -249,3 +249,20 @@
     )
   )
 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/art.go b/build/art.go
index 4e64dcf..9cab3b9 100644
--- a/build/art.go
+++ b/build/art.go
@@ -67,6 +67,12 @@
 		cflags = append(cflags, "-fstack-protector")
 	}
 
+	// Are additional statically-linked ART host binaries
+	// (dex2oats, oatdumps, etc.) getting built?
+	if envTrue(ctx, "ART_BUILD_HOST_STATIC") {
+		cflags = append(cflags, "-DART_BUILD_HOST_STATIC=1")
+	}
+
 	return cflags, asflags
 }
 
@@ -135,8 +141,42 @@
 
 type artGlobalDefaults struct{}
 
+func (a *artCustomLinkerCustomizer) CustomizeProperties(ctx android.CustomizePropertiesContext) {
+	linker := envDefault(ctx, "CUSTOM_TARGET_LINKER", "")
+	if linker != "" {
+		type props struct {
+			DynamicLinker string
+		}
+
+		p := &props{}
+		p.DynamicLinker = linker
+		ctx.AppendProperties(p)
+	}
+}
+
+type artCustomLinkerCustomizer struct{}
+
+func (a *artPrefer32BitCustomizer) CustomizeProperties(ctx android.CustomizePropertiesContext) {
+	if envTrue(ctx, "HOST_PREFER_32_BIT") {
+		type props struct {
+			Target struct {
+				Host struct {
+					Compile_multilib string
+				}
+			}
+		}
+
+		p := &props{}
+		p.Target.Host.Compile_multilib = "prefer32"
+		ctx.AppendProperties(p)
+	}
+}
+
+type artPrefer32BitCustomizer struct{}
+
 func init() {
 	soong.RegisterModuleType("art_cc_library", artLibrary)
+	soong.RegisterModuleType("art_cc_binary", artBinary)
 	soong.RegisterModuleType("art_cc_defaults", artDefaultsFactory)
 	soong.RegisterModuleType("art_global_defaults", artGlobalDefaultsFactory)
 }
@@ -164,6 +204,16 @@
 	c := &codegenCustomizer{}
 	android.AddCustomizer(library, c)
 	props = append(props, &c.codegenProperties)
+
+	return module, props
+}
+
+func artBinary() (blueprint.Module, []interface{}) {
+	binary, _ := cc.NewBinary(android.HostAndDeviceSupported)
+	module, props := binary.Init()
+
+	android.AddCustomizer(binary, &artCustomLinkerCustomizer{})
+	android.AddCustomizer(binary, &artPrefer32BitCustomizer{})
 	return module, props
 }
 
diff --git a/compiler/Android.bp b/compiler/Android.bp
index 0143268..595a824 100644
--- a/compiler/Android.bp
+++ b/compiler/Android.bp
@@ -188,6 +188,7 @@
         "liblzma",
     ],
     include_dirs: ["art/disassembler"],
+    export_include_dirs: ["."],
 }
 
 gensrcs {
diff --git a/compiler/optimizing/code_generator_arm.cc b/compiler/optimizing/code_generator_arm.cc
index 5d7b491..3c4a3e8 100644
--- a/compiler/optimizing/code_generator_arm.cc
+++ b/compiler/optimizing/code_generator_arm.cc
@@ -247,35 +247,6 @@
   DISALLOW_COPY_AND_ASSIGN(LoadClassSlowPathARM);
 };
 
-class LoadStringSlowPathARM : public SlowPathCode {
- public:
-  explicit LoadStringSlowPathARM(HLoadString* instruction) : SlowPathCode(instruction) {}
-
-  void EmitNativeCode(CodeGenerator* codegen) OVERRIDE {
-    LocationSummary* locations = instruction_->GetLocations();
-    DCHECK(!locations->GetLiveRegisters()->ContainsCoreRegister(locations->Out().reg()));
-
-    CodeGeneratorARM* arm_codegen = down_cast<CodeGeneratorARM*>(codegen);
-    __ Bind(GetEntryLabel());
-    SaveLiveRegisters(codegen, locations);
-
-    InvokeRuntimeCallingConvention calling_convention;
-    const uint32_t string_index = instruction_->AsLoadString()->GetStringIndex();
-    __ LoadImmediate(calling_convention.GetRegisterAt(0), string_index);
-    arm_codegen->InvokeRuntime(kQuickResolveString, instruction_, instruction_->GetDexPc(), this);
-    CheckEntrypointTypes<kQuickResolveString, void*, uint32_t>();
-    arm_codegen->Move32(locations->Out(), Location::RegisterLocation(R0));
-
-    RestoreLiveRegisters(codegen, locations);
-    __ b(GetExitLabel());
-  }
-
-  const char* GetDescription() const OVERRIDE { return "LoadStringSlowPathARM"; }
-
- private:
-  DISALLOW_COPY_AND_ASSIGN(LoadStringSlowPathARM);
-};
-
 class TypeCheckSlowPathARM : public SlowPathCode {
  public:
   TypeCheckSlowPathARM(HInstruction* instruction, bool is_fatal)
@@ -344,7 +315,6 @@
   void EmitNativeCode(CodeGenerator* codegen) OVERRIDE {
     CodeGeneratorARM* arm_codegen = down_cast<CodeGeneratorARM*>(codegen);
     __ Bind(GetEntryLabel());
-    SaveLiveRegisters(codegen, instruction_->GetLocations());
     arm_codegen->InvokeRuntime(kQuickDeoptimize, instruction_, instruction_->GetDexPc(), this);
     CheckEntrypointTypes<kQuickDeoptimize, void, void>();
   }
@@ -1532,6 +1502,7 @@
 void LocationsBuilderARM::VisitDeoptimize(HDeoptimize* deoptimize) {
   LocationSummary* locations = new (GetGraph()->GetArena())
       LocationSummary(deoptimize, LocationSummary::kCallOnSlowPath);
+  locations->SetCustomSlowPathCallerSaves(RegisterSet());  // No caller-save registers.
   if (IsBooleanValueOrMaterializedCondition(deoptimize->InputAt(0))) {
     locations->SetInAt(0, Location::RequiresRegister());
   }
@@ -4627,7 +4598,6 @@
   }
   if (needs_write_barrier) {
     // Temporary registers for the write barrier.
-    // These registers may be used for Baker read barriers too.
     locations->AddTemp(Location::RequiresRegister());  // Possibly used for ref. poisoning too.
     locations->AddTemp(Location::RequiresRegister());
   }
@@ -4745,127 +4715,42 @@
           __ Bind(&non_zero);
         }
 
-        if (kEmitCompilerReadBarrier) {
-          if (!kUseBakerReadBarrier) {
-            // When (non-Baker) read barriers are enabled, the type
-            // checking instrumentation requires two read barriers
-            // generated by CodeGeneratorARM::GenerateReadBarrierSlow:
-            //
-            //   __ Mov(temp2, temp1);
-            //   // /* HeapReference<Class> */ temp1 = temp1->component_type_
-            //   __ LoadFromOffset(kLoadWord, temp1, temp1, component_offset);
-            //   codegen_->GenerateReadBarrierSlow(
-            //       instruction, temp1_loc, temp1_loc, temp2_loc, component_offset);
-            //
-            //   // /* HeapReference<Class> */ temp2 = value->klass_
-            //   __ LoadFromOffset(kLoadWord, temp2, value, class_offset);
-            //   codegen_->GenerateReadBarrierSlow(
-            //       instruction, temp2_loc, temp2_loc, value_loc, class_offset, temp1_loc);
-            //
-            //   __ cmp(temp1, ShifterOperand(temp2));
-            //
-            // However, the second read barrier may trash `temp`, as it
-            // is a temporary register, and as such would not be saved
-            // along with live registers before calling the runtime (nor
-            // restored afterwards).  So in this case, we bail out and
-            // delegate the work to the array set slow path.
-            //
-            // TODO: Extend the register allocator to support a new
-            // "(locally) live temp" location so as to avoid always
-            // going into the slow path when read barriers are enabled?
-            //
-            // There is no such problem with Baker read barriers (see below).
-            __ b(slow_path->GetEntryLabel());
-          } else {
-            Register temp3 = IP;
-            Location temp3_loc = Location::RegisterLocation(temp3);
+        // Note that when read barriers are enabled, the type checks
+        // are performed without read barriers.  This is fine, even in
+        // the case where a class object is in the from-space after
+        // the flip, as a comparison involving such a type would not
+        // produce a false positive; it may of course produce a false
+        // negative, in which case we would take the ArraySet slow
+        // path.
 
-            // Note: `temp3` (scratch register IP) cannot be used as
-            // `ref` argument of GenerateFieldLoadWithBakerReadBarrier
-            // calls below (see ReadBarrierMarkSlowPathARM for more
-            // details).
+        // /* HeapReference<Class> */ temp1 = array->klass_
+        __ LoadFromOffset(kLoadWord, temp1, array, class_offset);
+        codegen_->MaybeRecordImplicitNullCheck(instruction);
+        __ MaybeUnpoisonHeapReference(temp1);
 
-            // /* HeapReference<Class> */ temp1 = array->klass_
-            codegen_->GenerateFieldLoadWithBakerReadBarrier(instruction,
-                                                            temp1_loc,
-                                                            array,
-                                                            class_offset,
-                                                            temp3_loc,
-                                                            /* needs_null_check */ true);
+        // /* HeapReference<Class> */ temp1 = temp1->component_type_
+        __ LoadFromOffset(kLoadWord, temp1, temp1, component_offset);
+        // /* HeapReference<Class> */ temp2 = value->klass_
+        __ LoadFromOffset(kLoadWord, temp2, value, class_offset);
+        // If heap poisoning is enabled, no need to unpoison `temp1`
+        // nor `temp2`, as we are comparing two poisoned references.
+        __ cmp(temp1, ShifterOperand(temp2));
 
-            // /* HeapReference<Class> */ temp1 = temp1->component_type_
-            codegen_->GenerateFieldLoadWithBakerReadBarrier(instruction,
-                                                            temp1_loc,
-                                                            temp1,
-                                                            component_offset,
-                                                            temp3_loc,
-                                                            /* needs_null_check */ false);
-            // Register `temp1` is not trashed by the read barrier
-            // emitted by GenerateFieldLoadWithBakerReadBarrier below,
-            // as that method produces a call to a ReadBarrierMarkRegX
-            // entry point, which saves all potentially live registers,
-            // including temporaries such a `temp1`.
-            // /* HeapReference<Class> */ temp2 = value->klass_
-            codegen_->GenerateFieldLoadWithBakerReadBarrier(instruction,
-                                                            temp2_loc,
-                                                            value,
-                                                            class_offset,
-                                                            temp3_loc,
-                                                            /* needs_null_check */ false);
-            // If heap poisoning is enabled, `temp1` and `temp2` have
-            // been unpoisoned by the the previous calls to
-            // CodeGeneratorARM::GenerateFieldLoadWithBakerReadBarrier.
-            __ cmp(temp1, ShifterOperand(temp2));
-
-            if (instruction->StaticTypeOfArrayIsObjectArray()) {
-              Label do_put;
-              __ b(&do_put, EQ);
-              // We do not need to emit a read barrier for the
-              // following heap reference load, as `temp1` is only used
-              // in a comparison with null below, and this reference
-              // is not kept afterwards.
-              // /* HeapReference<Class> */ temp1 = temp1->super_class_
-              __ LoadFromOffset(kLoadWord, temp1, temp1, super_offset);
-              // If heap poisoning is enabled, no need to unpoison
-              // `temp`, as we are comparing against null below.
-              __ CompareAndBranchIfNonZero(temp1, slow_path->GetEntryLabel());
-              __ Bind(&do_put);
-            } else {
-              __ b(slow_path->GetEntryLabel(), NE);
-            }
-          }
-        } else {
-          // Non read barrier code.
-
-          // /* HeapReference<Class> */ temp1 = array->klass_
-          __ LoadFromOffset(kLoadWord, temp1, array, class_offset);
-          codegen_->MaybeRecordImplicitNullCheck(instruction);
+        if (instruction->StaticTypeOfArrayIsObjectArray()) {
+          Label do_put;
+          __ b(&do_put, EQ);
+          // If heap poisoning is enabled, the `temp1` reference has
+          // not been unpoisoned yet; unpoison it now.
           __ MaybeUnpoisonHeapReference(temp1);
 
-          // /* HeapReference<Class> */ temp1 = temp1->component_type_
-          __ LoadFromOffset(kLoadWord, temp1, temp1, component_offset);
-          // /* HeapReference<Class> */ temp2 = value->klass_
-          __ LoadFromOffset(kLoadWord, temp2, value, class_offset);
-          // If heap poisoning is enabled, no need to unpoison `temp1`
-          // nor `temp2`, as we are comparing two poisoned references.
-          __ cmp(temp1, ShifterOperand(temp2));
-
-          if (instruction->StaticTypeOfArrayIsObjectArray()) {
-            Label do_put;
-            __ b(&do_put, EQ);
-            // If heap poisoning is enabled, the `temp1` reference has
-            // not been unpoisoned yet; unpoison it now.
-            __ MaybeUnpoisonHeapReference(temp1);
-
-            // /* HeapReference<Class> */ temp1 = temp1->super_class_
-            __ LoadFromOffset(kLoadWord, temp1, temp1, super_offset);
-            // If heap poisoning is enabled, no need to unpoison
-            // `temp1`, as we are comparing against null below.
-            __ CompareAndBranchIfNonZero(temp1, slow_path->GetEntryLabel());
-            __ Bind(&do_put);
-          } else {
-            __ b(slow_path->GetEntryLabel(), NE);
-          }
+          // /* HeapReference<Class> */ temp1 = temp1->super_class_
+          __ LoadFromOffset(kLoadWord, temp1, temp1, super_offset);
+          // If heap poisoning is enabled, no need to unpoison
+          // `temp1`, as we are comparing against null below.
+          __ CompareAndBranchIfNonZero(temp1, slow_path->GetEntryLabel());
+          __ Bind(&do_put);
+        } else {
+          __ b(slow_path->GetEntryLabel(), NE);
         }
       }
 
@@ -5337,17 +5222,6 @@
 
 HLoadClass::LoadKind CodeGeneratorARM::GetSupportedLoadClassKind(
     HLoadClass::LoadKind desired_class_load_kind) {
-  if (kEmitCompilerReadBarrier) {
-    switch (desired_class_load_kind) {
-      case HLoadClass::LoadKind::kBootImageLinkTimeAddress:
-      case HLoadClass::LoadKind::kBootImageLinkTimePcRelative:
-      case HLoadClass::LoadKind::kBootImageAddress:
-        // TODO: Implement for read barrier.
-        return HLoadClass::LoadKind::kDexCacheViaMethod;
-      default:
-        break;
-    }
-  }
   switch (desired_class_load_kind) {
     case HLoadClass::LoadKind::kReferrersClass:
       break;
@@ -5389,11 +5263,12 @@
     return;
   }
 
-  LocationSummary::CallKind call_kind = (cls->NeedsEnvironment() || kEmitCompilerReadBarrier)
+  const bool requires_read_barrier = kEmitCompilerReadBarrier && !cls->IsInBootImage();
+  LocationSummary::CallKind call_kind = (cls->NeedsEnvironment() || requires_read_barrier)
       ? LocationSummary::kCallOnSlowPath
       : LocationSummary::kNoCall;
   LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(cls, call_kind);
-  if (kUseBakerReadBarrier && !cls->NeedsEnvironment()) {
+  if (kUseBakerReadBarrier && requires_read_barrier && !cls->NeedsEnvironment()) {
     locations->SetCustomSlowPathCallerSaves(RegisterSet());  // No caller-save registers.
   }
 
@@ -5418,6 +5293,7 @@
   Location out_loc = locations->Out();
   Register out = out_loc.AsRegister<Register>();
 
+  const bool requires_read_barrier = kEmitCompilerReadBarrier && !cls->IsInBootImage();
   bool generate_null_check = false;
   switch (cls->GetLoadKind()) {
     case HLoadClass::LoadKind::kReferrersClass: {
@@ -5425,18 +5301,21 @@
       DCHECK(!cls->MustGenerateClinitCheck());
       // /* GcRoot<mirror::Class> */ out = current_method->declaring_class_
       Register current_method = locations->InAt(0).AsRegister<Register>();
-      GenerateGcRootFieldLoad(
-          cls, out_loc, current_method, ArtMethod::DeclaringClassOffset().Int32Value());
+      GenerateGcRootFieldLoad(cls,
+                              out_loc,
+                              current_method,
+                              ArtMethod::DeclaringClassOffset().Int32Value(),
+                              requires_read_barrier);
       break;
     }
     case HLoadClass::LoadKind::kBootImageLinkTimeAddress: {
-      DCHECK(!kEmitCompilerReadBarrier);
+      DCHECK(!requires_read_barrier);
       __ LoadLiteral(out, codegen_->DeduplicateBootImageTypeLiteral(cls->GetDexFile(),
                                                                     cls->GetTypeIndex()));
       break;
     }
     case HLoadClass::LoadKind::kBootImageLinkTimePcRelative: {
-      DCHECK(!kEmitCompilerReadBarrier);
+      DCHECK(!requires_read_barrier);
       CodeGeneratorARM::PcRelativePatchInfo* labels =
           codegen_->NewPcRelativeTypePatch(cls->GetDexFile(), cls->GetTypeIndex());
       __ BindTrackedLabel(&labels->movw_label);
@@ -5448,7 +5327,7 @@
       break;
     }
     case HLoadClass::LoadKind::kBootImageAddress: {
-      DCHECK(!kEmitCompilerReadBarrier);
+      DCHECK(!requires_read_barrier);
       DCHECK_NE(cls->GetAddress(), 0u);
       uint32_t address = dchecked_integral_cast<uint32_t>(cls->GetAddress());
       __ LoadLiteral(out, codegen_->DeduplicateBootImageAddressLiteral(address));
@@ -5468,7 +5347,7 @@
       uint32_t offset = address & MaxInt<uint32_t>(offset_bits);
       __ LoadLiteral(out, codegen_->DeduplicateDexCacheAddressLiteral(base_address));
       // /* GcRoot<mirror::Class> */ out = *(base_address + offset)
-      GenerateGcRootFieldLoad(cls, out_loc, out, offset);
+      GenerateGcRootFieldLoad(cls, out_loc, out, offset, requires_read_barrier);
       generate_null_check = !cls->IsInDexCache();
       break;
     }
@@ -5477,7 +5356,7 @@
       HArmDexCacheArraysBase* base = cls->InputAt(0)->AsArmDexCacheArraysBase();
       int32_t offset = cls->GetDexCacheElementOffset() - base->GetElementOffset();
       // /* GcRoot<mirror::Class> */ out = *(dex_cache_arrays_base + offset)
-      GenerateGcRootFieldLoad(cls, out_loc, base_reg, offset);
+      GenerateGcRootFieldLoad(cls, out_loc, base_reg, offset, requires_read_barrier);
       generate_null_check = !cls->IsInDexCache();
       break;
     }
@@ -5491,7 +5370,7 @@
                         ArtMethod::DexCacheResolvedTypesOffset(kArmPointerSize).Int32Value());
       // /* GcRoot<mirror::Class> */ out = out[type_index]
       size_t offset = CodeGenerator::GetCacheOffset(cls->GetTypeIndex());
-      GenerateGcRootFieldLoad(cls, out_loc, out, offset);
+      GenerateGcRootFieldLoad(cls, out_loc, out, offset, requires_read_barrier);
       generate_null_check = !cls->IsInDexCache();
     }
   }
@@ -5583,28 +5462,28 @@
 }
 
 void LocationsBuilderARM::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.
-  }
 
   HLoadString::LoadKind load_kind = load->GetLoadKind();
-  if (load_kind == HLoadString::LoadKind::kDexCacheViaMethod ||
-      load_kind == HLoadString::LoadKind::kDexCachePcRelative) {
+  DCHECK(load_kind != HLoadString::LoadKind::kDexCachePcRelative) << "Not supported";
+  if (load_kind == HLoadString::LoadKind::kDexCacheViaMethod) {
     locations->SetInAt(0, Location::RequiresRegister());
+    locations->SetOut(Location::RegisterLocation(R0));
+  } else {
+    locations->SetOut(Location::RequiresRegister());
   }
-  locations->SetOut(Location::RequiresRegister());
 }
 
 void InstructionCodeGeneratorARM::VisitLoadString(HLoadString* load) {
   LocationSummary* locations = load->GetLocations();
   Location out_loc = locations->Out();
   Register out = out_loc.AsRegister<Register>();
+  HLoadString::LoadKind load_kind = load->GetLoadKind();
 
-  switch (load->GetLoadKind()) {
+  switch (load_kind) {
     case HLoadString::LoadKind::kBootImageLinkTimeAddress: {
       DCHECK(!kEmitCompilerReadBarrier);
       __ LoadLiteral(out, codegen_->DeduplicateBootImageStringLiteral(load->GetDexFile(),
@@ -5634,11 +5513,12 @@
       break;
   }
 
-  // TODO: Re-add the compiler code to do string dex cache lookup again.
-  SlowPathCode* slow_path = new (GetGraph()->GetArena()) LoadStringSlowPathARM(load);
-  codegen_->AddSlowPath(slow_path);
-  __ b(slow_path->GetEntryLabel());
-  __ Bind(slow_path->GetExitLabel());
+  // TODO: Consider re-adding the compiler code to do string dex cache lookup again.
+  DCHECK(load_kind == HLoadString::LoadKind::kDexCacheViaMethod);
+  InvokeRuntimeCallingConvention calling_convention;
+  __ LoadImmediate(calling_convention.GetRegisterAt(0), load->GetStringIndex());
+  codegen_->InvokeRuntime(kQuickResolveString, load, load->GetDexPc());
+  CheckEntrypointTypes<kQuickResolveString, void*, uint32_t>();
 }
 
 static int32_t GetExceptionTlsOffset() {
@@ -6403,9 +6283,11 @@
 void InstructionCodeGeneratorARM::GenerateGcRootFieldLoad(HInstruction* instruction,
                                                           Location root,
                                                           Register obj,
-                                                          uint32_t offset) {
+                                                          uint32_t offset,
+                                                          bool requires_read_barrier) {
   Register root_reg = root.AsRegister<Register>();
-  if (kEmitCompilerReadBarrier) {
+  if (requires_read_barrier) {
+    DCHECK(kEmitCompilerReadBarrier);
     if (kUseBakerReadBarrier) {
       // Fast path implementation of art::ReadBarrier::BarrierForRoot when
       // Baker's read barrier are used:
diff --git a/compiler/optimizing/code_generator_arm.h b/compiler/optimizing/code_generator_arm.h
index ac10e23..ce9d7e6 100644
--- a/compiler/optimizing/code_generator_arm.h
+++ b/compiler/optimizing/code_generator_arm.h
@@ -271,11 +271,12 @@
   //
   //   root <- *(obj + offset)
   //
-  // while honoring read barriers (if any).
+  // while honoring read barriers if requires_read_barrier is true.
   void GenerateGcRootFieldLoad(HInstruction* instruction,
                                Location root,
                                Register obj,
-                               uint32_t offset);
+                               uint32_t offset,
+                               bool requires_read_barrier = kEmitCompilerReadBarrier);
   void GenerateTestAndBranch(HInstruction* instruction,
                              size_t condition_input_index,
                              Label* true_target,
diff --git a/compiler/optimizing/code_generator_arm64.cc b/compiler/optimizing/code_generator_arm64.cc
index 3923f52..1d2f334 100644
--- a/compiler/optimizing/code_generator_arm64.cc
+++ b/compiler/optimizing/code_generator_arm64.cc
@@ -336,36 +336,6 @@
   DISALLOW_COPY_AND_ASSIGN(LoadClassSlowPathARM64);
 };
 
-class LoadStringSlowPathARM64 : public SlowPathCodeARM64 {
- public:
-  explicit LoadStringSlowPathARM64(HLoadString* instruction) : SlowPathCodeARM64(instruction) {}
-
-  void EmitNativeCode(CodeGenerator* codegen) OVERRIDE {
-    LocationSummary* locations = instruction_->GetLocations();
-    DCHECK(!locations->GetLiveRegisters()->ContainsCoreRegister(locations->Out().reg()));
-    CodeGeneratorARM64* arm64_codegen = down_cast<CodeGeneratorARM64*>(codegen);
-
-    __ Bind(GetEntryLabel());
-    SaveLiveRegisters(codegen, locations);
-
-    InvokeRuntimeCallingConvention calling_convention;
-    const uint32_t string_index = instruction_->AsLoadString()->GetStringIndex();
-    __ Mov(calling_convention.GetRegisterAt(0).W(), string_index);
-    arm64_codegen->InvokeRuntime(kQuickResolveString, instruction_, instruction_->GetDexPc(), this);
-    CheckEntrypointTypes<kQuickResolveString, void*, uint32_t>();
-    Primitive::Type type = instruction_->GetType();
-    arm64_codegen->MoveLocation(locations->Out(), calling_convention.GetReturnLocation(type), type);
-
-    RestoreLiveRegisters(codegen, locations);
-    __ B(GetExitLabel());
-  }
-
-  const char* GetDescription() const OVERRIDE { return "LoadStringSlowPathARM64"; }
-
- private:
-  DISALLOW_COPY_AND_ASSIGN(LoadStringSlowPathARM64);
-};
-
 class NullCheckSlowPathARM64 : public SlowPathCodeARM64 {
  public:
   explicit NullCheckSlowPathARM64(HNullCheck* instr) : SlowPathCodeARM64(instr) {}
@@ -494,7 +464,6 @@
   void EmitNativeCode(CodeGenerator* codegen) OVERRIDE {
     CodeGeneratorARM64* arm64_codegen = down_cast<CodeGeneratorARM64*>(codegen);
     __ Bind(GetEntryLabel());
-    SaveLiveRegisters(codegen, instruction_->GetLocations());
     arm64_codegen->InvokeRuntime(kQuickDeoptimize, instruction_, instruction_->GetDexPc(), this);
     CheckEntrypointTypes<kQuickDeoptimize, void, void>();
   }
@@ -2179,11 +2148,6 @@
   } else {
     locations->SetInAt(2, Location::RequiresRegister());
   }
-  if (kEmitCompilerReadBarrier && kUseBakerReadBarrier && (value_type == Primitive::kPrimNot)) {
-    // Additional temporary registers for a Baker read barrier.
-    locations->AddTemp(Location::RequiresRegister());
-    locations->AddTemp(Location::RequiresRegister());
-  }
 }
 
 void InstructionCodeGeneratorARM64::VisitArraySet(HArraySet* instruction) {
@@ -2270,144 +2234,44 @@
           __ Bind(&non_zero);
         }
 
-        if (kEmitCompilerReadBarrier) {
-          if (!kUseBakerReadBarrier) {
-            // When (non-Baker) read barriers are enabled, the type
-            // checking instrumentation requires two read barriers
-            // generated by CodeGeneratorARM64::GenerateReadBarrierSlow:
-            //
-            //   __ Mov(temp2, temp);
-            //   // /* HeapReference<Class> */ temp = temp->component_type_
-            //   __ Ldr(temp, HeapOperand(temp, component_offset));
-            //   codegen_->GenerateReadBarrierSlow(
-            //       instruction, temp_loc, temp_loc, temp2_loc, component_offset);
-            //
-            //   // /* HeapReference<Class> */ temp2 = value->klass_
-            //   __ Ldr(temp2, HeapOperand(Register(value), class_offset));
-            //   codegen_->GenerateReadBarrierSlow(
-            //       instruction, temp2_loc, temp2_loc, value_loc, class_offset, temp_loc);
-            //
-            //   __ Cmp(temp, temp2);
-            //
-            // However, the second read barrier may trash `temp`, as it
-            // is a temporary register, and as such would not be saved
-            // along with live registers before calling the runtime (nor
-            // restored afterwards).  So in this case, we bail out and
-            // delegate the work to the array set slow path.
-            //
-            // TODO: Extend the register allocator to support a new
-            // "(locally) live temp" location so as to avoid always
-            // going into the slow path when read barriers are enabled?
-            //
-            // There is no such problem with Baker read barriers (see below).
-            __ B(slow_path->GetEntryLabel());
-          } else {
-            // Note that we cannot use `temps` (instance of VIXL's
-            // UseScratchRegisterScope) to allocate `temp2` because
-            // the Baker read barriers generated by
-            // GenerateFieldLoadWithBakerReadBarrier below also use
-            // that facility to allocate a temporary register, thus
-            // making VIXL's scratch register pool empty.
-            Location temp2_loc = locations->GetTemp(0);
-            Register temp2 = WRegisterFrom(temp2_loc);
+        // Note that when Baker read barriers are enabled, the type
+        // checks are performed without read barriers.  This is fine,
+        // even in the case where a class object is in the from-space
+        // after the flip, as a comparison involving such a type would
+        // not produce a false positive; it may of course produce a
+        // false negative, in which case we would take the ArraySet
+        // slow path.
 
-            // Note: Because it is acquired from VIXL's scratch register
-            // pool, `temp` might be IP0, and thus cannot be used as
-            // `ref` argument of GenerateFieldLoadWithBakerReadBarrier
-            // calls below (see ReadBarrierMarkSlowPathARM64 for more
-            // details).
+        Register temp2 = temps.AcquireSameSizeAs(array);
+        // /* HeapReference<Class> */ temp = array->klass_
+        __ Ldr(temp, HeapOperand(array, class_offset));
+        codegen_->MaybeRecordImplicitNullCheck(instruction);
+        GetAssembler()->MaybeUnpoisonHeapReference(temp);
 
-            // /* HeapReference<Class> */ temp2 = array->klass_
-            codegen_->GenerateFieldLoadWithBakerReadBarrier(instruction,
-                                                            temp2_loc,
-                                                            array,
-                                                            class_offset,
-                                                            temp,
-                                                            /* needs_null_check */ true,
-                                                            /* use_load_acquire */ false);
+        // /* HeapReference<Class> */ temp = temp->component_type_
+        __ Ldr(temp, HeapOperand(temp, component_offset));
+        // /* HeapReference<Class> */ temp2 = value->klass_
+        __ Ldr(temp2, HeapOperand(Register(value), class_offset));
+        // If heap poisoning is enabled, no need to unpoison `temp`
+        // nor `temp2`, as we are comparing two poisoned references.
+        __ Cmp(temp, temp2);
+        temps.Release(temp2);
 
-            // /* HeapReference<Class> */ temp2 = temp2->component_type_
-            codegen_->GenerateFieldLoadWithBakerReadBarrier(instruction,
-                                                            temp2_loc,
-                                                            temp2,
-                                                            component_offset,
-                                                            temp,
-                                                            /* needs_null_check */ false,
-                                                            /* use_load_acquire */ false);
-            // For the same reason that we request `temp2` from the
-            // register allocator above, we cannot get `temp3` from
-            // VIXL's scratch register pool.
-            Location temp3_loc = locations->GetTemp(1);
-            Register temp3 = WRegisterFrom(temp3_loc);
-            // Register `temp2` is not trashed by the read barrier
-            // emitted by GenerateFieldLoadWithBakerReadBarrier below,
-            // as that method produces a call to a ReadBarrierMarkRegX
-            // entry point, which saves all potentially live registers,
-            // including temporaries such a `temp2`.
-            // /* HeapReference<Class> */ temp3 = register_value->klass_
-            codegen_->GenerateFieldLoadWithBakerReadBarrier(instruction,
-                                                            temp3_loc,
-                                                            value.W(),
-                                                            class_offset,
-                                                            temp,
-                                                            /* needs_null_check */ false,
-                                                            /* use_load_acquire */ false);
-            // If heap poisoning is enabled, `temp2` and `temp3` have
-            // been unpoisoned by the the previous calls to
-            // CodeGeneratorARM64::GenerateFieldLoadWithBakerReadBarrier.
-            __ Cmp(temp2, temp3);
-
-            if (instruction->StaticTypeOfArrayIsObjectArray()) {
-              vixl::aarch64::Label do_put;
-              __ B(eq, &do_put);
-              // We do not need to emit a read barrier for the
-              // following heap reference load, as `temp2` is only used
-              // in a comparison with null below, and this reference
-              // is not kept afterwards.
-              // /* HeapReference<Class> */ temp = temp2->super_class_
-              __ Ldr(temp, HeapOperand(temp2, super_offset));
-              // If heap poisoning is enabled, no need to unpoison
-              // `temp`, as we are comparing against null below.
-              __ Cbnz(temp, slow_path->GetEntryLabel());
-              __ Bind(&do_put);
-            } else {
-              __ B(ne, slow_path->GetEntryLabel());
-            }
-          }
-        } else {
-          // Non read barrier code.
-
-          Register temp2 = temps.AcquireSameSizeAs(array);
-          // /* HeapReference<Class> */ temp = array->klass_
-          __ Ldr(temp, HeapOperand(array, class_offset));
-          codegen_->MaybeRecordImplicitNullCheck(instruction);
+        if (instruction->StaticTypeOfArrayIsObjectArray()) {
+          vixl::aarch64::Label do_put;
+          __ B(eq, &do_put);
+          // If heap poisoning is enabled, the `temp` reference has
+          // not been unpoisoned yet; unpoison it now.
           GetAssembler()->MaybeUnpoisonHeapReference(temp);
 
-          // /* HeapReference<Class> */ temp = temp->component_type_
-          __ Ldr(temp, HeapOperand(temp, component_offset));
-          // /* HeapReference<Class> */ temp2 = value->klass_
-          __ Ldr(temp2, HeapOperand(Register(value), class_offset));
-          // If heap poisoning is enabled, no need to unpoison `temp`
-          // nor `temp2`, as we are comparing two poisoned references.
-          __ Cmp(temp, temp2);
-          temps.Release(temp2);
-
-          if (instruction->StaticTypeOfArrayIsObjectArray()) {
-            vixl::aarch64::Label do_put;
-            __ B(eq, &do_put);
-            // If heap poisoning is enabled, the `temp` reference has
-            // not been unpoisoned yet; unpoison it now.
-            GetAssembler()->MaybeUnpoisonHeapReference(temp);
-
-            // /* HeapReference<Class> */ temp = temp->super_class_
-            __ Ldr(temp, HeapOperand(temp, super_offset));
-            // If heap poisoning is enabled, no need to unpoison
-            // `temp`, as we are comparing against null below.
-            __ Cbnz(temp, slow_path->GetEntryLabel());
-            __ Bind(&do_put);
-          } else {
-            __ B(ne, slow_path->GetEntryLabel());
-          }
+          // /* HeapReference<Class> */ temp = temp->super_class_
+          __ Ldr(temp, HeapOperand(temp, super_offset));
+          // If heap poisoning is enabled, no need to unpoison
+          // `temp`, as we are comparing against null below.
+          __ Cbnz(temp, slow_path->GetEntryLabel());
+          __ Bind(&do_put);
+        } else {
+          __ B(ne, slow_path->GetEntryLabel());
         }
       }
 
@@ -3060,6 +2924,7 @@
 void LocationsBuilderARM64::VisitDeoptimize(HDeoptimize* deoptimize) {
   LocationSummary* locations = new (GetGraph()->GetArena())
       LocationSummary(deoptimize, LocationSummary::kCallOnSlowPath);
+  locations->SetCustomSlowPathCallerSaves(RegisterSet());  // No caller-save registers.
   if (IsBooleanValueOrMaterializedCondition(deoptimize->InputAt(0))) {
     locations->SetInAt(0, Location::RequiresRegister());
   }
@@ -4044,17 +3909,6 @@
 
 HLoadClass::LoadKind CodeGeneratorARM64::GetSupportedLoadClassKind(
     HLoadClass::LoadKind desired_class_load_kind) {
-  if (kEmitCompilerReadBarrier) {
-    switch (desired_class_load_kind) {
-      case HLoadClass::LoadKind::kBootImageLinkTimeAddress:
-      case HLoadClass::LoadKind::kBootImageLinkTimePcRelative:
-      case HLoadClass::LoadKind::kBootImageAddress:
-        // TODO: Implement for read barrier.
-        return HLoadClass::LoadKind::kDexCacheViaMethod;
-      default:
-        break;
-    }
-  }
   switch (desired_class_load_kind) {
     case HLoadClass::LoadKind::kReferrersClass:
       break;
@@ -4089,11 +3943,12 @@
     return;
   }
 
-  LocationSummary::CallKind call_kind = (cls->NeedsEnvironment() || kEmitCompilerReadBarrier)
+  const bool requires_read_barrier = kEmitCompilerReadBarrier && !cls->IsInBootImage();
+  LocationSummary::CallKind call_kind = (cls->NeedsEnvironment() || requires_read_barrier)
       ? LocationSummary::kCallOnSlowPath
       : LocationSummary::kNoCall;
   LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(cls, call_kind);
-  if (kUseBakerReadBarrier && !cls->NeedsEnvironment()) {
+  if (kUseBakerReadBarrier && requires_read_barrier && !cls->NeedsEnvironment()) {
     locations->SetCustomSlowPathCallerSaves(RegisterSet());  // No caller-save registers.
   }
 
@@ -4116,6 +3971,7 @@
   Location out_loc = cls->GetLocations()->Out();
   Register out = OutputRegister(cls);
 
+  const bool requires_read_barrier = kEmitCompilerReadBarrier && !cls->IsInBootImage();
   bool generate_null_check = false;
   switch (cls->GetLoadKind()) {
     case HLoadClass::LoadKind::kReferrersClass: {
@@ -4123,17 +3979,21 @@
       DCHECK(!cls->MustGenerateClinitCheck());
       // /* GcRoot<mirror::Class> */ out = current_method->declaring_class_
       Register current_method = InputRegisterAt(cls, 0);
-      GenerateGcRootFieldLoad(
-          cls, out_loc, current_method, ArtMethod::DeclaringClassOffset().Int32Value());
+      GenerateGcRootFieldLoad(cls,
+                              out_loc,
+                              current_method,
+                              ArtMethod::DeclaringClassOffset().Int32Value(),
+                              /*fixup_label*/ nullptr,
+                              requires_read_barrier);
       break;
     }
     case HLoadClass::LoadKind::kBootImageLinkTimeAddress:
-      DCHECK(!kEmitCompilerReadBarrier);
+      DCHECK(!requires_read_barrier);
       __ Ldr(out, codegen_->DeduplicateBootImageTypeLiteral(cls->GetDexFile(),
                                                             cls->GetTypeIndex()));
       break;
     case HLoadClass::LoadKind::kBootImageLinkTimePcRelative: {
-      DCHECK(!kEmitCompilerReadBarrier);
+      DCHECK(!requires_read_barrier);
       // Add ADRP with its PC-relative type patch.
       const DexFile& dex_file = cls->GetDexFile();
       uint32_t type_index = cls->GetTypeIndex();
@@ -4154,7 +4014,7 @@
       break;
     }
     case HLoadClass::LoadKind::kBootImageAddress: {
-      DCHECK(!kEmitCompilerReadBarrier);
+      DCHECK(!requires_read_barrier);
       DCHECK(cls->GetAddress() != 0u && IsUint<32>(cls->GetAddress()));
       __ Ldr(out.W(), codegen_->DeduplicateBootImageAddressLiteral(cls->GetAddress()));
       break;
@@ -4172,7 +4032,12 @@
       uint32_t offset = cls->GetAddress() & MaxInt<uint64_t>(offset_bits);
       __ Ldr(out.X(), codegen_->DeduplicateDexCacheAddressLiteral(base_address));
       // /* GcRoot<mirror::Class> */ out = *(base_address + offset)
-      GenerateGcRootFieldLoad(cls, out_loc, out.X(), offset);
+      GenerateGcRootFieldLoad(cls,
+                              out_loc,
+                              out.X(),
+                              offset,
+                              /*fixup_label*/ nullptr,
+                              requires_read_barrier);
       generate_null_check = !cls->IsInDexCache();
       break;
     }
@@ -4191,7 +4056,12 @@
       vixl::aarch64::Label* ldr_label =
           codegen_->NewPcRelativeDexCacheArrayPatch(dex_file, element_offset, adrp_label);
       // /* GcRoot<mirror::Class> */ out = *(base_address + offset)  /* PC-relative */
-      GenerateGcRootFieldLoad(cls, out_loc, out.X(), /* offset placeholder */ 0, ldr_label);
+      GenerateGcRootFieldLoad(cls,
+                              out_loc,
+                              out.X(),
+                              /* offset placeholder */ 0,
+                              ldr_label,
+                              requires_read_barrier);
       generate_null_check = !cls->IsInDexCache();
       break;
     }
@@ -4203,8 +4073,12 @@
       Register current_method = InputRegisterAt(cls, 0);
       __ Ldr(out.X(), MemOperand(current_method, resolved_types_offset.Int32Value()));
       // /* GcRoot<mirror::Class> */ out = out[type_index]
-      GenerateGcRootFieldLoad(
-          cls, out_loc, out.X(), CodeGenerator::GetCacheOffset(cls->GetTypeIndex()));
+      GenerateGcRootFieldLoad(cls,
+                              out_loc,
+                              out.X(),
+                              CodeGenerator::GetCacheOffset(cls->GetTypeIndex()),
+                              /*fixup_label*/ nullptr,
+                              requires_read_barrier);
       generate_null_check = !cls->IsInDexCache();
       break;
     }
@@ -4283,18 +4157,17 @@
 }
 
 void LocationsBuilderARM64::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());
+    InvokeRuntimeCallingConvention calling_convention;
+    locations->SetOut(calling_convention.GetReturnLocation(load->GetType()));
+  } else {
+    locations->SetOut(Location::RequiresRegister());
   }
-  locations->SetOut(Location::RequiresRegister());
 }
 
 void InstructionCodeGeneratorARM64::VisitLoadString(HLoadString* load) {
@@ -4338,10 +4211,10 @@
   }
 
   // TODO: Re-add the compiler code to do string dex cache lookup again.
-  SlowPathCodeARM64* slow_path = new (GetGraph()->GetArena()) LoadStringSlowPathARM64(load);
-  codegen_->AddSlowPath(slow_path);
-  __ B(slow_path->GetEntryLabel());
-  __ Bind(slow_path->GetExitLabel());
+  InvokeRuntimeCallingConvention calling_convention;
+  __ Mov(calling_convention.GetRegisterAt(0).W(), load->GetStringIndex());
+  codegen_->InvokeRuntime(kQuickResolveString, load, load->GetDexPc());
+  CheckEntrypointTypes<kQuickResolveString, void*, uint32_t>();
 }
 
 void LocationsBuilderARM64::VisitLongConstant(HLongConstant* constant) {
@@ -5106,9 +4979,11 @@
                                                             Location root,
                                                             Register obj,
                                                             uint32_t offset,
-                                                            vixl::aarch64::Label* fixup_label) {
+                                                            vixl::aarch64::Label* fixup_label,
+                                                            bool requires_read_barrier) {
   Register root_reg = RegisterFrom(root, Primitive::kPrimNot);
-  if (kEmitCompilerReadBarrier) {
+  if (requires_read_barrier) {
+    DCHECK(kEmitCompilerReadBarrier);
     if (kUseBakerReadBarrier) {
       // Fast path implementation of art::ReadBarrier::BarrierForRoot when
       // Baker's read barrier are used:
diff --git a/compiler/optimizing/code_generator_arm64.h b/compiler/optimizing/code_generator_arm64.h
index 78db803..f0d7910 100644
--- a/compiler/optimizing/code_generator_arm64.h
+++ b/compiler/optimizing/code_generator_arm64.h
@@ -294,7 +294,8 @@
                                Location root,
                                vixl::aarch64::Register obj,
                                uint32_t offset,
-                               vixl::aarch64::Label* fixup_label = nullptr);
+                               vixl::aarch64::Label* fixup_label = nullptr,
+                               bool requires_read_barrier = kEmitCompilerReadBarrier);
 
   // Generate a floating-point comparison.
   void GenerateFcmp(HInstruction* instruction);
diff --git a/compiler/optimizing/code_generator_mips.cc b/compiler/optimizing/code_generator_mips.cc
index 36bb55a..f07f8a0 100644
--- a/compiler/optimizing/code_generator_mips.cc
+++ b/compiler/optimizing/code_generator_mips.cc
@@ -418,7 +418,6 @@
   void EmitNativeCode(CodeGenerator* codegen) OVERRIDE {
     CodeGeneratorMIPS* mips_codegen = down_cast<CodeGeneratorMIPS*>(codegen);
     __ Bind(GetEntryLabel());
-    SaveLiveRegisters(codegen, instruction_->GetLocations());
     mips_codegen->InvokeRuntime(kQuickDeoptimize, instruction_, instruction_->GetDexPc(), this);
     CheckEntrypointTypes<kQuickDeoptimize, void, void>();
   }
@@ -2379,13 +2378,8 @@
 
     case Primitive::kPrimFloat:
     case Primitive::kPrimDouble:
-      // TODO: don't use branches.
-      GenerateFpCompareAndBranch(instruction->GetCondition(),
-                                 instruction->IsGtBias(),
-                                 type,
-                                 locations,
-                                 &true_label);
-      break;
+      GenerateFpCompare(instruction->GetCondition(), instruction->IsGtBias(), type, locations);
+      return;
   }
 
   // Convert the branches into the result.
@@ -3178,6 +3172,230 @@
   }
 }
 
+void InstructionCodeGeneratorMIPS::GenerateFpCompare(IfCondition cond,
+                                                     bool gt_bias,
+                                                     Primitive::Type type,
+                                                     LocationSummary* locations) {
+  Register dst = locations->Out().AsRegister<Register>();
+  FRegister lhs = locations->InAt(0).AsFpuRegister<FRegister>();
+  FRegister rhs = locations->InAt(1).AsFpuRegister<FRegister>();
+  bool isR6 = codegen_->GetInstructionSetFeatures().IsR6();
+  if (type == Primitive::kPrimFloat) {
+    if (isR6) {
+      switch (cond) {
+        case kCondEQ:
+          __ CmpEqS(FTMP, lhs, rhs);
+          __ Mfc1(dst, FTMP);
+          __ Andi(dst, dst, 1);
+          break;
+        case kCondNE:
+          __ CmpEqS(FTMP, lhs, rhs);
+          __ Mfc1(dst, FTMP);
+          __ Addiu(dst, dst, 1);
+          break;
+        case kCondLT:
+          if (gt_bias) {
+            __ CmpLtS(FTMP, lhs, rhs);
+          } else {
+            __ CmpUltS(FTMP, lhs, rhs);
+          }
+          __ Mfc1(dst, FTMP);
+          __ Andi(dst, dst, 1);
+          break;
+        case kCondLE:
+          if (gt_bias) {
+            __ CmpLeS(FTMP, lhs, rhs);
+          } else {
+            __ CmpUleS(FTMP, lhs, rhs);
+          }
+          __ Mfc1(dst, FTMP);
+          __ Andi(dst, dst, 1);
+          break;
+        case kCondGT:
+          if (gt_bias) {
+            __ CmpUltS(FTMP, rhs, lhs);
+          } else {
+            __ CmpLtS(FTMP, rhs, lhs);
+          }
+          __ Mfc1(dst, FTMP);
+          __ Andi(dst, dst, 1);
+          break;
+        case kCondGE:
+          if (gt_bias) {
+            __ CmpUleS(FTMP, rhs, lhs);
+          } else {
+            __ CmpLeS(FTMP, rhs, lhs);
+          }
+          __ Mfc1(dst, FTMP);
+          __ Andi(dst, dst, 1);
+          break;
+        default:
+          LOG(FATAL) << "Unexpected non-floating-point condition " << cond;
+          UNREACHABLE();
+      }
+    } else {
+      switch (cond) {
+        case kCondEQ:
+          __ CeqS(0, lhs, rhs);
+          __ LoadConst32(dst, 1);
+          __ Movf(dst, ZERO, 0);
+          break;
+        case kCondNE:
+          __ CeqS(0, lhs, rhs);
+          __ LoadConst32(dst, 1);
+          __ Movt(dst, ZERO, 0);
+          break;
+        case kCondLT:
+          if (gt_bias) {
+            __ ColtS(0, lhs, rhs);
+          } else {
+            __ CultS(0, lhs, rhs);
+          }
+          __ LoadConst32(dst, 1);
+          __ Movf(dst, ZERO, 0);
+          break;
+        case kCondLE:
+          if (gt_bias) {
+            __ ColeS(0, lhs, rhs);
+          } else {
+            __ CuleS(0, lhs, rhs);
+          }
+          __ LoadConst32(dst, 1);
+          __ Movf(dst, ZERO, 0);
+          break;
+        case kCondGT:
+          if (gt_bias) {
+            __ CultS(0, rhs, lhs);
+          } else {
+            __ ColtS(0, rhs, lhs);
+          }
+          __ LoadConst32(dst, 1);
+          __ Movf(dst, ZERO, 0);
+          break;
+        case kCondGE:
+          if (gt_bias) {
+            __ CuleS(0, rhs, lhs);
+          } else {
+            __ ColeS(0, rhs, lhs);
+          }
+          __ LoadConst32(dst, 1);
+          __ Movf(dst, ZERO, 0);
+          break;
+        default:
+          LOG(FATAL) << "Unexpected non-floating-point condition " << cond;
+          UNREACHABLE();
+      }
+    }
+  } else {
+    DCHECK_EQ(type, Primitive::kPrimDouble);
+    if (isR6) {
+      switch (cond) {
+        case kCondEQ:
+          __ CmpEqD(FTMP, lhs, rhs);
+          __ Mfc1(dst, FTMP);
+          __ Andi(dst, dst, 1);
+          break;
+        case kCondNE:
+          __ CmpEqD(FTMP, lhs, rhs);
+          __ Mfc1(dst, FTMP);
+          __ Addiu(dst, dst, 1);
+          break;
+        case kCondLT:
+          if (gt_bias) {
+            __ CmpLtD(FTMP, lhs, rhs);
+          } else {
+            __ CmpUltD(FTMP, lhs, rhs);
+          }
+          __ Mfc1(dst, FTMP);
+          __ Andi(dst, dst, 1);
+          break;
+        case kCondLE:
+          if (gt_bias) {
+            __ CmpLeD(FTMP, lhs, rhs);
+          } else {
+            __ CmpUleD(FTMP, lhs, rhs);
+          }
+          __ Mfc1(dst, FTMP);
+          __ Andi(dst, dst, 1);
+          break;
+        case kCondGT:
+          if (gt_bias) {
+            __ CmpUltD(FTMP, rhs, lhs);
+          } else {
+            __ CmpLtD(FTMP, rhs, lhs);
+          }
+          __ Mfc1(dst, FTMP);
+          __ Andi(dst, dst, 1);
+          break;
+        case kCondGE:
+          if (gt_bias) {
+            __ CmpUleD(FTMP, rhs, lhs);
+          } else {
+            __ CmpLeD(FTMP, rhs, lhs);
+          }
+          __ Mfc1(dst, FTMP);
+          __ Andi(dst, dst, 1);
+          break;
+        default:
+          LOG(FATAL) << "Unexpected non-floating-point condition " << cond;
+          UNREACHABLE();
+      }
+    } else {
+      switch (cond) {
+        case kCondEQ:
+          __ CeqD(0, lhs, rhs);
+          __ LoadConst32(dst, 1);
+          __ Movf(dst, ZERO, 0);
+          break;
+        case kCondNE:
+          __ CeqD(0, lhs, rhs);
+          __ LoadConst32(dst, 1);
+          __ Movt(dst, ZERO, 0);
+          break;
+        case kCondLT:
+          if (gt_bias) {
+            __ ColtD(0, lhs, rhs);
+          } else {
+            __ CultD(0, lhs, rhs);
+          }
+          __ LoadConst32(dst, 1);
+          __ Movf(dst, ZERO, 0);
+          break;
+        case kCondLE:
+          if (gt_bias) {
+            __ ColeD(0, lhs, rhs);
+          } else {
+            __ CuleD(0, lhs, rhs);
+          }
+          __ LoadConst32(dst, 1);
+          __ Movf(dst, ZERO, 0);
+          break;
+        case kCondGT:
+          if (gt_bias) {
+            __ CultD(0, rhs, lhs);
+          } else {
+            __ ColtD(0, rhs, lhs);
+          }
+          __ LoadConst32(dst, 1);
+          __ Movf(dst, ZERO, 0);
+          break;
+        case kCondGE:
+          if (gt_bias) {
+            __ CuleD(0, rhs, lhs);
+          } else {
+            __ ColeD(0, rhs, lhs);
+          }
+          __ LoadConst32(dst, 1);
+          __ Movf(dst, ZERO, 0);
+          break;
+        default:
+          LOG(FATAL) << "Unexpected non-floating-point condition " << cond;
+          UNREACHABLE();
+      }
+    }
+  }
+}
+
 void InstructionCodeGeneratorMIPS::GenerateFpCompareAndBranch(IfCondition cond,
                                                               bool gt_bias,
                                                               Primitive::Type type,
@@ -3470,6 +3688,7 @@
 void LocationsBuilderMIPS::VisitDeoptimize(HDeoptimize* deoptimize) {
   LocationSummary* locations = new (GetGraph()->GetArena())
       LocationSummary(deoptimize, LocationSummary::kCallOnSlowPath);
+  locations->SetCustomSlowPathCallerSaves(RegisterSet());  // No caller-save registers.
   if (IsBooleanValueOrMaterializedCondition(deoptimize->InputAt(0))) {
     locations->SetInAt(0, Location::RequiresRegister());
   }
diff --git a/compiler/optimizing/code_generator_mips.h b/compiler/optimizing/code_generator_mips.h
index 7ba6c0d..0039981 100644
--- a/compiler/optimizing/code_generator_mips.h
+++ b/compiler/optimizing/code_generator_mips.h
@@ -243,6 +243,10 @@
   void GenerateLongCompareAndBranch(IfCondition cond,
                                     LocationSummary* locations,
                                     MipsLabel* label);
+  void GenerateFpCompare(IfCondition cond,
+                         bool gt_bias,
+                         Primitive::Type type,
+                         LocationSummary* locations);
   void GenerateFpCompareAndBranch(IfCondition cond,
                                   bool gt_bias,
                                   Primitive::Type type,
diff --git a/compiler/optimizing/code_generator_mips64.cc b/compiler/optimizing/code_generator_mips64.cc
index 18d928d..664d498 100644
--- a/compiler/optimizing/code_generator_mips64.cc
+++ b/compiler/optimizing/code_generator_mips64.cc
@@ -376,7 +376,6 @@
   void EmitNativeCode(CodeGenerator* codegen) OVERRIDE {
     CodeGeneratorMIPS64* mips64_codegen = down_cast<CodeGeneratorMIPS64*>(codegen);
     __ Bind(GetEntryLabel());
-    SaveLiveRegisters(codegen, instruction_->GetLocations());
     mips64_codegen->InvokeRuntime(kQuickDeoptimize, instruction_, instruction_->GetDexPc(), this);
     CheckEntrypointTypes<kQuickDeoptimize, void, void>();
   }
@@ -2631,6 +2630,7 @@
 void LocationsBuilderMIPS64::VisitDeoptimize(HDeoptimize* deoptimize) {
   LocationSummary* locations = new (GetGraph()->GetArena())
       LocationSummary(deoptimize, LocationSummary::kCallOnSlowPath);
+  locations->SetCustomSlowPathCallerSaves(RegisterSet());  // No caller-save registers.
   if (IsBooleanValueOrMaterializedCondition(deoptimize->InputAt(0))) {
     locations->SetInAt(0, Location::RequiresRegister());
   }
diff --git a/compiler/optimizing/code_generator_x86.cc b/compiler/optimizing/code_generator_x86.cc
index 4b3eddd..b3b648f 100644
--- a/compiler/optimizing/code_generator_x86.cc
+++ b/compiler/optimizing/code_generator_x86.cc
@@ -369,7 +369,6 @@
   void EmitNativeCode(CodeGenerator* codegen) OVERRIDE {
     CodeGeneratorX86* x86_codegen = down_cast<CodeGeneratorX86*>(codegen);
     __ Bind(GetEntryLabel());
-    SaveLiveRegisters(codegen, instruction_->GetLocations());
     x86_codegen->InvokeRuntime(kQuickDeoptimize, instruction_, instruction_->GetDexPc(), this);
     CheckEntrypointTypes<kQuickDeoptimize, void, void>();
   }
@@ -1499,6 +1498,7 @@
 void LocationsBuilderX86::VisitDeoptimize(HDeoptimize* deoptimize) {
   LocationSummary* locations = new (GetGraph()->GetArena())
       LocationSummary(deoptimize, LocationSummary::kCallOnSlowPath);
+  locations->SetCustomSlowPathCallerSaves(RegisterSet());  // No caller-save registers.
   if (IsBooleanValueOrMaterializedCondition(deoptimize->InputAt(0))) {
     locations->SetInAt(0, Location::Any());
   }
@@ -5238,7 +5238,6 @@
   }
   if (needs_write_barrier) {
     // Temporary registers for the write barrier.
-    // These registers may be used for Baker read barriers too.
     locations->AddTemp(Location::RequiresRegister());  // Possibly used for ref. poisoning too.
     // Ensure the card is in a byte register.
     locations->AddTemp(Location::RegisterLocation(ECX));
@@ -5328,105 +5327,40 @@
           __ Bind(&not_null);
         }
 
-        if (kEmitCompilerReadBarrier) {
-          if (!kUseBakerReadBarrier) {
-            // When (non-Baker) read barriers are enabled, the type
-            // checking instrumentation requires two read barriers
-            // generated by CodeGeneratorX86::GenerateReadBarrierSlow:
-            //
-            //   __ movl(temp2, temp);
-            //   // /* HeapReference<Class> */ temp = temp->component_type_
-            //   __ movl(temp, Address(temp, component_offset));
-            //   codegen_->GenerateReadBarrierSlow(
-            //       instruction, temp_loc, temp_loc, temp2_loc, component_offset);
-            //
-            //   // /* HeapReference<Class> */ temp2 = register_value->klass_
-            //   __ movl(temp2, Address(register_value, class_offset));
-            //   codegen_->GenerateReadBarrierSlow(
-            //       instruction, temp2_loc, temp2_loc, value, class_offset, temp_loc);
-            //
-            //   __ cmpl(temp, temp2);
-            //
-            // However, the second read barrier may trash `temp`, as it
-            // is a temporary register, and as such would not be saved
-            // along with live registers before calling the runtime (nor
-            // restored afterwards).  So in this case, we bail out and
-            // delegate the work to the array set slow path.
-            //
-            // TODO: Extend the register allocator to support a new
-            // "(locally) live temp" location so as to avoid always
-            // going into the slow path when read barriers are enabled?
-            //
-            // There is no such problem with Baker read barriers (see below).
-            __ jmp(slow_path->GetEntryLabel());
-          } else {
-            Location temp2_loc = locations->GetTemp(1);
-            Register temp2 = temp2_loc.AsRegister<Register>();
-            // /* HeapReference<Class> */ temp = array->klass_
-            codegen_->GenerateFieldLoadWithBakerReadBarrier(
-                instruction, temp_loc, array, class_offset, /* needs_null_check */ true);
+        // Note that when Baker read barriers are enabled, the type
+        // checks are performed without read barriers.  This is fine,
+        // even in the case where a class object is in the from-space
+        // after the flip, as a comparison involving such a type would
+        // not produce a false positive; it may of course produce a
+        // false negative, in which case we would take the ArraySet
+        // slow path.
 
-            // /* HeapReference<Class> */ temp = temp->component_type_
-            codegen_->GenerateFieldLoadWithBakerReadBarrier(
-                instruction, temp_loc, temp, component_offset, /* needs_null_check */ false);
-            // Register `temp` is not trashed by the read barrier
-            // emitted by GenerateFieldLoadWithBakerReadBarrier below,
-            // as that method produces a call to a ReadBarrierMarkRegX
-            // entry point, which saves all potentially live registers,
-            // including temporaries such a `temp`.
-            // /* HeapReference<Class> */ temp2 = register_value->klass_
-            codegen_->GenerateFieldLoadWithBakerReadBarrier(
-                instruction, temp2_loc, register_value, class_offset, /* needs_null_check */ false);
-            // If heap poisoning is enabled, `temp` and `temp2` have
-            // been unpoisoned by the the previous calls to
-            // CodeGeneratorX86::GenerateFieldLoadWithBakerReadBarrier.
-            __ cmpl(temp, temp2);
+        // /* HeapReference<Class> */ temp = array->klass_
+        __ movl(temp, Address(array, class_offset));
+        codegen_->MaybeRecordImplicitNullCheck(instruction);
+        __ MaybeUnpoisonHeapReference(temp);
 
-            if (instruction->StaticTypeOfArrayIsObjectArray()) {
-              __ j(kEqual, &do_put);
-              // We do not need to emit a read barrier for the
-              // following heap reference load, as `temp` is only used
-              // in a comparison with null below, and this reference
-              // is not kept afterwards. Also, if heap poisoning is
-              // enabled, there is no need to unpoison that heap
-              // reference for the same reason (comparison with null).
-              __ cmpl(Address(temp, super_offset), Immediate(0));
-              __ j(kNotEqual, slow_path->GetEntryLabel());
-              __ Bind(&do_put);
-            } else {
-              __ j(kNotEqual, slow_path->GetEntryLabel());
-            }
-          }
-        } else {
-          // Non read barrier code.
+        // /* HeapReference<Class> */ temp = temp->component_type_
+        __ movl(temp, Address(temp, component_offset));
+        // If heap poisoning is enabled, no need to unpoison `temp`
+        // nor the object reference in `register_value->klass`, as
+        // we are comparing two poisoned references.
+        __ cmpl(temp, Address(register_value, class_offset));
 
-          // /* HeapReference<Class> */ temp = array->klass_
-          __ movl(temp, Address(array, class_offset));
-          codegen_->MaybeRecordImplicitNullCheck(instruction);
+        if (instruction->StaticTypeOfArrayIsObjectArray()) {
+          __ j(kEqual, &do_put);
+          // If heap poisoning is enabled, the `temp` reference has
+          // not been unpoisoned yet; unpoison it now.
           __ MaybeUnpoisonHeapReference(temp);
 
-          // /* HeapReference<Class> */ temp = temp->component_type_
-          __ movl(temp, Address(temp, component_offset));
-          // If heap poisoning is enabled, no need to unpoison `temp`
-          // nor the object reference in `register_value->klass`, as
-          // we are comparing two poisoned references.
-          __ cmpl(temp, Address(register_value, class_offset));
-
-          if (instruction->StaticTypeOfArrayIsObjectArray()) {
-            __ j(kEqual, &do_put);
-            // If heap poisoning is enabled, the `temp` reference has
-            // not been unpoisoned yet; unpoison it now.
-            __ MaybeUnpoisonHeapReference(temp);
-
-            // If heap poisoning is enabled, no need to unpoison the
-            // heap reference loaded below, as it is only used for a
-            // comparison with null.
-            __ cmpl(Address(temp, super_offset), Immediate(0));
-            __ j(kNotEqual, slow_path->GetEntryLabel());
-            __ Bind(&do_put);
-          } else {
-            __ j(kNotEqual, slow_path->GetEntryLabel());
-          }
+          // If heap poisoning is enabled, no need to unpoison the
+          // heap reference loaded below, as it is only used for a
+          // comparison with null.
+          __ cmpl(Address(temp, super_offset), Immediate(0));
+          __ j(kNotEqual, slow_path->GetEntryLabel());
+          __ Bind(&do_put);
+        } else {
+          __ j(kNotEqual, slow_path->GetEntryLabel());
         }
       }
 
@@ -5961,17 +5895,6 @@
 
 HLoadClass::LoadKind CodeGeneratorX86::GetSupportedLoadClassKind(
     HLoadClass::LoadKind desired_class_load_kind) {
-  if (kEmitCompilerReadBarrier) {
-    switch (desired_class_load_kind) {
-      case HLoadClass::LoadKind::kBootImageLinkTimeAddress:
-      case HLoadClass::LoadKind::kBootImageLinkTimePcRelative:
-      case HLoadClass::LoadKind::kBootImageAddress:
-        // TODO: Implement for read barrier.
-        return HLoadClass::LoadKind::kDexCacheViaMethod;
-      default:
-        break;
-    }
-  }
   switch (desired_class_load_kind) {
     case HLoadClass::LoadKind::kReferrersClass:
       break;
@@ -6013,11 +5936,12 @@
     return;
   }
 
-  LocationSummary::CallKind call_kind = (cls->NeedsEnvironment() || kEmitCompilerReadBarrier)
+  const bool requires_read_barrier = kEmitCompilerReadBarrier && !cls->IsInBootImage();
+  LocationSummary::CallKind call_kind = (cls->NeedsEnvironment() || requires_read_barrier)
       ? LocationSummary::kCallOnSlowPath
       : LocationSummary::kNoCall;
   LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(cls, call_kind);
-  if (kUseBakerReadBarrier && !cls->NeedsEnvironment()) {
+  if (kUseBakerReadBarrier && requires_read_barrier && !cls->NeedsEnvironment()) {
     locations->SetCustomSlowPathCallerSaves(RegisterSet());  // No caller-save registers.
   }
 
@@ -6044,6 +5968,7 @@
   Register out = out_loc.AsRegister<Register>();
 
   bool generate_null_check = false;
+  const bool requires_read_barrier = kEmitCompilerReadBarrier && !cls->IsInBootImage();
   switch (cls->GetLoadKind()) {
     case HLoadClass::LoadKind::kReferrersClass: {
       DCHECK(!cls->CanCallRuntime());
@@ -6051,24 +5976,28 @@
       // /* GcRoot<mirror::Class> */ out = current_method->declaring_class_
       Register current_method = locations->InAt(0).AsRegister<Register>();
       GenerateGcRootFieldLoad(
-          cls, out_loc, Address(current_method, ArtMethod::DeclaringClassOffset().Int32Value()));
+          cls,
+          out_loc,
+          Address(current_method, ArtMethod::DeclaringClassOffset().Int32Value()),
+          /*fixup_label*/ nullptr,
+          requires_read_barrier);
       break;
     }
     case HLoadClass::LoadKind::kBootImageLinkTimeAddress: {
-      DCHECK(!kEmitCompilerReadBarrier);
+      DCHECK(!requires_read_barrier);
       __ movl(out, Immediate(/* placeholder */ 0));
       codegen_->RecordTypePatch(cls);
       break;
     }
     case HLoadClass::LoadKind::kBootImageLinkTimePcRelative: {
-      DCHECK(!kEmitCompilerReadBarrier);
+      DCHECK(!requires_read_barrier);
       Register method_address = locations->InAt(0).AsRegister<Register>();
       __ leal(out, Address(method_address, CodeGeneratorX86::kDummy32BitOffset));
       codegen_->RecordTypePatch(cls);
       break;
     }
     case HLoadClass::LoadKind::kBootImageAddress: {
-      DCHECK(!kEmitCompilerReadBarrier);
+      DCHECK(!requires_read_barrier);
       DCHECK_NE(cls->GetAddress(), 0u);
       uint32_t address = dchecked_integral_cast<uint32_t>(cls->GetAddress());
       __ movl(out, Immediate(address));
@@ -6079,7 +6008,11 @@
       DCHECK_NE(cls->GetAddress(), 0u);
       uint32_t address = dchecked_integral_cast<uint32_t>(cls->GetAddress());
       // /* GcRoot<mirror::Class> */ out = *address
-      GenerateGcRootFieldLoad(cls, out_loc, Address::Absolute(address));
+      GenerateGcRootFieldLoad(cls,
+                              out_loc,
+                              Address::Absolute(address),
+                              /*fixup_label*/ nullptr,
+                              requires_read_barrier);
       generate_null_check = !cls->IsInDexCache();
       break;
     }
@@ -6088,8 +6021,11 @@
       uint32_t offset = cls->GetDexCacheElementOffset();
       Label* fixup_label = codegen_->NewPcRelativeDexCacheArrayPatch(cls->GetDexFile(), offset);
       // /* GcRoot<mirror::Class> */ out = *(base + offset)  /* PC-relative */
-      GenerateGcRootFieldLoad(
-          cls, out_loc, Address(base_reg, CodeGeneratorX86::kDummy32BitOffset), fixup_label);
+      GenerateGcRootFieldLoad(cls,
+                              out_loc,
+                              Address(base_reg, CodeGeneratorX86::kDummy32BitOffset),
+                              fixup_label,
+                              requires_read_barrier);
       generate_null_check = !cls->IsInDexCache();
       break;
     }
@@ -6100,8 +6036,11 @@
       __ movl(out, Address(current_method,
                            ArtMethod::DexCacheResolvedTypesOffset(kX86PointerSize).Int32Value()));
       // /* GcRoot<mirror::Class> */ out = out[type_index]
-      GenerateGcRootFieldLoad(
-          cls, out_loc, Address(out, CodeGenerator::GetCacheOffset(cls->GetTypeIndex())));
+      GenerateGcRootFieldLoad(cls,
+                              out_loc,
+                              Address(out, CodeGenerator::GetCacheOffset(cls->GetTypeIndex())),
+                              /*fixup_label*/ nullptr,
+                              requires_read_barrier);
       generate_null_check = !cls->IsInDexCache();
       break;
     }
@@ -6938,9 +6877,11 @@
 void InstructionCodeGeneratorX86::GenerateGcRootFieldLoad(HInstruction* instruction,
                                                           Location root,
                                                           const Address& address,
-                                                          Label* fixup_label) {
+                                                          Label* fixup_label,
+                                                          bool requires_read_barrier) {
   Register root_reg = root.AsRegister<Register>();
-  if (kEmitCompilerReadBarrier) {
+  if (requires_read_barrier) {
+    DCHECK(kEmitCompilerReadBarrier);
     if (kUseBakerReadBarrier) {
       // Fast path implementation of art::ReadBarrier::BarrierForRoot when
       // Baker's read barrier are used:
diff --git a/compiler/optimizing/code_generator_x86.h b/compiler/optimizing/code_generator_x86.h
index df65fa2..e225098 100644
--- a/compiler/optimizing/code_generator_x86.h
+++ b/compiler/optimizing/code_generator_x86.h
@@ -263,7 +263,8 @@
   void GenerateGcRootFieldLoad(HInstruction* instruction,
                                Location root,
                                const Address& address,
-                               Label* fixup_label = nullptr);
+                               Label* fixup_label = nullptr,
+                               bool requires_read_barrier = kEmitCompilerReadBarrier);
 
   // Push value to FPU stack. `is_fp` specifies whether the value is floating point or not.
   // `is_wide` specifies whether it is long/double or not.
diff --git a/compiler/optimizing/code_generator_x86_64.cc b/compiler/optimizing/code_generator_x86_64.cc
index a60c270..b3228f8 100644
--- a/compiler/optimizing/code_generator_x86_64.cc
+++ b/compiler/optimizing/code_generator_x86_64.cc
@@ -388,7 +388,6 @@
   void EmitNativeCode(CodeGenerator* codegen) OVERRIDE {
     CodeGeneratorX86_64* x86_64_codegen = down_cast<CodeGeneratorX86_64*>(codegen);
     __ Bind(GetEntryLabel());
-    SaveLiveRegisters(codegen, instruction_->GetLocations());
     x86_64_codegen->InvokeRuntime(kQuickDeoptimize, instruction_, instruction_->GetDexPc(), this);
     CheckEntrypointTypes<kQuickDeoptimize, void, void>();
   }
@@ -1563,6 +1562,7 @@
 void LocationsBuilderX86_64::VisitDeoptimize(HDeoptimize* deoptimize) {
   LocationSummary* locations = new (GetGraph()->GetArena())
       LocationSummary(deoptimize, LocationSummary::kCallOnSlowPath);
+  locations->SetCustomSlowPathCallerSaves(RegisterSet());  // No caller-save registers.
   if (IsBooleanValueOrMaterializedCondition(deoptimize->InputAt(0))) {
     locations->SetInAt(0, Location::Any());
   }
@@ -4732,7 +4732,6 @@
 
   if (needs_write_barrier) {
     // Temporary registers for the write barrier.
-    // These registers may be used for Baker read barriers too.
     locations->AddTemp(Location::RequiresRegister());  // Possibly used for ref. poisoning too.
     locations->AddTemp(Location::RequiresRegister());
   }
@@ -4822,105 +4821,40 @@
           __ Bind(&not_null);
         }
 
-        if (kEmitCompilerReadBarrier) {
-          if (!kUseBakerReadBarrier) {
-            // When (non-Baker) read barriers are enabled, the type
-            // checking instrumentation requires two read barriers
-            // generated by CodeGeneratorX86_64::GenerateReadBarrierSlow:
-            //
-            //   __ movl(temp2, temp);
-            //   // /* HeapReference<Class> */ temp = temp->component_type_
-            //   __ movl(temp, Address(temp, component_offset));
-            //   codegen_->GenerateReadBarrierSlow(
-            //       instruction, temp_loc, temp_loc, temp2_loc, component_offset);
-            //
-            //   // /* HeapReference<Class> */ temp2 = register_value->klass_
-            //   __ movl(temp2, Address(register_value, class_offset));
-            //   codegen_->GenerateReadBarrierSlow(
-            //       instruction, temp2_loc, temp2_loc, value, class_offset, temp_loc);
-            //
-            //   __ cmpl(temp, temp2);
-            //
-            // However, the second read barrier may trash `temp`, as it
-            // is a temporary register, and as such would not be saved
-            // along with live registers before calling the runtime (nor
-            // restored afterwards).  So in this case, we bail out and
-            // delegate the work to the array set slow path.
-            //
-            // TODO: Extend the register allocator to support a new
-            // "(locally) live temp" location so as to avoid always
-            // going into the slow path when read barriers are enabled?
-            //
-            // There is no such problem with Baker read barriers (see below).
-            __ jmp(slow_path->GetEntryLabel());
-          } else {
-            Location temp2_loc = locations->GetTemp(1);
-            CpuRegister temp2 = temp2_loc.AsRegister<CpuRegister>();
-            // /* HeapReference<Class> */ temp = array->klass_
-            codegen_->GenerateFieldLoadWithBakerReadBarrier(
-                instruction, temp_loc, array, class_offset, /* needs_null_check */ true);
+        // Note that when Baker read barriers are enabled, the type
+        // checks are performed without read barriers.  This is fine,
+        // even in the case where a class object is in the from-space
+        // after the flip, as a comparison involving such a type would
+        // not produce a false positive; it may of course produce a
+        // false negative, in which case we would take the ArraySet
+        // slow path.
 
-            // /* HeapReference<Class> */ temp = temp->component_type_
-            codegen_->GenerateFieldLoadWithBakerReadBarrier(
-                instruction, temp_loc, temp, component_offset, /* needs_null_check */ false);
-            // Register `temp` is not trashed by the read barrier
-            // emitted by GenerateFieldLoadWithBakerReadBarrier below,
-            // as that method produces a call to a ReadBarrierMarkRegX
-            // entry point, which saves all potentially live registers,
-            // including temporaries such a `temp`.
-            // /* HeapReference<Class> */ temp2 = register_value->klass_
-            codegen_->GenerateFieldLoadWithBakerReadBarrier(
-                instruction, temp2_loc, register_value, class_offset, /* needs_null_check */ false);
-            // If heap poisoning is enabled, `temp` and `temp2` have
-            // been unpoisoned by the the previous calls to
-            // CodeGeneratorX86_64::GenerateFieldLoadWithBakerReadBarrier.
-            __ cmpl(temp, temp2);
+        // /* HeapReference<Class> */ temp = array->klass_
+        __ movl(temp, Address(array, class_offset));
+        codegen_->MaybeRecordImplicitNullCheck(instruction);
+        __ MaybeUnpoisonHeapReference(temp);
 
-            if (instruction->StaticTypeOfArrayIsObjectArray()) {
-              __ j(kEqual, &do_put);
-              // We do not need to emit a read barrier for the
-              // following heap reference load, as `temp` is only used
-              // in a comparison with null below, and this reference
-              // is not kept afterwards. Also, if heap poisoning is
-              // enabled, there is no need to unpoison that heap
-              // reference for the same reason (comparison with null).
-              __ cmpl(Address(temp, super_offset), Immediate(0));
-              __ j(kNotEqual, slow_path->GetEntryLabel());
-              __ Bind(&do_put);
-            } else {
-              __ j(kNotEqual, slow_path->GetEntryLabel());
-            }
-          }
-        } else {
-          // Non read barrier code.
+        // /* HeapReference<Class> */ temp = temp->component_type_
+        __ movl(temp, Address(temp, component_offset));
+        // If heap poisoning is enabled, no need to unpoison `temp`
+        // nor the object reference in `register_value->klass`, as
+        // we are comparing two poisoned references.
+        __ cmpl(temp, Address(register_value, class_offset));
 
-          // /* HeapReference<Class> */ temp = array->klass_
-          __ movl(temp, Address(array, class_offset));
-          codegen_->MaybeRecordImplicitNullCheck(instruction);
+        if (instruction->StaticTypeOfArrayIsObjectArray()) {
+          __ j(kEqual, &do_put);
+          // If heap poisoning is enabled, the `temp` reference has
+          // not been unpoisoned yet; unpoison it now.
           __ MaybeUnpoisonHeapReference(temp);
 
-          // /* HeapReference<Class> */ temp = temp->component_type_
-          __ movl(temp, Address(temp, component_offset));
-          // If heap poisoning is enabled, no need to unpoison `temp`
-          // nor the object reference in `register_value->klass`, as
-          // we are comparing two poisoned references.
-          __ cmpl(temp, Address(register_value, class_offset));
-
-          if (instruction->StaticTypeOfArrayIsObjectArray()) {
-            __ j(kEqual, &do_put);
-            // If heap poisoning is enabled, the `temp` reference has
-            // not been unpoisoned yet; unpoison it now.
-            __ MaybeUnpoisonHeapReference(temp);
-
-            // If heap poisoning is enabled, no need to unpoison the
-            // heap reference loaded below, as it is only used for a
-            // comparison with null.
-            __ cmpl(Address(temp, super_offset), Immediate(0));
-            __ j(kNotEqual, slow_path->GetEntryLabel());
-            __ Bind(&do_put);
-          } else {
-            __ j(kNotEqual, slow_path->GetEntryLabel());
-          }
+          // If heap poisoning is enabled, no need to unpoison the
+          // heap reference loaded below, as it is only used for a
+          // comparison with null.
+          __ cmpl(Address(temp, super_offset), Immediate(0));
+          __ j(kNotEqual, slow_path->GetEntryLabel());
+          __ Bind(&do_put);
+        } else {
+          __ j(kNotEqual, slow_path->GetEntryLabel());
         }
       }
 
@@ -5408,17 +5342,6 @@
 
 HLoadClass::LoadKind CodeGeneratorX86_64::GetSupportedLoadClassKind(
     HLoadClass::LoadKind desired_class_load_kind) {
-  if (kEmitCompilerReadBarrier) {
-    switch (desired_class_load_kind) {
-      case HLoadClass::LoadKind::kBootImageLinkTimeAddress:
-      case HLoadClass::LoadKind::kBootImageLinkTimePcRelative:
-      case HLoadClass::LoadKind::kBootImageAddress:
-        // TODO: Implement for read barrier.
-        return HLoadClass::LoadKind::kDexCacheViaMethod;
-      default:
-        break;
-    }
-  }
   switch (desired_class_load_kind) {
     case HLoadClass::LoadKind::kReferrersClass:
       break;
@@ -5454,11 +5377,12 @@
     return;
   }
 
-  LocationSummary::CallKind call_kind = (cls->NeedsEnvironment() || kEmitCompilerReadBarrier)
+  const bool requires_read_barrier = kEmitCompilerReadBarrier && !cls->IsInBootImage();
+  LocationSummary::CallKind call_kind = (cls->NeedsEnvironment() || requires_read_barrier)
       ? LocationSummary::kCallOnSlowPath
       : LocationSummary::kNoCall;
   LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(cls, call_kind);
-  if (kUseBakerReadBarrier && !cls->NeedsEnvironment()) {
+  if (kUseBakerReadBarrier && requires_read_barrier && !cls->NeedsEnvironment()) {
     locations->SetCustomSlowPathCallerSaves(RegisterSet());  // No caller-save registers.
   }
 
@@ -5482,6 +5406,7 @@
   Location out_loc = locations->Out();
   CpuRegister out = out_loc.AsRegister<CpuRegister>();
 
+  const bool requires_read_barrier = kEmitCompilerReadBarrier && !cls->IsInBootImage();
   bool generate_null_check = false;
   switch (cls->GetLoadKind()) {
     case HLoadClass::LoadKind::kReferrersClass: {
@@ -5490,16 +5415,20 @@
       // /* GcRoot<mirror::Class> */ out = current_method->declaring_class_
       CpuRegister current_method = locations->InAt(0).AsRegister<CpuRegister>();
       GenerateGcRootFieldLoad(
-          cls, out_loc, Address(current_method, ArtMethod::DeclaringClassOffset().Int32Value()));
+          cls,
+          out_loc,
+          Address(current_method, ArtMethod::DeclaringClassOffset().Int32Value()),
+          /*fixup_label*/nullptr,
+          requires_read_barrier);
       break;
     }
     case HLoadClass::LoadKind::kBootImageLinkTimePcRelative:
-      DCHECK(!kEmitCompilerReadBarrier);
+      DCHECK(!requires_read_barrier);
       __ leal(out, Address::Absolute(CodeGeneratorX86_64::kDummy32BitOffset, /* no_rip */ false));
       codegen_->RecordTypePatch(cls);
       break;
     case HLoadClass::LoadKind::kBootImageAddress: {
-      DCHECK(!kEmitCompilerReadBarrier);
+      DCHECK(!requires_read_barrier);
       DCHECK_NE(cls->GetAddress(), 0u);
       uint32_t address = dchecked_integral_cast<uint32_t>(cls->GetAddress());
       __ movl(out, Immediate(address));  // Zero-extended.
@@ -5511,11 +5440,19 @@
       // /* GcRoot<mirror::Class> */ out = *address
       if (IsUint<32>(cls->GetAddress())) {
         Address address = Address::Absolute(cls->GetAddress(), /* no_rip */ true);
-        GenerateGcRootFieldLoad(cls, out_loc, address);
+        GenerateGcRootFieldLoad(cls,
+                                out_loc,
+                                address,
+                                /*fixup_label*/nullptr,
+                                requires_read_barrier);
       } else {
         // TODO: Consider using opcode A1, i.e. movl eax, moff32 (with 64-bit address).
         __ movq(out, Immediate(cls->GetAddress()));
-        GenerateGcRootFieldLoad(cls, out_loc, Address(out, 0));
+        GenerateGcRootFieldLoad(cls,
+                                out_loc,
+                                Address(out, 0),
+                                /*fixup_label*/nullptr,
+                                requires_read_barrier);
       }
       generate_null_check = !cls->IsInDexCache();
       break;
@@ -5526,7 +5463,7 @@
       Address address = Address::Absolute(CodeGeneratorX86_64::kDummy32BitOffset,
                                           /* no_rip */ false);
       // /* GcRoot<mirror::Class> */ out = *address  /* PC-relative */
-      GenerateGcRootFieldLoad(cls, out_loc, address, fixup_label);
+      GenerateGcRootFieldLoad(cls, out_loc, address, fixup_label, requires_read_barrier);
       generate_null_check = !cls->IsInDexCache();
       break;
     }
@@ -5539,7 +5476,11 @@
                       ArtMethod::DexCacheResolvedTypesOffset(kX86_64PointerSize).Int32Value()));
       // /* GcRoot<mirror::Class> */ out = out[type_index]
       GenerateGcRootFieldLoad(
-          cls, out_loc, Address(out, CodeGenerator::GetCacheOffset(cls->GetTypeIndex())));
+          cls,
+          out_loc,
+          Address(out, CodeGenerator::GetCacheOffset(cls->GetTypeIndex())),
+          /*fixup_label*/nullptr,
+          requires_read_barrier);
       generate_null_check = !cls->IsInDexCache();
       break;
     }
@@ -6387,9 +6328,11 @@
 void InstructionCodeGeneratorX86_64::GenerateGcRootFieldLoad(HInstruction* instruction,
                                                              Location root,
                                                              const Address& address,
-                                                             Label* fixup_label) {
+                                                             Label* fixup_label,
+                                                             bool requires_read_barrier) {
   CpuRegister root_reg = root.AsRegister<CpuRegister>();
-  if (kEmitCompilerReadBarrier) {
+  if (requires_read_barrier) {
+    DCHECK(kEmitCompilerReadBarrier);
     if (kUseBakerReadBarrier) {
       // Fast path implementation of art::ReadBarrier::BarrierForRoot when
       // Baker's read barrier are used:
diff --git a/compiler/optimizing/code_generator_x86_64.h b/compiler/optimizing/code_generator_x86_64.h
index f23bff5..d939083 100644
--- a/compiler/optimizing/code_generator_x86_64.h
+++ b/compiler/optimizing/code_generator_x86_64.h
@@ -257,7 +257,8 @@
   void GenerateGcRootFieldLoad(HInstruction* instruction,
                                Location root,
                                const Address& address,
-                               Label* fixup_label = nullptr);
+                               Label* fixup_label = nullptr,
+                               bool requires_read_barrier = kEmitCompilerReadBarrier);
 
   void PushOntoFPStack(Location source, uint32_t temp_offset,
                        uint32_t stack_adjustment, bool is_float);
diff --git a/compiler/optimizing/inliner.cc b/compiler/optimizing/inliner.cc
index 1e5f0b6..ce53134 100644
--- a/compiler/optimizing/inliner.cc
+++ b/compiler/optimizing/inliner.cc
@@ -452,7 +452,8 @@
                                                                is_referrer,
                                                                invoke_instruction->GetDexPc(),
                                                                /* needs_access_check */ false,
-                                                               /* is_in_dex_cache */ true);
+                                                               /* is_in_dex_cache */ true,
+                                                               /* is_in_boot_image */ false);
 
   HNotEqual* compare = new (graph_->GetArena()) HNotEqual(load_class, receiver_class);
   // TODO: Extend reference type propagation to understand the guard.
diff --git a/compiler/optimizing/instruction_builder.cc b/compiler/optimizing/instruction_builder.cc
index 453068b..d7e4c53 100644
--- a/compiler/optimizing/instruction_builder.cc
+++ b/compiler/optimizing/instruction_builder.cc
@@ -935,7 +935,8 @@
       IsOutermostCompilingClass(type_index),
       dex_pc,
       needs_access_check,
-      /* is_in_dex_cache */ false);
+      /* is_in_dex_cache */ false,
+      /* is_in_boot_image */ false);
 
   AppendInstruction(load_class);
   HInstruction* cls = load_class;
@@ -1026,7 +1027,8 @@
         is_outer_class,
         dex_pc,
         /*needs_access_check*/ false,
-        /* is_in_dex_cache */ false);
+        /* is_in_dex_cache */ false,
+        /* is_in_boot_image */ false);
     AppendInstruction(load_class);
     clinit_check = new (arena_) HClinitCheck(load_class, dex_pc);
     AppendInstruction(clinit_check);
@@ -1384,7 +1386,8 @@
                                                  is_outer_class,
                                                  dex_pc,
                                                  /*needs_access_check*/ false,
-                                                 /* is_in_dex_cache */ false);
+                                                 /* is_in_dex_cache */ false,
+                                                 /* is_in_boot_image */ false);
   AppendInstruction(constant);
 
   HInstruction* cls = constant;
@@ -1545,8 +1548,6 @@
 
 void HInstructionBuilder::BuildFillArrayData(const Instruction& instruction, uint32_t dex_pc) {
   HInstruction* array = LoadNullCheckedLocal(instruction.VRegA_31t(), dex_pc);
-  HInstruction* length = new (arena_) HArrayLength(array, dex_pc);
-  AppendInstruction(length);
 
   int32_t payload_offset = instruction.VRegB_31t() + dex_pc;
   const Instruction::ArrayDataPayload* payload =
@@ -1554,6 +1555,14 @@
   const uint8_t* data = payload->data;
   uint32_t element_count = payload->element_count;
 
+  if (element_count == 0u) {
+    // For empty payload we emit only the null check above.
+    return;
+  }
+
+  HInstruction* length = new (arena_) HArrayLength(array, dex_pc);
+  AppendInstruction(length);
+
   // Implementation of this DEX instruction seems to be that the bounds check is
   // done before doing any stores.
   HInstruction* last_index = graph_->GetIntConstant(payload->element_count - 1, dex_pc);
@@ -1653,7 +1662,8 @@
       IsOutermostCompilingClass(type_index),
       dex_pc,
       !can_access,
-      /* is_in_dex_cache */ false);
+      /* is_in_dex_cache */ false,
+      /* is_in_boot_image */ false);
   AppendInstruction(cls);
 
   TypeCheckKind check_kind = ComputeTypeCheckKind(resolved_class);
@@ -2628,7 +2638,8 @@
           IsOutermostCompilingClass(type_index),
           dex_pc,
           !can_access,
-          /* is_in_dex_cache */ false));
+          /* is_in_dex_cache */ false,
+          /* is_in_boot_image */ false));
       UpdateLocal(instruction.VRegA_21c(), current_block_->GetLastInstruction());
       break;
     }
diff --git a/compiler/optimizing/nodes.h b/compiler/optimizing/nodes.h
index 19e499b..149a71d 100644
--- a/compiler/optimizing/nodes.h
+++ b/compiler/optimizing/nodes.h
@@ -5461,7 +5461,8 @@
              bool is_referrers_class,
              uint32_t dex_pc,
              bool needs_access_check,
-             bool is_in_dex_cache)
+             bool is_in_dex_cache,
+             bool is_in_boot_image)
       : HInstruction(SideEffectsForArchRuntimeCalls(), dex_pc),
         special_input_(HUserRecord<HInstruction*>(current_method)),
         type_index_(type_index),
@@ -5475,6 +5476,7 @@
         is_referrers_class ? LoadKind::kReferrersClass : LoadKind::kDexCacheViaMethod);
     SetPackedFlag<kFlagNeedsAccessCheck>(needs_access_check);
     SetPackedFlag<kFlagIsInDexCache>(is_in_dex_cache);
+    SetPackedFlag<kFlagIsInBootImage>(is_in_boot_image);
     SetPackedFlag<kFlagGenerateClInitCheck>(false);
   }
 
@@ -5565,6 +5567,7 @@
   bool IsReferrersClass() const { return GetLoadKind() == LoadKind::kReferrersClass; }
   bool NeedsAccessCheck() const { return GetPackedFlag<kFlagNeedsAccessCheck>(); }
   bool IsInDexCache() const { return GetPackedFlag<kFlagIsInDexCache>(); }
+  bool IsInBootImage() const { return GetPackedFlag<kFlagIsInBootImage>(); }
   bool MustGenerateClinitCheck() const { return GetPackedFlag<kFlagGenerateClInitCheck>(); }
 
   void MarkInDexCache() {
@@ -5574,6 +5577,10 @@
     SetSideEffects(SideEffects::None());
   }
 
+  void MarkInBootImage() {
+    SetPackedFlag<kFlagIsInBootImage>(true);
+  }
+
   void AddSpecialInput(HInstruction* special_input);
 
   using HInstruction::GetInputRecords;  // Keep the const version visible.
@@ -5591,9 +5598,10 @@
  private:
   static constexpr size_t kFlagNeedsAccessCheck    = kNumberOfGenericPackedBits;
   static constexpr size_t kFlagIsInDexCache        = kFlagNeedsAccessCheck + 1;
+  static constexpr size_t kFlagIsInBootImage       = kFlagIsInDexCache + 1;
   // Whether this instruction must generate the initialization check.
   // Used for code generation.
-  static constexpr size_t kFlagGenerateClInitCheck = kFlagIsInDexCache + 1;
+  static constexpr size_t kFlagGenerateClInitCheck = kFlagIsInBootImage + 1;
   static constexpr size_t kFieldLoadKind           = kFlagGenerateClInitCheck + 1;
   static constexpr size_t kFieldLoadKindSize =
       MinimumBitsToStore(static_cast<size_t>(LoadKind::kLast));
diff --git a/compiler/optimizing/sharpening.cc b/compiler/optimizing/sharpening.cc
index 81163e2..b8e1379 100644
--- a/compiler/optimizing/sharpening.cc
+++ b/compiler/optimizing/sharpening.cc
@@ -176,6 +176,7 @@
   uint32_t type_index = load_class->GetTypeIndex();
 
   bool is_in_dex_cache = false;
+  bool is_in_boot_image = false;
   HLoadClass::LoadKind desired_load_kind;
   uint64_t address = 0u;  // Class or dex cache element address.
   {
@@ -192,45 +193,42 @@
       // Compiling boot image. Check if the class is a boot image class.
       DCHECK(!runtime->UseJitCompilation());
       if (!compiler_driver_->GetSupportBootImageFixup()) {
-        // MIPS/MIPS64 or compiler_driver_test. Do not sharpen.
+        // MIPS64 or compiler_driver_test. Do not sharpen.
         desired_load_kind = HLoadClass::LoadKind::kDexCacheViaMethod;
+      } else if ((klass != nullptr) && compiler_driver_->IsImageClass(
+          dex_file.StringDataByIdx(dex_file.GetTypeId(type_index).descriptor_idx_))) {
+        is_in_boot_image = true;
+        is_in_dex_cache = true;
+        desired_load_kind = codegen_->GetCompilerOptions().GetCompilePic()
+            ? HLoadClass::LoadKind::kBootImageLinkTimePcRelative
+            : HLoadClass::LoadKind::kBootImageLinkTimeAddress;
       } else {
-        if (klass != nullptr &&
-            compiler_driver_->IsImageClass(
-                dex_file.StringDataByIdx(dex_file.GetTypeId(type_index).descriptor_idx_))) {
-          is_in_dex_cache = true;
-          desired_load_kind = codegen_->GetCompilerOptions().GetCompilePic()
-              ? HLoadClass::LoadKind::kBootImageLinkTimePcRelative
-              : HLoadClass::LoadKind::kBootImageLinkTimeAddress;
-        } else {
-          // Not a boot image class. We must go through the dex cache.
-          DCHECK(ContainsElement(compiler_driver_->GetDexFilesForOatFile(), &dex_file));
-          desired_load_kind = HLoadClass::LoadKind::kDexCachePcRelative;
-        }
-      }
-    } else if (runtime->UseJitCompilation()) {
-      // TODO: Make sure we don't set the "compile PIC" flag for JIT as that's bogus.
-      // DCHECK(!codegen_->GetCompilerOptions().GetCompilePic());
-      is_in_dex_cache = (klass != nullptr);
-      if (klass != nullptr && runtime->GetHeap()->ObjectIsInBootImageSpace(klass)) {
-        // TODO: Use direct pointers for all non-moving spaces, not just boot image. Bug: 29530787
-        desired_load_kind = HLoadClass::LoadKind::kBootImageAddress;
-        address = reinterpret_cast64<uint64_t>(klass);
-      } else {
-        // Note: If the class is not in the dex cache or isn't initialized, the
-        // instruction needs environment and will not be inlined across dex files.
-        // Within a dex file, the slow-path helper loads the correct class and
-        // inlined frames are used correctly for OOM stack trace.
-        // TODO: Write a test for this. Bug: 29416588
-        desired_load_kind = HLoadClass::LoadKind::kDexCacheAddress;
-        void* dex_cache_element_address = &dex_cache->GetResolvedTypes()[type_index];
-        address = reinterpret_cast64<uint64_t>(dex_cache_element_address);
+        // Not a boot image class. We must go through the dex cache.
+        DCHECK(ContainsElement(compiler_driver_->GetDexFilesForOatFile(), &dex_file));
+        desired_load_kind = HLoadClass::LoadKind::kDexCachePcRelative;
       }
     } else {
-      // AOT app compilation. Check if the class is in the boot image.
-      if ((klass != nullptr) &&
-          runtime->GetHeap()->ObjectIsInBootImageSpace(klass) &&
-          !codegen_->GetCompilerOptions().GetCompilePic()) {
+      is_in_boot_image = (klass != nullptr) && runtime->GetHeap()->ObjectIsInBootImageSpace(klass);
+      if (runtime->UseJitCompilation()) {
+        // TODO: Make sure we don't set the "compile PIC" flag for JIT as that's bogus.
+        // DCHECK(!codegen_->GetCompilerOptions().GetCompilePic());
+        is_in_dex_cache = (klass != nullptr);
+        if (is_in_boot_image) {
+          // TODO: Use direct pointers for all non-moving spaces, not just boot image. Bug: 29530787
+          desired_load_kind = HLoadClass::LoadKind::kBootImageAddress;
+          address = reinterpret_cast64<uint64_t>(klass);
+        } else {
+          // Note: If the class is not in the dex cache or isn't initialized, the
+          // instruction needs environment and will not be inlined across dex files.
+          // Within a dex file, the slow-path helper loads the correct class and
+          // inlined frames are used correctly for OOM stack trace.
+          // TODO: Write a test for this. Bug: 29416588
+          desired_load_kind = HLoadClass::LoadKind::kDexCacheAddress;
+          void* dex_cache_element_address = &dex_cache->GetResolvedTypes()[type_index];
+          address = reinterpret_cast64<uint64_t>(dex_cache_element_address);
+        }
+        // AOT app compilation. Check if the class is in the boot image.
+      } else if (is_in_boot_image && !codegen_->GetCompilerOptions().GetCompilePic()) {
         desired_load_kind = HLoadClass::LoadKind::kBootImageAddress;
         address = reinterpret_cast64<uint64_t>(klass);
       } else {
@@ -247,6 +245,9 @@
   if (is_in_dex_cache) {
     load_class->MarkInDexCache();
   }
+  if (is_in_boot_image) {
+    load_class->MarkInBootImage();
+  }
 
   HLoadClass::LoadKind load_kind = codegen_->GetSupportedLoadClassKind(desired_load_kind);
   switch (load_kind) {
@@ -296,7 +297,15 @@
       DCHECK(!runtime->UseJitCompilation());
       mirror::String* string = class_linker->ResolveString(dex_file, string_index, dex_cache);
       CHECK(string != nullptr);
-      // TODO: In follow up CL, add PcRelative and Address back in.
+      if (compiler_driver_->GetSupportBootImageFixup()) {
+        DCHECK(ContainsElement(compiler_driver_->GetDexFilesForOatFile(), &dex_file));
+        desired_load_kind = codegen_->GetCompilerOptions().GetCompilePic()
+            ? HLoadString::LoadKind::kBootImageLinkTimePcRelative
+            : HLoadString::LoadKind::kBootImageLinkTimeAddress;
+      } else {
+        // MIPS64 or compiler_driver_test. Do not sharpen.
+        DCHECK_EQ(desired_load_kind, HLoadString::LoadKind::kDexCacheViaMethod);
+      }
     } else if (runtime->UseJitCompilation()) {
       // TODO: Make sure we don't set the "compile PIC" flag for JIT as that's bogus.
       // DCHECK(!codegen_->GetCompilerOptions().GetCompilePic());
diff --git a/compiler/utils/arm/jni_macro_assembler_arm_vixl.cc b/compiler/utils/arm/jni_macro_assembler_arm_vixl.cc
index 719fe7f..a03dd74 100644
--- a/compiler/utils/arm/jni_macro_assembler_arm_vixl.cc
+++ b/compiler/utils/arm/jni_macro_assembler_arm_vixl.cc
@@ -73,12 +73,11 @@
   cfi().RelOffsetForMany(DWARFReg(r0), 0, core_spill_mask, kFramePointerSize);
   if (fp_spill_mask != 0) {
     uint32_t first = CTZ(fp_spill_mask);
-    uint32_t last  = first + POPCOUNT(fp_spill_mask) - 1;
 
     // Check that list is contiguous.
     DCHECK_EQ(fp_spill_mask >> CTZ(fp_spill_mask), ~0u >> (32 - POPCOUNT(fp_spill_mask)));
 
-    ___ Vpush(SRegisterList(vixl32::SRegister(first), vixl32::SRegister(last)));
+    ___ Vpush(SRegisterList(vixl32::SRegister(first), POPCOUNT(fp_spill_mask)));
     cfi().AdjustCFAOffset(POPCOUNT(fp_spill_mask) * kFramePointerSize);
     cfi().RelOffsetForMany(DWARFReg(s0), 0, fp_spill_mask, kFramePointerSize);
   }
@@ -136,11 +135,10 @@
 
   if (fp_spill_mask != 0) {
     uint32_t first = CTZ(fp_spill_mask);
-    uint32_t last  = first + POPCOUNT(fp_spill_mask) - 1;
     // Check that list is contiguous.
      DCHECK_EQ(fp_spill_mask >> CTZ(fp_spill_mask), ~0u >> (32 - POPCOUNT(fp_spill_mask)));
 
-    ___ Vpop(SRegisterList(vixl32::SRegister(first), vixl32::SRegister(last)));
+    ___ Vpop(SRegisterList(vixl32::SRegister(first), POPCOUNT(fp_spill_mask)));
     cfi().AdjustCFAOffset(-kFramePointerSize * POPCOUNT(fp_spill_mask));
     cfi().RestoreMany(DWARFReg(s0), fp_spill_mask);
   }
diff --git a/compiler/utils/x86/assembler_x86.cc b/compiler/utils/x86/assembler_x86.cc
index f2ef41f..cd30872 100644
--- a/compiler/utils/x86/assembler_x86.cc
+++ b/compiler/utils/x86/assembler_x86.cc
@@ -1708,6 +1708,13 @@
 }
 
 
+void X86Assembler::repne_scasb() {
+  AssemblerBuffer::EnsureCapacity ensured(&buffer_);
+  EmitUint8(0xF2);
+  EmitUint8(0xAE);
+}
+
+
 void X86Assembler::repne_scasw() {
   AssemblerBuffer::EnsureCapacity ensured(&buffer_);
   EmitUint8(0x66);
@@ -1716,6 +1723,13 @@
 }
 
 
+void X86Assembler::repe_cmpsb() {
+  AssemblerBuffer::EnsureCapacity ensured(&buffer_);
+  EmitUint8(0xF2);
+  EmitUint8(0xA6);
+}
+
+
 void X86Assembler::repe_cmpsw() {
   AssemblerBuffer::EnsureCapacity ensured(&buffer_);
   EmitUint8(0x66);
@@ -1731,6 +1745,13 @@
 }
 
 
+void X86Assembler::rep_movsb() {
+  AssemblerBuffer::EnsureCapacity ensured(&buffer_);
+  EmitUint8(0xF3);
+  EmitUint8(0xA4);
+}
+
+
 void X86Assembler::rep_movsw() {
   AssemblerBuffer::EnsureCapacity ensured(&buffer_);
   EmitUint8(0x66);
diff --git a/compiler/utils/x86/assembler_x86.h b/compiler/utils/x86/assembler_x86.h
index 2ddcd76..9738784 100644
--- a/compiler/utils/x86/assembler_x86.h
+++ b/compiler/utils/x86/assembler_x86.h
@@ -592,9 +592,12 @@
   void jmp(Label* label);
   void jmp(NearLabel* label);
 
+  void repne_scasb();
   void repne_scasw();
+  void repe_cmpsb();
   void repe_cmpsw();
   void repe_cmpsl();
+  void rep_movsb();
   void rep_movsw();
 
   X86Assembler* lock();
diff --git a/compiler/utils/x86/assembler_x86_test.cc b/compiler/utils/x86/assembler_x86_test.cc
index 61d70d7..9bae6c2 100644
--- a/compiler/utils/x86/assembler_x86_test.cc
+++ b/compiler/utils/x86/assembler_x86_test.cc
@@ -207,12 +207,24 @@
   DriverStr(expected, "FPUIntegerStore");
 }
 
+TEST_F(AssemblerX86Test, Repnescasb) {
+  GetAssembler()->repne_scasb();
+  const char* expected = "repne scasb\n";
+  DriverStr(expected, "Repnescasb");
+}
+
 TEST_F(AssemblerX86Test, Repnescasw) {
   GetAssembler()->repne_scasw();
   const char* expected = "repne scasw\n";
   DriverStr(expected, "Repnescasw");
 }
 
+TEST_F(AssemblerX86Test, Repecmpsb) {
+  GetAssembler()->repe_cmpsb();
+  const char* expected = "repe cmpsb\n";
+  DriverStr(expected, "Repecmpsb");
+}
+
 TEST_F(AssemblerX86Test, Repecmpsw) {
   GetAssembler()->repe_cmpsw();
   const char* expected = "repe cmpsw\n";
@@ -225,10 +237,10 @@
   DriverStr(expected, "Repecmpsl");
 }
 
-TEST_F(AssemblerX86Test, RepneScasw) {
-  GetAssembler()->repne_scasw();
-  const char* expected = "repne scasw\n";
-  DriverStr(expected, "repne_scasw");
+TEST_F(AssemblerX86Test, RepMovsb) {
+  GetAssembler()->rep_movsb();
+  const char* expected = "rep movsb\n";
+  DriverStr(expected, "rep_movsb");
 }
 
 TEST_F(AssemblerX86Test, RepMovsw) {
diff --git a/compiler/utils/x86_64/assembler_x86_64.cc b/compiler/utils/x86_64/assembler_x86_64.cc
index 1f73aa7..e9a0607 100644
--- a/compiler/utils/x86_64/assembler_x86_64.cc
+++ b/compiler/utils/x86_64/assembler_x86_64.cc
@@ -2325,6 +2325,12 @@
   EmitOperand(dst.LowBits(), src);
 }
 
+void X86_64Assembler::repne_scasb() {
+  AssemblerBuffer::EnsureCapacity ensured(&buffer_);
+  EmitUint8(0xF2);
+  EmitUint8(0xAE);
+}
+
 void X86_64Assembler::repne_scasw() {
   AssemblerBuffer::EnsureCapacity ensured(&buffer_);
   EmitUint8(0x66);
@@ -2332,7 +2338,6 @@
   EmitUint8(0xAF);
 }
 
-
 void X86_64Assembler::repe_cmpsw() {
   AssemblerBuffer::EnsureCapacity ensured(&buffer_);
   EmitUint8(0x66);
diff --git a/compiler/utils/x86_64/assembler_x86_64.h b/compiler/utils/x86_64/assembler_x86_64.h
index 3a4bfca..fdd3aa9 100644
--- a/compiler/utils/x86_64/assembler_x86_64.h
+++ b/compiler/utils/x86_64/assembler_x86_64.h
@@ -670,6 +670,7 @@
   void rolq(CpuRegister reg, const Immediate& imm);
   void rolq(CpuRegister operand, CpuRegister shifter);
 
+  void repne_scasb();
   void repne_scasw();
   void repe_cmpsw();
   void repe_cmpsl();
diff --git a/compiler/utils/x86_64/assembler_x86_64_test.cc b/compiler/utils/x86_64/assembler_x86_64_test.cc
index 48a1876..ff01429 100644
--- a/compiler/utils/x86_64/assembler_x86_64_test.cc
+++ b/compiler/utils/x86_64/assembler_x86_64_test.cc
@@ -956,6 +956,12 @@
   DriverStr(expected, "xorq");
 }
 
+TEST_F(AssemblerX86_64Test, RepneScasb) {
+  GetAssembler()->repne_scasb();
+  const char* expected = "repne scasb\n";
+  DriverStr(expected, "repne_scasb");
+}
+
 TEST_F(AssemblerX86_64Test, RepneScasw) {
   GetAssembler()->repne_scasw();
   const char* expected = "repne scasw\n";
diff --git a/dalvikvm/Android.bp b/dalvikvm/Android.bp
new file mode 100644
index 0000000..ab645bb
--- /dev/null
+++ b/dalvikvm/Android.bp
@@ -0,0 +1,63 @@
+//
+// Copyright (C) 2013 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_binary {
+    name: "dalvikvm",
+    host_supported: true,
+    compile_multilib: "both",
+
+    srcs: ["dalvikvm.cc"],
+    cflags: [
+        "-Wall",
+        "-Werror",
+        "-Wextra",
+    ],
+    include_dirs: ["art/runtime"],
+    shared_libs: [
+        "libnativehelper",
+    ],
+    whole_static_libs: ["libsigchain"],
+    target: {
+        host: {
+            host_ldlibs: [
+                "-ldl",
+                "-lpthread",
+            ],
+        },
+        android: {
+            shared_libs: [
+                "libdl",
+                "liblog",
+            ],
+            ldflags: ["-Wl,--export-dynamic"],
+        },
+        linux: {
+            ldflags: ["-Wl,--export-dynamic"],
+        },
+    },
+
+    multilib: {
+        lib32: {
+            suffix: "32",
+        },
+        lib64: {
+            suffix: "64",
+        },
+    },
+
+    // Create symlink for the primary version target.
+    symlink_preferred_arch: true,
+}
diff --git a/dalvikvm/Android.mk b/dalvikvm/Android.mk
deleted file mode 100644
index 6c0bcb1..0000000
--- a/dalvikvm/Android.mk
+++ /dev/null
@@ -1,87 +0,0 @@
-#
-# Copyright (C) 2013 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.common.mk
-
-dalvikvm_cflags := -Wall -Werror -Wextra
-
-include $(CLEAR_VARS)
-LOCAL_MODULE := dalvikvm
-LOCAL_MODULE_TAGS := optional
-LOCAL_CPP_EXTENSION := cc
-LOCAL_SRC_FILES := dalvikvm.cc
-LOCAL_CFLAGS := $(dalvikvm_cflags)
-LOCAL_C_INCLUDES := art/runtime
-LOCAL_SHARED_LIBRARIES := libdl liblog libnativehelper
-LOCAL_WHOLE_STATIC_LIBRARIES := libsigchain
-LOCAL_LDFLAGS := -Wl,--export-dynamic
-LOCAL_ADDITIONAL_DEPENDENCIES := $(LOCAL_PATH)/Android.mk
-LOCAL_ADDITIONAL_DEPENDENCIES += art/build/Android.common.mk
-LOCAL_MULTILIB := both
-LOCAL_MODULE_STEM_32 := dalvikvm32
-LOCAL_MODULE_STEM_64 := dalvikvm64
-LOCAL_NATIVE_COVERAGE := $(ART_COVERAGE)
-include $(BUILD_EXECUTABLE)
-
-# Create symlink for the primary version target.
-include  $(BUILD_SYSTEM)/executable_prefer_symlink.mk
-
-ART_TARGET_EXECUTABLES += $(TARGET_OUT_EXECUTABLES)/$(LOCAL_MODULE)
-ART_TARGET_EXECUTABLES += $(TARGET_OUT_EXECUTABLES)/$(LOCAL_MODULE)$(ART_PHONY_TEST_TARGET_SUFFIX)
-ifdef 2ND_ART_PHONY_TEST_TARGET_SUFFIX
-  ART_TARGET_EXECUTABLES += $(TARGET_OUT_EXECUTABLES)/$(LOCAL_MODULE)$(2ND_ART_PHONY_TEST_TARGET_SUFFIX)
-endif
-
-include $(CLEAR_VARS)
-LOCAL_MODULE := dalvikvm
-LOCAL_MODULE_TAGS := optional
-LOCAL_CLANG := true
-LOCAL_CPP_EXTENSION := cc
-LOCAL_SRC_FILES := dalvikvm.cc
-LOCAL_CFLAGS := $(dalvikvm_cflags)
-LOCAL_C_INCLUDES := art/runtime
-LOCAL_SHARED_LIBRARIES := libnativehelper
-LOCAL_WHOLE_STATIC_LIBRARIES := libsigchain
-LOCAL_LDFLAGS := -ldl -lpthread
-# Mac OS linker doesn't understand --export-dynamic.
-ifneq ($(HOST_OS),darwin)
-  LOCAL_LDFLAGS += -Wl,--export-dynamic
-endif
-LOCAL_ADDITIONAL_DEPENDENCIES += $(LOCAL_PATH)/Android.mk
-LOCAL_ADDITIONAL_DEPENDENCIES += art/build/Android.common.mk
-LOCAL_IS_HOST_MODULE := true
-LOCAL_MULTILIB := both
-ifdef ART_MULTILIB_OVERRIDE_host
-  LOCAL_MULTILIB := $(ART_MULTILIB_OVERRIDE_host)
-endif
-ifeq ($(LOCAL_MULTILIB),both)
-LOCAL_MODULE_STEM_32 := dalvikvm32
-LOCAL_MODULE_STEM_64 := dalvikvm64
-endif
-LOCAL_NATIVE_COVERAGE := $(ART_COVERAGE)
-include $(BUILD_HOST_EXECUTABLE)
-# Create symlink for the primary version target.
-ifeq ($(LOCAL_MULTILIB),both)
-include  $(BUILD_SYSTEM)/executable_prefer_symlink.mk
-
-ART_HOST_EXECUTABLES += $(HOST_OUT_EXECUTABLES)/$(LOCAL_MODULE)$(ART_PHONY_TEST_HOST_SUFFIX)
-ifdef 2ND_ART_PHONY_TEST_HOST_SUFFIX
-  ART_HOST_EXECUTABLES += $(HOST_OUT_EXECUTABLES)/$(LOCAL_MODULE)$(2ND_ART_PHONY_TEST_HOST_SUFFIX)
-endif
-endif
-ART_HOST_EXECUTABLES += $(HOST_OUT_EXECUTABLES)/$(LOCAL_MODULE)
diff --git a/dex2oat/Android.mk b/dex2oat/Android.mk
index 8a179c1..32424ca 100644
--- a/dex2oat/Android.mk
+++ b/dex2oat/Android.mk
@@ -55,35 +55,19 @@
   $(eval $(call build-art-executable,dex2oat,$(DEX2OAT_SRC_FILES),libcutils libartd-compiler libsigchain,art/compiler,target,debug,$(dex2oat_target_arch)))
 endif
 
-# Note: the order is important because of static linking resolution.
-DEX2OAT_STATIC_DEPENDENCIES := \
-  libziparchive \
-  libnativehelper \
-  libnativebridge \
-  libnativeloader \
-  libsigchain_dummy \
-  liblog \
-  libz \
-  libbacktrace \
-  libcutils \
-  libunwindbacktrace \
-  libutils \
-  libbase \
-  liblz4 \
-  liblzma
-
-# We always build dex2oat and dependencies, even if the host build is otherwise disabled, since they are used to cross compile for the target.
+# 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 $(DEX2OAT_STATIC_DEPENDENCIES),art/compiler,host,ndebug,$(dex2oat_host_arch),static))
+    $(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 $(DEX2OAT_STATIC_DEPENDENCIES),art/compiler,host,debug,$(dex2oat_host_arch),static))
+    $(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
 
diff --git a/dexdump/Android.bp b/dexdump/Android.bp
new file mode 100644
index 0000000..e77f809
--- /dev/null
+++ b/dexdump/Android.bp
@@ -0,0 +1,26 @@
+// Copyright (C) 2015 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.
+
+// TODO(ajcbik): rename dexdump2 into dexdump when Dalvik version is removed
+
+art_cc_binary {
+    name: "dexdump2",
+    host_supported: true,
+    srcs: [
+        "dexdump_main.cc",
+        "dexdump.cc",
+    ],
+    cflags: ["-Wall"],
+    shared_libs: ["libart"],
+}
diff --git a/dexdump/Android.mk b/dexdump/Android.mk
deleted file mode 100755
index ec2529e..0000000
--- a/dexdump/Android.mk
+++ /dev/null
@@ -1,52 +0,0 @@
-# Copyright (C) 2015 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.
-
-# TODO(ajcbik): Art-i-fy this makefile
-
-# TODO(ajcbik): rename dexdump2 into dexdump when Dalvik version is removed
-
-LOCAL_PATH:= $(call my-dir)
-
-dexdump_src_files := dexdump_main.cc dexdump.cc
-dexdump_c_includes := art/runtime
-dexdump_libraries := libart
-
-##
-## Build the device command line tool dexdump.
-##
-
-ifneq ($(SDK_ONLY),true)  # SDK_only doesn't need device version
-include $(CLEAR_VARS)
-LOCAL_CPP_EXTENSION := cc
-LOCAL_SRC_FILES := $(dexdump_src_files)
-LOCAL_C_INCLUDES := $(dexdump_c_includes)
-LOCAL_CFLAGS += -Wall
-LOCAL_SHARED_LIBRARIES += $(dexdump_libraries)
-LOCAL_MODULE := dexdump2
-include $(BUILD_EXECUTABLE)
-endif # !SDK_ONLY
-
-##
-## Build the host command line tool dexdump.
-##
-
-include $(CLEAR_VARS)
-LOCAL_CPP_EXTENSION := cc
-LOCAL_SRC_FILES := $(dexdump_src_files)
-LOCAL_C_INCLUDES := $(dexdump_c_includes)
-LOCAL_CFLAGS += -Wall
-LOCAL_SHARED_LIBRARIES += $(dexdump_libraries)
-LOCAL_MODULE := dexdump2
-LOCAL_MULTILIB := $(ART_MULTILIB_OVERRIDE_host)
-include $(BUILD_HOST_EXECUTABLE)
diff --git a/dexlayout/Android.bp b/dexlayout/Android.bp
new file mode 100644
index 0000000..852f6c2
--- /dev/null
+++ b/dexlayout/Android.bp
@@ -0,0 +1,25 @@
+// 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_binary {
+    name: "dexlayout",
+    host_supported: true,
+    srcs: [
+        "dexlayout_main.cc",
+        "dexlayout.cc",
+        "dex_ir_builder.cc",
+    ],
+    cflags: ["-Wall"],
+    shared_libs: ["libart"],
+}
diff --git a/dexlayout/Android.mk b/dexlayout/Android.mk
deleted file mode 100755
index 3095866..0000000
--- a/dexlayout/Android.mk
+++ /dev/null
@@ -1,50 +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.
-
-# TODO(sehr): Art-i-fy this makefile
-
-LOCAL_PATH:= $(call my-dir)
-
-dexlayout_src_files := dexlayout_main.cc dexlayout.cc dex_ir.cc
-dexlayout_c_includes := art/runtime
-dexlayout_libraries := libart
-
-##
-## Build the device command line tool dexlayout.
-##
-
-ifneq ($(SDK_ONLY),true)  # SDK_only doesn't need device version
-include $(CLEAR_VARS)
-LOCAL_CPP_EXTENSION := cc
-LOCAL_SRC_FILES := $(dexlayout_src_files)
-LOCAL_C_INCLUDES := $(dexlayout_c_includes)
-LOCAL_CFLAGS += -Wall
-LOCAL_SHARED_LIBRARIES += $(dexlayout_libraries)
-LOCAL_MODULE := dexlayout
-include $(BUILD_EXECUTABLE)
-endif # !SDK_ONLY
-
-##
-## Build the host command line tool dexlayout.
-##
-
-include $(CLEAR_VARS)
-LOCAL_CPP_EXTENSION := cc
-LOCAL_SRC_FILES := $(dexlayout_src_files)
-LOCAL_C_INCLUDES := $(dexlayout_c_includes)
-LOCAL_CFLAGS += -Wall
-LOCAL_SHARED_LIBRARIES += $(dexlayout_libraries)
-LOCAL_MODULE := dexlayout
-LOCAL_MULTILIB := $(ART_MULTILIB_OVERRIDE_host)
-include $(BUILD_HOST_EXECUTABLE)
diff --git a/dexlayout/dex_ir.cc b/dexlayout/dex_ir.cc
deleted file mode 100644
index 0ed040e..0000000
--- a/dexlayout/dex_ir.cc
+++ /dev/null
@@ -1,390 +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.
- *
- * Implementation file of the dex file intermediate representation.
- *
- * Utilities for reading dex files into an internal representation,
- * manipulating them, and writing them out.
- */
-
-#include "dex_ir.h"
-
-#include <map>
-#include <vector>
-
-#include "dex_file.h"
-#include "dex_file-inl.h"
-#include "utils.h"
-
-namespace art {
-namespace dex_ir {
-
-namespace {
-static uint64_t ReadVarWidth(const uint8_t** data, uint8_t length, bool sign_extend) {
-  uint64_t value = 0;
-  for (uint32_t i = 0; i <= length; i++) {
-    value |= static_cast<uint64_t>(*(*data)++) << (i * 8);
-  }
-  if (sign_extend) {
-    int shift = (7 - length) * 8;
-    return (static_cast<int64_t>(value) << shift) >> shift;
-  }
-  return value;
-}
-
-static bool GetPositionsCb(void* context, const DexFile::PositionInfo& entry) {
-  DebugInfoItem* debug_info = reinterpret_cast<DebugInfoItem*>(context);
-  std::vector<std::unique_ptr<PositionInfo>>& positions = debug_info->GetPositionInfo();
-  positions.push_back(std::unique_ptr<PositionInfo>(new PositionInfo(entry.address_, entry.line_)));
-  return false;
-}
-
-static void GetLocalsCb(void* context, const DexFile::LocalInfo& entry) {
-  DebugInfoItem* debug_info = reinterpret_cast<DebugInfoItem*>(context);
-  std::vector<std::unique_ptr<LocalInfo>>& locals = debug_info->GetLocalInfo();
-  const char* name = entry.name_ != nullptr ? entry.name_ : "(null)";
-  const char* signature = entry.signature_ != nullptr ? entry.signature_ : "";
-  locals.push_back(std::unique_ptr<LocalInfo>(
-      new LocalInfo(name, entry.descriptor_, signature, entry.start_address_,
-                    entry.end_address_, entry.reg_)));
-}
-}  // namespace
-
-Header::Header(const DexFile& dex_file) : dex_file_(dex_file) {
-  const DexFile::Header& disk_header = dex_file.GetHeader();
-  memcpy(magic_, disk_header.magic_, sizeof(magic_));
-  checksum_ = disk_header.checksum_;
-  // TODO(sehr): clearly the signature will need to be recomputed before dumping.
-  memcpy(signature_, disk_header.signature_, sizeof(signature_));
-  endian_tag_ = disk_header.endian_tag_;
-  file_size_ = disk_header.file_size_;
-  header_size_ = disk_header.header_size_;
-  link_size_ = disk_header.link_size_;
-  link_offset_ = disk_header.link_off_;
-  data_size_ = disk_header.data_size_;
-  data_offset_ = disk_header.data_off_;
-  // Walk the rest of the header fields.
-  string_ids_.SetOffset(disk_header.string_ids_off_);
-  for (uint32_t i = 0; i < dex_file_.NumStringIds(); ++i) {
-    string_ids_.AddWithPosition(i, new StringId(dex_file_.GetStringId(i), *this));
-  }
-  type_ids_.SetOffset(disk_header.type_ids_off_);
-  for (uint32_t i = 0; i < dex_file_.NumTypeIds(); ++i) {
-    type_ids_.AddWithPosition(i, new TypeId(dex_file_.GetTypeId(i), *this));
-  }
-  proto_ids_.SetOffset(disk_header.proto_ids_off_);
-  for (uint32_t i = 0; i < dex_file_.NumProtoIds(); ++i) {
-    proto_ids_.AddWithPosition(i, new ProtoId(dex_file_.GetProtoId(i), *this));
-  }
-  field_ids_.SetOffset(disk_header.field_ids_off_);
-  for (uint32_t i = 0; i < dex_file_.NumFieldIds(); ++i) {
-    field_ids_.AddWithPosition(i, new FieldId(dex_file_.GetFieldId(i), *this));
-  }
-  method_ids_.SetOffset(disk_header.method_ids_off_);
-  for (uint32_t i = 0; i < dex_file_.NumMethodIds(); ++i) {
-    method_ids_.AddWithPosition(i, new MethodId(dex_file_.GetMethodId(i), *this));
-  }
-  class_defs_.SetOffset(disk_header.class_defs_off_);
-  for (uint32_t i = 0; i < dex_file_.NumClassDefs(); ++i) {
-    class_defs_.AddWithPosition(i, new ClassDef(dex_file_.GetClassDef(i), *this));
-  }
-}
-
-ArrayItem::ArrayItem(Header& header, const uint8_t** data, uint8_t type, uint8_t length) {
-  Read(header, data, type, length);
-}
-
-ArrayItem::ArrayItem(Header& header, const uint8_t** data) {
-  const uint8_t encoded_value = *(*data)++;
-  Read(header, data, encoded_value & 0x1f, encoded_value >> 5);
-}
-
-void ArrayItem::Read(Header& header, const uint8_t** data, uint8_t type, uint8_t length) {
-  type_ = type;
-  switch (type_) {
-    case DexFile::kDexAnnotationByte:
-      item_.byte_val_ = static_cast<int8_t>(ReadVarWidth(data, length, false));
-      break;
-    case DexFile::kDexAnnotationShort:
-      item_.short_val_ = static_cast<int16_t>(ReadVarWidth(data, length, true));
-      break;
-    case DexFile::kDexAnnotationChar:
-      item_.char_val_ = static_cast<uint16_t>(ReadVarWidth(data, length, false));
-      break;
-    case DexFile::kDexAnnotationInt:
-      item_.int_val_ = static_cast<int32_t>(ReadVarWidth(data, length, true));
-      break;
-    case DexFile::kDexAnnotationLong:
-      item_.long_val_ = static_cast<int64_t>(ReadVarWidth(data, length, true));
-      break;
-    case DexFile::kDexAnnotationFloat: {
-      // Fill on right.
-      union {
-        float f;
-        uint32_t data;
-      } conv;
-      conv.data = static_cast<uint32_t>(ReadVarWidth(data, length, false)) << (3 - length) * 8;
-      item_.float_val_ = conv.f;
-      break;
-    }
-    case DexFile::kDexAnnotationDouble: {
-      // Fill on right.
-      union {
-        double d;
-        uint64_t data;
-      } conv;
-      conv.data = ReadVarWidth(data, length, false) << (7 - length) * 8;
-      item_.double_val_ = conv.d;
-      break;
-    }
-    case DexFile::kDexAnnotationString: {
-      const uint32_t string_index = static_cast<uint32_t>(ReadVarWidth(data, length, false));
-      item_.string_val_ = header.StringIds()[string_index].get();
-      break;
-    }
-    case DexFile::kDexAnnotationType: {
-      const uint32_t string_index = static_cast<uint32_t>(ReadVarWidth(data, length, false));
-      item_.string_val_ = header.TypeIds()[string_index]->GetStringId();
-      break;
-    }
-    case DexFile::kDexAnnotationField:
-    case DexFile::kDexAnnotationEnum: {
-      const uint32_t field_index = static_cast<uint32_t>(ReadVarWidth(data, length, false));
-      item_.field_val_ = header.FieldIds()[field_index].get();
-      break;
-    }
-    case DexFile::kDexAnnotationMethod: {
-      const uint32_t method_index = static_cast<uint32_t>(ReadVarWidth(data, length, false));
-      item_.method_val_ = header.MethodIds()[method_index].get();
-      break;
-    }
-    case DexFile::kDexAnnotationArray: {
-      item_.annotation_array_val_ = new std::vector<std::unique_ptr<ArrayItem>>();
-      // Decode all elements.
-      const uint32_t size = DecodeUnsignedLeb128(data);
-      for (uint32_t i = 0; i < size; i++) {
-        item_.annotation_array_val_->push_back(
-            std::unique_ptr<ArrayItem>(new ArrayItem(header, data)));
-      }
-      break;
-    }
-    case DexFile::kDexAnnotationAnnotation: {
-      const uint32_t type_idx = DecodeUnsignedLeb128(data);
-      item_.annotation_annotation_val_.string_ = header.TypeIds()[type_idx]->GetStringId();
-      item_.annotation_annotation_val_.array_ = new std::vector<std::unique_ptr<NameValuePair>>();
-      // Decode all name=value pairs.
-      const uint32_t size = DecodeUnsignedLeb128(data);
-      for (uint32_t i = 0; i < size; i++) {
-        const uint32_t name_index = DecodeUnsignedLeb128(data);
-        item_.annotation_annotation_val_.array_->push_back(std::unique_ptr<NameValuePair>(
-            new NameValuePair(header.StringIds()[name_index].get(), new ArrayItem(header, data))));
-      }
-      break;
-    }
-    case DexFile::kDexAnnotationNull:
-      break;
-    case DexFile::kDexAnnotationBoolean:
-      item_.bool_val_ = (length != 0);
-      break;
-    default:
-      break;
-  }
-}
-
-ClassDef::ClassDef(const DexFile::ClassDef& disk_class_def, Header& header) {
-  class_type_ = header.TypeIds()[disk_class_def.class_idx_].get();
-  access_flags_ = disk_class_def.access_flags_;
-  superclass_ = header.GetTypeIdOrNullPtr(disk_class_def.superclass_idx_);
-
-  const DexFile::TypeList* type_list = header.GetDexFile().GetInterfacesList(disk_class_def);
-  interfaces_offset_ = disk_class_def.interfaces_off_;
-  if (type_list != nullptr) {
-    for (uint32_t index = 0; index < type_list->Size(); ++index) {
-      interfaces_.push_back(header.TypeIds()[type_list->GetTypeItem(index).type_idx_].get());
-    }
-  }
-  source_file_ = header.GetStringIdOrNullPtr(disk_class_def.source_file_idx_);
-  // Annotations.
-  const DexFile::AnnotationsDirectoryItem* disk_annotations_directory_item =
-      header.GetDexFile().GetAnnotationsDirectory(disk_class_def);
-  if (disk_annotations_directory_item == nullptr) {
-    annotations_.reset(nullptr);
-  } else {
-    annotations_.reset(new AnnotationsDirectoryItem(disk_annotations_directory_item, header));
-    annotations_->SetOffset(disk_class_def.annotations_off_);
-  }
-  // Static field initializers.
-  static_values_ = nullptr;
-  const uint8_t* static_data = header.GetDexFile().GetEncodedStaticFieldValuesArray(disk_class_def);
-  if (static_data != nullptr) {
-    uint32_t static_value_count = static_data == nullptr ? 0 : DecodeUnsignedLeb128(&static_data);
-    if (static_value_count > 0) {
-      static_values_ = new std::vector<std::unique_ptr<ArrayItem>>();
-      for (uint32_t i = 0; i < static_value_count; ++i) {
-        static_values_->push_back(std::unique_ptr<ArrayItem>(new ArrayItem(header, &static_data)));
-      }
-    }
-  }
-  // Read the fields and methods defined by the class, resolving the circular reference from those
-  // to classes by setting class at the same time.
-  const uint8_t* encoded_data = header.GetDexFile().GetClassData(disk_class_def);
-  class_data_.SetOffset(disk_class_def.class_data_off_);
-  if (encoded_data != nullptr) {
-    ClassDataItemIterator cdii(header.GetDexFile(), encoded_data);
-    // Static fields.
-    for (uint32_t i = 0; cdii.HasNextStaticField(); i++, cdii.Next()) {
-      FieldId* field_item = header.FieldIds()[cdii.GetMemberIndex()].get();
-      uint32_t access_flags = cdii.GetRawMemberAccessFlags();
-      class_data_.StaticFields().push_back(
-          std::unique_ptr<FieldItem>(new FieldItem(access_flags, field_item)));
-    }
-    // Instance fields.
-    for (uint32_t i = 0; cdii.HasNextInstanceField(); i++, cdii.Next()) {
-      FieldId* field_item = header.FieldIds()[cdii.GetMemberIndex()].get();
-      uint32_t access_flags = cdii.GetRawMemberAccessFlags();
-      class_data_.InstanceFields().push_back(
-          std::unique_ptr<FieldItem>(new FieldItem(access_flags, field_item)));
-    }
-    // Direct methods.
-    for (uint32_t i = 0; cdii.HasNextDirectMethod(); i++, cdii.Next()) {
-      class_data_.DirectMethods().push_back(
-          std::unique_ptr<MethodItem>(GenerateMethodItem(header, cdii)));
-    }
-    // Virtual methods.
-    for (uint32_t i = 0; cdii.HasNextVirtualMethod(); i++, cdii.Next()) {
-      class_data_.VirtualMethods().push_back(
-          std::unique_ptr<MethodItem>(GenerateMethodItem(header, cdii)));
-    }
-  }
-}
-
-MethodItem* ClassDef::GenerateMethodItem(Header& header, ClassDataItemIterator& cdii) {
-  MethodId* method_item = header.MethodIds()[cdii.GetMemberIndex()].get();
-  uint32_t access_flags = cdii.GetRawMemberAccessFlags();
-  const DexFile::CodeItem* disk_code_item = cdii.GetMethodCodeItem();
-  CodeItem* code_item = nullptr;
-  DebugInfoItem* debug_info = nullptr;
-  if (disk_code_item != nullptr) {
-    code_item = new CodeItem(*disk_code_item, header);
-    code_item->SetOffset(cdii.GetMethodCodeItemOffset());
-    debug_info = code_item->DebugInfo();
-  }
-  if (debug_info != nullptr) {
-    bool is_static = (access_flags & kAccStatic) != 0;
-    header.GetDexFile().DecodeDebugLocalInfo(
-        disk_code_item, is_static, cdii.GetMemberIndex(), GetLocalsCb, debug_info);
-    header.GetDexFile().DecodeDebugPositionInfo(disk_code_item, GetPositionsCb, debug_info);
-  }
-  return new MethodItem(access_flags, method_item, code_item);
-}
-
-CodeItem::CodeItem(const DexFile::CodeItem& disk_code_item, Header& header) {
-  registers_size_ = disk_code_item.registers_size_;
-  ins_size_ = disk_code_item.ins_size_;
-  outs_size_ = disk_code_item.outs_size_;
-  tries_size_ = disk_code_item.tries_size_;
-
-  const uint8_t* debug_info_stream = header.GetDexFile().GetDebugInfoStream(&disk_code_item);
-  if (debug_info_stream != nullptr) {
-    debug_info_.reset(new DebugInfoItem());
-  } else {
-    debug_info_.reset(nullptr);
-  }
-
-  insns_size_ = disk_code_item.insns_size_in_code_units_;
-  insns_.reset(new uint16_t[insns_size_]);
-  memcpy(insns_.get(), disk_code_item.insns_, insns_size_ * sizeof(uint16_t));
-
-  if (tries_size_ > 0) {
-    tries_ = new std::vector<std::unique_ptr<const TryItem>>();
-    for (uint32_t i = 0; i < tries_size_; ++i) {
-      const DexFile::TryItem* disk_try_item = header.GetDexFile().GetTryItems(disk_code_item, i);
-      tries_->push_back(std::unique_ptr<const TryItem>(
-          new TryItem(*disk_try_item, disk_code_item, header)));
-    }
-  } else {
-    tries_ = nullptr;
-  }
-}
-
-AnnotationSetItem::AnnotationSetItem(const DexFile::AnnotationSetItem& disk_annotations_item,
-                                     Header& header) {
-  if (disk_annotations_item.size_ == 0) {
-    return;
-  }
-  for (uint32_t i = 0; i < disk_annotations_item.size_; ++i) {
-    const DexFile::AnnotationItem* annotation =
-        header.GetDexFile().GetAnnotationItem(&disk_annotations_item, i);
-    if (annotation == nullptr) {
-      continue;
-    }
-    uint8_t visibility = annotation->visibility_;
-    const uint8_t* annotation_data = annotation->annotation_;
-    ArrayItem* array_item =
-        new ArrayItem(header, &annotation_data, DexFile::kDexAnnotationAnnotation, 0);
-    items_.push_back(std::unique_ptr<AnnotationItem>(new AnnotationItem(visibility, array_item)));
-  }
-}
-
-AnnotationsDirectoryItem::AnnotationsDirectoryItem(
-    const DexFile::AnnotationsDirectoryItem* disk_annotations_item, Header& header) {
-  const DexFile::AnnotationSetItem* class_set_item =
-      header.GetDexFile().GetClassAnnotationSet(disk_annotations_item);
-  if (class_set_item == nullptr) {
-    class_annotation_.reset(nullptr);
-  } else {
-    class_annotation_.reset(new AnnotationSetItem(*class_set_item, header));
-  }
-  const DexFile::FieldAnnotationsItem* fields =
-      header.GetDexFile().GetFieldAnnotations(disk_annotations_item);
-  if (fields != nullptr) {
-    for (uint32_t i = 0; i < disk_annotations_item->fields_size_; ++i) {
-      FieldId* field_id = header.FieldIds()[fields[i].field_idx_].get();
-      const DexFile::AnnotationSetItem* field_set_item =
-          header.GetDexFile().GetFieldAnnotationSetItem(fields[i]);
-      dex_ir::AnnotationSetItem* annotation_set_item =
-          new AnnotationSetItem(*field_set_item, header);
-      field_annotations_.push_back(std::unique_ptr<FieldAnnotation>(
-          new FieldAnnotation(field_id, annotation_set_item)));
-    }
-  }
-  const DexFile::MethodAnnotationsItem* methods =
-      header.GetDexFile().GetMethodAnnotations(disk_annotations_item);
-  if (methods != nullptr) {
-    for (uint32_t i = 0; i < disk_annotations_item->methods_size_; ++i) {
-      MethodId* method_id = header.MethodIds()[methods[i].method_idx_].get();
-      const DexFile::AnnotationSetItem* method_set_item =
-          header.GetDexFile().GetMethodAnnotationSetItem(methods[i]);
-      dex_ir::AnnotationSetItem* annotation_set_item =
-          new AnnotationSetItem(*method_set_item, header);
-      method_annotations_.push_back(std::unique_ptr<MethodAnnotation>(
-          new MethodAnnotation(method_id, annotation_set_item)));
-    }
-  }
-  const DexFile::ParameterAnnotationsItem* parameters =
-      header.GetDexFile().GetParameterAnnotations(disk_annotations_item);
-  if (parameters != nullptr) {
-    for (uint32_t i = 0; i < disk_annotations_item->parameters_size_; ++i) {
-      MethodId* method_id = header.MethodIds()[parameters[i].method_idx_].get();
-      const DexFile::AnnotationSetRefList* list =
-          header.GetDexFile().GetParameterAnnotationSetRefList(&parameters[i]);
-      parameter_annotations_.push_back(std::unique_ptr<ParameterAnnotation>(
-          new ParameterAnnotation(method_id, list, header)));
-    }
-  }
-}
-
-}  // namespace dex_ir
-}  // namespace art
diff --git a/dexlayout/dex_ir.h b/dexlayout/dex_ir.h
index fcd3ab0..cbb4404 100644
--- a/dexlayout/dex_ir.h
+++ b/dexlayout/dex_ir.h
@@ -19,12 +19,10 @@
 #ifndef ART_DEXLAYOUT_DEX_IR_H_
 #define ART_DEXLAYOUT_DEX_IR_H_
 
-#include <iostream>
-#include <map>
 #include <vector>
 #include <stdint.h>
 
-#include "dex_file.h"
+#include "dex_file-inl.h"
 
 namespace art {
 namespace dex_ir {
@@ -106,19 +104,39 @@
 class Item {
  public:
   virtual ~Item() { }
+
   uint32_t GetOffset() const { return offset_; }
   void SetOffset(uint32_t offset) { offset_ = offset; }
+
  protected:
   uint32_t offset_ = 0;
 };
 
 class Header : public Item {
  public:
-  explicit Header(const DexFile& dex_file);
+  Header(const uint8_t* magic,
+         uint32_t checksum,
+         const uint8_t* signature,
+         uint32_t endian_tag,
+         uint32_t file_size,
+         uint32_t header_size,
+         uint32_t link_size,
+         uint32_t link_offset,
+         uint32_t data_size,
+         uint32_t data_offset)
+      : checksum_(checksum),
+        endian_tag_(endian_tag),
+        file_size_(file_size),
+        header_size_(header_size),
+        link_size_(link_size),
+        link_offset_(link_offset),
+        data_size_(data_size),
+        data_offset_(data_offset) {
+    memcpy(magic_, magic, sizeof(magic_));
+    memcpy(signature_, signature, sizeof(signature_));
+  }
   ~Header() OVERRIDE { }
 
-  const DexFile& GetDexFile() const { return dex_file_; }
-
   const uint8_t* Magic() const { return magic_; }
   uint32_t Checksum() const { return checksum_; }
   const uint8_t* Signature() const { return signature_; }
@@ -178,7 +196,6 @@
   void Accept(AbstractDispatcher* dispatch) { dispatch->Dispatch(this); }
 
  private:
-  const DexFile& dex_file_;
   uint8_t magic_[8];
   uint32_t checksum_;
   uint8_t signature_[DexFile::kSha1DigestSize];
@@ -201,9 +218,7 @@
 
 class StringId : public Item {
  public:
-  StringId(const DexFile::StringId& disk_string_id, Header& header) :
-    data_(strdup(header.GetDexFile().GetStringData(disk_string_id))) {
-  }
+  explicit StringId(const char* data) : data_(strdup(data)) { }
   ~StringId() OVERRIDE { }
 
   const char* Data() const { return data_.get(); }
@@ -217,9 +232,7 @@
 
 class TypeId : public Item {
  public:
-  TypeId(const DexFile::TypeId& disk_type_id, Header& header) :
-    string_id_(header.StringIds()[disk_type_id.descriptor_idx_].get()) {
-  }
+  explicit TypeId(StringId* string_id) : string_id_(string_id) { }
   ~TypeId() OVERRIDE { }
 
   StringId* GetStringId() const { return string_id_; }
@@ -231,39 +244,31 @@
   DISALLOW_COPY_AND_ASSIGN(TypeId);
 };
 
+using TypeIdVector = std::vector<const TypeId*>;
+
 class ProtoId : public Item {
  public:
-  ProtoId(const DexFile::ProtoId& disk_proto_id, Header& header) {
-    shorty_ = header.StringIds()[disk_proto_id.shorty_idx_].get();
-    return_type_ = header.TypeIds()[disk_proto_id.return_type_idx_].get();
-    DexFileParameterIterator dfpi(header.GetDexFile(), disk_proto_id);
-    while (dfpi.HasNext()) {
-      parameters_.push_back(header.TypeIds()[dfpi.GetTypeIdx()].get());
-      dfpi.Next();
-    }
-  }
+  ProtoId(const StringId* shorty, const TypeId* return_type, TypeIdVector* parameters)
+      : shorty_(shorty), return_type_(return_type), parameters_(parameters) { }
   ~ProtoId() OVERRIDE { }
 
   const StringId* Shorty() const { return shorty_; }
   const TypeId* ReturnType() const { return return_type_; }
-  const std::vector<const TypeId*>& Parameters() const { return parameters_; }
+  const std::vector<const TypeId*>& Parameters() const { return *parameters_; }
 
   void Accept(AbstractDispatcher* dispatch) const { dispatch->Dispatch(this); }
 
  private:
   const StringId* shorty_;
   const TypeId* return_type_;
-  std::vector<const TypeId*> parameters_;
+  std::unique_ptr<TypeIdVector> parameters_;
   DISALLOW_COPY_AND_ASSIGN(ProtoId);
 };
 
 class FieldId : public Item {
  public:
-  FieldId(const DexFile::FieldId& disk_field_id, Header& header) {
-    class_ = header.TypeIds()[disk_field_id.class_idx_].get();
-    type_ = header.TypeIds()[disk_field_id.type_idx_].get();
-    name_ = header.StringIds()[disk_field_id.name_idx_].get();
-  }
+  FieldId(const TypeId* klass, const TypeId* type, const StringId* name)
+      : class_(klass), type_(type), name_(name) { }
   ~FieldId() OVERRIDE { }
 
   const TypeId* Class() const { return class_; }
@@ -281,11 +286,8 @@
 
 class MethodId : public Item {
  public:
-  MethodId(const DexFile::MethodId& disk_method_id, Header& header) {
-    class_ = header.TypeIds()[disk_method_id.class_idx_].get();
-    proto_ = header.ProtoIds()[disk_method_id.proto_idx_].get();
-    name_ = header.StringIds()[disk_method_id.name_idx_].get();
-  }
+  MethodId(const TypeId* klass, const ProtoId* proto, const StringId* name)
+      : class_(klass), proto_(proto), name_(name) { }
   ~MethodId() OVERRIDE { }
 
   const TypeId* Class() const { return class_; }
@@ -303,8 +305,8 @@
 
 class FieldItem : public Item {
  public:
-  FieldItem(uint32_t access_flags, const FieldId* field_id) :
-    access_flags_(access_flags), field_id_(field_id) { }
+  FieldItem(uint32_t access_flags, const FieldId* field_id)
+      : access_flags_(access_flags), field_id_(field_id) { }
   ~FieldItem() OVERRIDE { }
 
   uint32_t GetAccessFlags() const { return access_flags_; }
@@ -318,10 +320,12 @@
   DISALLOW_COPY_AND_ASSIGN(FieldItem);
 };
 
+using FieldItemVector = std::vector<std::unique_ptr<FieldItem>>;
+
 class MethodItem : public Item {
  public:
-  MethodItem(uint32_t access_flags, const MethodId* method_id, const CodeItem* code) :
-    access_flags_(access_flags), method_id_(method_id), code_(code) { }
+  MethodItem(uint32_t access_flags, const MethodId* method_id, const CodeItem* code)
+      : access_flags_(access_flags), method_id_(method_id), code_(code) { }
   ~MethodItem() OVERRIDE { }
 
   uint32_t GetAccessFlags() const { return access_flags_; }
@@ -337,12 +341,14 @@
   DISALLOW_COPY_AND_ASSIGN(MethodItem);
 };
 
+using MethodItemVector = std::vector<std::unique_ptr<MethodItem>>;
+
 class ArrayItem : public Item {
  public:
   class NameValuePair {
    public:
-    NameValuePair(StringId* name, ArrayItem* value) :
-      name_(name), value_(value) { }
+    NameValuePair(StringId* name, ArrayItem* value)
+        : name_(name), value_(value) { }
 
     StringId* Name() const { return name_; }
     ArrayItem* Value() const { return value_.get(); }
@@ -353,92 +359,125 @@
     DISALLOW_COPY_AND_ASSIGN(NameValuePair);
   };
 
-  ArrayItem(Header& header, const uint8_t** data, uint8_t type, uint8_t length);
-  ArrayItem(Header& header, const uint8_t** data);
+  struct ArrayItemVariant {
+   public:
+    union {
+      bool bool_val_;
+      int8_t byte_val_;
+      int16_t short_val_;
+      uint16_t char_val_;
+      int32_t int_val_;
+      int64_t long_val_;
+      float float_val_;
+      double double_val_;
+      StringId* string_val_;
+      FieldId* field_val_;
+      MethodId* method_val_;
+    } u_;
+    std::unique_ptr<std::vector<std::unique_ptr<ArrayItem>>> annotation_array_val_;
+    struct {
+      StringId* string_;
+      std::unique_ptr<std::vector<std::unique_ptr<NameValuePair>>> array_;
+    } annotation_annotation_val_;
+  };
+
+  explicit ArrayItem(uint8_t type) : type_(type) { }
   ~ArrayItem() OVERRIDE { }
 
   int8_t Type() const { return type_; }
-  bool GetBoolean() const { return item_.bool_val_; }
-  int8_t GetByte() const { return item_.byte_val_; }
-  int16_t GetShort() const { return item_.short_val_; }
-  uint16_t GetChar() const { return item_.char_val_; }
-  int32_t GetInt() const { return item_.int_val_; }
-  int64_t GetLong() const { return item_.long_val_; }
-  float GetFloat() const { return item_.float_val_; }
-  double GetDouble() const { return item_.double_val_; }
-  StringId* GetStringId() const { return item_.string_val_; }
-  FieldId* GetFieldId() const { return item_.field_val_; }
-  MethodId* GetMethodId() const { return item_.method_val_; }
+  bool GetBoolean() const { return item_.u_.bool_val_; }
+  int8_t GetByte() const { return item_.u_.byte_val_; }
+  int16_t GetShort() const { return item_.u_.short_val_; }
+  uint16_t GetChar() const { return item_.u_.char_val_; }
+  int32_t GetInt() const { return item_.u_.int_val_; }
+  int64_t GetLong() const { return item_.u_.long_val_; }
+  float GetFloat() const { return item_.u_.float_val_; }
+  double GetDouble() const { return item_.u_.double_val_; }
+  StringId* GetStringId() const { return item_.u_.string_val_; }
+  FieldId* GetFieldId() const { return item_.u_.field_val_; }
+  MethodId* GetMethodId() const { return item_.u_.method_val_; }
   std::vector<std::unique_ptr<ArrayItem>>* GetAnnotationArray() const {
-    return item_.annotation_array_val_;
+    return item_.annotation_array_val_.get();
   }
   StringId* GetAnnotationAnnotationString() const {
     return item_.annotation_annotation_val_.string_;
   }
   std::vector<std::unique_ptr<NameValuePair>>* GetAnnotationAnnotationNameValuePairArray() const {
-    return item_.annotation_annotation_val_.array_;
+    return item_.annotation_annotation_val_.array_.get();
   }
+  // Used to construct the item union.  Ugly, but necessary.
+  ArrayItemVariant* GetArrayItemVariant() { return &item_; }
 
   void Accept(AbstractDispatcher* dispatch) { dispatch->Dispatch(this); }
 
  private:
-  void Read(Header& header, const uint8_t** data, uint8_t type, uint8_t length);
   uint8_t type_;
-  union {
-    bool bool_val_;
-    int8_t byte_val_;
-    int16_t short_val_;
-    uint16_t char_val_;
-    int32_t int_val_;
-    int64_t long_val_;
-    float float_val_;
-    double double_val_;
-    StringId* string_val_;
-    FieldId* field_val_;
-    MethodId* method_val_;
-    std::vector<std::unique_ptr<ArrayItem>>* annotation_array_val_;
-    struct {
-      StringId* string_;
-      std::vector<std::unique_ptr<NameValuePair>>* array_;
-    } annotation_annotation_val_;
-  } item_;
+  ArrayItemVariant item_;
   DISALLOW_COPY_AND_ASSIGN(ArrayItem);
 };
 
+using ArrayItemVector = std::vector<std::unique_ptr<ArrayItem>>;
+
 class ClassData : public Item {
  public:
-  ClassData() = default;
+  ClassData(FieldItemVector* static_fields,
+            FieldItemVector* instance_fields,
+            MethodItemVector* direct_methods,
+            MethodItemVector* virtual_methods)
+      : static_fields_(static_fields),
+        instance_fields_(instance_fields),
+        direct_methods_(direct_methods),
+        virtual_methods_(virtual_methods) { }
+
   ~ClassData() OVERRIDE = default;
-  std::vector<std::unique_ptr<FieldItem>>& StaticFields() { return static_fields_; }
-  std::vector<std::unique_ptr<FieldItem>>& InstanceFields() { return instance_fields_; }
-  std::vector<std::unique_ptr<MethodItem>>& DirectMethods() { return direct_methods_; }
-  std::vector<std::unique_ptr<MethodItem>>& VirtualMethods() { return virtual_methods_; }
+  FieldItemVector* StaticFields() { return static_fields_.get(); }
+  FieldItemVector* InstanceFields() { return instance_fields_.get(); }
+  MethodItemVector* DirectMethods() { return direct_methods_.get(); }
+  MethodItemVector* VirtualMethods() { return virtual_methods_.get(); }
 
   void Accept(AbstractDispatcher* dispatch) { dispatch->Dispatch(this); }
 
  private:
-  std::vector<std::unique_ptr<FieldItem>> static_fields_;
-  std::vector<std::unique_ptr<FieldItem>> instance_fields_;
-  std::vector<std::unique_ptr<MethodItem>> direct_methods_;
-  std::vector<std::unique_ptr<MethodItem>> virtual_methods_;
+  std::unique_ptr<FieldItemVector> static_fields_;
+  std::unique_ptr<FieldItemVector> instance_fields_;
+  std::unique_ptr<MethodItemVector> direct_methods_;
+  std::unique_ptr<MethodItemVector> virtual_methods_;
   DISALLOW_COPY_AND_ASSIGN(ClassData);
 };
 
 class ClassDef : public Item {
  public:
-  ClassDef(const DexFile::ClassDef& disk_class_def, Header& header);
+  ClassDef(const TypeId* class_type,
+           uint32_t access_flags,
+           const TypeId* superclass,
+           TypeIdVector* interfaces,
+           uint32_t interfaces_offset,
+           const StringId* source_file,
+           AnnotationsDirectoryItem* annotations,
+           ArrayItemVector* static_values,
+           ClassData* class_data)
+      : class_type_(class_type),
+        access_flags_(access_flags),
+        superclass_(superclass),
+        interfaces_(interfaces),
+        interfaces_offset_(interfaces_offset),
+        source_file_(source_file),
+        annotations_(annotations),
+        static_values_(static_values),
+        class_data_(class_data) { }
+
   ~ClassDef() OVERRIDE { }
 
   const TypeId* ClassType() const { return class_type_; }
   uint32_t GetAccessFlags() const { return access_flags_; }
   const TypeId* Superclass() const { return superclass_; }
-  std::vector<TypeId*>* Interfaces() { return &interfaces_; }
+  TypeIdVector* Interfaces() { return interfaces_.get(); }
   uint32_t InterfacesOffset() const { return interfaces_offset_; }
   void SetInterfacesOffset(uint32_t new_offset) { interfaces_offset_ = new_offset; }
   const StringId* SourceFile() const { return source_file_; }
   AnnotationsDirectoryItem* Annotations() const { return annotations_.get(); }
-  std::vector<std::unique_ptr<ArrayItem>>* StaticValues() { return static_values_; }
-  ClassData* GetClassData() { return &class_data_; }
+  ArrayItemVector* StaticValues() { return static_values_.get(); }
+  ClassData* GetClassData() { return class_data_.get(); }
 
   MethodItem* GenerateMethodItem(Header& header, ClassDataItemIterator& cdii);
 
@@ -448,28 +487,78 @@
   const TypeId* class_type_;
   uint32_t access_flags_;
   const TypeId* superclass_;
-  std::vector<TypeId*> interfaces_;
+  std::unique_ptr<TypeIdVector> interfaces_;
   uint32_t interfaces_offset_;
   const StringId* source_file_;
   std::unique_ptr<AnnotationsDirectoryItem> annotations_;
-  std::vector<std::unique_ptr<ArrayItem>>* static_values_;
-  ClassData class_data_;
+  std::unique_ptr<ArrayItemVector> static_values_;
+  std::unique_ptr<ClassData> class_data_;
   DISALLOW_COPY_AND_ASSIGN(ClassDef);
 };
 
+class CatchHandler {
+ public:
+  CatchHandler(const TypeId* type_id, uint32_t address) : type_id_(type_id), address_(address) { }
+
+  const TypeId* GetTypeId() const { return type_id_; }
+  uint32_t GetAddress() const { return address_; }
+
+ private:
+  const TypeId* type_id_;
+  uint32_t address_;
+  DISALLOW_COPY_AND_ASSIGN(CatchHandler);
+};
+
+using CatchHandlerVector = std::vector<std::unique_ptr<const CatchHandler>>;
+
+class TryItem : public Item {
+ public:
+  TryItem(uint32_t start_addr, uint16_t insn_count, CatchHandlerVector* handlers)
+      : start_addr_(start_addr), insn_count_(insn_count), handlers_(handlers) { }
+  ~TryItem() OVERRIDE { }
+
+  uint32_t StartAddr() const { return start_addr_; }
+  uint16_t InsnCount() const { return insn_count_; }
+  const CatchHandlerVector& GetHandlers() const { return *handlers_.get(); }
+
+  void Accept(AbstractDispatcher* dispatch) { dispatch->Dispatch(this); }
+
+ private:
+  uint32_t start_addr_;
+  uint16_t insn_count_;
+  std::unique_ptr<CatchHandlerVector> handlers_;
+  DISALLOW_COPY_AND_ASSIGN(TryItem);
+};
+
+using TryItemVector = std::vector<std::unique_ptr<const TryItem>>;
+
 class CodeItem : public Item {
  public:
-  CodeItem(const DexFile::CodeItem& disk_code_item, Header& header);
+  CodeItem(uint16_t registers_size,
+           uint16_t ins_size,
+           uint16_t outs_size,
+           DebugInfoItem* debug_info,
+           uint32_t insns_size,
+           uint16_t* insns,
+           TryItemVector* tries)
+      : registers_size_(registers_size),
+        ins_size_(ins_size),
+        outs_size_(outs_size),
+        debug_info_(debug_info),
+        insns_size_(insns_size),
+        insns_(insns),
+        tries_(tries) { }
+
   ~CodeItem() OVERRIDE { }
 
   uint16_t RegistersSize() const { return registers_size_; }
   uint16_t InsSize() const { return ins_size_; }
   uint16_t OutsSize() const { return outs_size_; }
-  uint16_t TriesSize() const { return tries_size_; }
+  uint16_t TriesSize() const { return tries_ == nullptr ? 0 : tries_->size(); }
   DebugInfoItem* DebugInfo() const { return debug_info_.get(); }
   uint32_t InsnsSize() const { return insns_size_; }
   uint16_t* Insns() const { return insns_.get(); }
-  std::vector<std::unique_ptr<const TryItem>>* Tries() const { return tries_; }
+  TryItemVector* Tries() const { return tries_.get(); }
 
   void Accept(AbstractDispatcher* dispatch) { dispatch->Dispatch(this); }
 
@@ -477,56 +566,13 @@
   uint16_t registers_size_;
   uint16_t ins_size_;
   uint16_t outs_size_;
-  uint16_t tries_size_;
   std::unique_ptr<DebugInfoItem> debug_info_;
   uint32_t insns_size_;
   std::unique_ptr<uint16_t[]> insns_;
-  std::vector<std::unique_ptr<const TryItem>>* tries_;
+  std::unique_ptr<TryItemVector> tries_;
   DISALLOW_COPY_AND_ASSIGN(CodeItem);
 };
 
-class TryItem : public Item {
- public:
-  class CatchHandler {
-   public:
-    CatchHandler(const TypeId* type_id, uint32_t address) : type_id_(type_id), address_(address) { }
-
-    const TypeId* GetTypeId() const { return type_id_; }
-    uint32_t GetAddress() const { return address_; }
-
-   private:
-    const TypeId* type_id_;
-    uint32_t address_;
-    DISALLOW_COPY_AND_ASSIGN(CatchHandler);
-  };
-
-  TryItem(const DexFile::TryItem& disk_try_item,
-          const DexFile::CodeItem& disk_code_item,
-          Header& header) {
-    start_addr_ = disk_try_item.start_addr_;
-    insn_count_ = disk_try_item.insn_count_;
-    for (CatchHandlerIterator it(disk_code_item, disk_try_item); it.HasNext(); it.Next()) {
-      const uint16_t type_index = it.GetHandlerTypeIndex();
-      const TypeId* type_id = header.GetTypeIdOrNullPtr(type_index);
-      handlers_.push_back(std::unique_ptr<const CatchHandler>(
-          new CatchHandler(type_id, it.GetHandlerAddress())));
-    }
-  }
-  ~TryItem() OVERRIDE { }
-
-  uint32_t StartAddr() const { return start_addr_; }
-  uint16_t InsnCount() const { return insn_count_; }
-  const std::vector<std::unique_ptr<const CatchHandler>>& GetHandlers() const { return handlers_; }
-
-  void Accept(AbstractDispatcher* dispatch) { dispatch->Dispatch(this); }
-
- private:
-  uint32_t start_addr_;
-  uint16_t insn_count_;
-  std::vector<std::unique_ptr<const CatchHandler>> handlers_;
-  DISALLOW_COPY_AND_ASSIGN(TryItem);
-};
-
 
 struct PositionInfo {
   PositionInfo(uint32_t address, uint32_t line) : address_(address), line_(line) { }
@@ -535,11 +581,21 @@
   uint32_t line_;
 };
 
+using PositionInfoVector = std::vector<std::unique_ptr<PositionInfo>>;
+
 struct LocalInfo {
-  LocalInfo(const char* name, const char* descriptor, const char* signature, uint32_t start_address,
-            uint32_t end_address, uint16_t reg) :
-    name_(name), descriptor_(descriptor), signature_(signature), start_address_(start_address),
-    end_address_(end_address), reg_(reg) { }
+  LocalInfo(const char* name,
+            const char* descriptor,
+            const char* signature,
+            uint32_t start_address,
+            uint32_t end_address,
+            uint16_t reg)
+      : name_(name),
+        descriptor_(descriptor),
+        signature_(signature),
+        start_address_(start_address),
+        end_address_(end_address),
+        reg_(reg) { }
 
   std::string name_;
   std::string descriptor_;
@@ -549,124 +605,123 @@
   uint16_t reg_;
 };
 
+using LocalInfoVector = std::vector<std::unique_ptr<LocalInfo>>;
+
 class DebugInfoItem : public Item {
  public:
   DebugInfoItem() = default;
 
-  std::vector<std::unique_ptr<PositionInfo>>& GetPositionInfo() { return positions_; }
-  std::vector<std::unique_ptr<LocalInfo>>& GetLocalInfo() { return locals_; }
+  PositionInfoVector& GetPositionInfo() { return positions_; }
+  LocalInfoVector& GetLocalInfo() { return locals_; }
 
  private:
-  std::vector<std::unique_ptr<PositionInfo>> positions_;
-  std::vector<std::unique_ptr<LocalInfo>> locals_;
+  PositionInfoVector positions_;
+  LocalInfoVector locals_;
   DISALLOW_COPY_AND_ASSIGN(DebugInfoItem);
 };
 
+class AnnotationItem {
+ public:
+  AnnotationItem(uint8_t visibility, ArrayItem* item) : visibility_(visibility), item_(item) { }
+
+  uint8_t GetVisibility() const { return visibility_; }
+  ArrayItem* GetItem() const { return item_.get(); }
+
+ private:
+  uint8_t visibility_;
+  std::unique_ptr<ArrayItem> item_;
+  DISALLOW_COPY_AND_ASSIGN(AnnotationItem);
+};
+
+using AnnotationItemVector = std::vector<std::unique_ptr<AnnotationItem>>;
+
 class AnnotationSetItem : public Item {
  public:
-  class AnnotationItem {
-   public:
-    AnnotationItem(uint8_t visibility, ArrayItem* item) :
-      visibility_(visibility), item_(item) { }
-
-    uint8_t GetVisibility() const { return visibility_; }
-    ArrayItem* GetItem() const { return item_.get(); }
-
-   private:
-    uint8_t visibility_;
-    std::unique_ptr<ArrayItem> item_;
-    DISALLOW_COPY_AND_ASSIGN(AnnotationItem);
-  };
-
-  AnnotationSetItem(const DexFile::AnnotationSetItem& disk_annotations_item, Header& header);
+  explicit AnnotationSetItem(AnnotationItemVector* items) : items_(items) { }
   ~AnnotationSetItem() OVERRIDE { }
 
-  std::vector<std::unique_ptr<AnnotationItem>>& GetItems() { return items_; }
+  AnnotationItemVector* GetItems() { return items_.get(); }
 
   void Accept(AbstractDispatcher* dispatch) { dispatch->Dispatch(this); }
 
  private:
-  std::vector<std::unique_ptr<AnnotationItem>> items_;
+  std::unique_ptr<AnnotationItemVector> items_;
   DISALLOW_COPY_AND_ASSIGN(AnnotationSetItem);
 };
 
+using AnnotationSetItemVector = std::vector<std::unique_ptr<AnnotationSetItem>>;
+
+class FieldAnnotation {
+ public:
+  FieldAnnotation(FieldId* field_id, AnnotationSetItem* annotation_set_item)
+      : field_id_(field_id), annotation_set_item_(annotation_set_item) { }
+
+  FieldId* GetFieldId() const { return field_id_; }
+  AnnotationSetItem* GetAnnotationSetItem() const { return annotation_set_item_.get(); }
+
+ private:
+  FieldId* field_id_;
+  std::unique_ptr<AnnotationSetItem> annotation_set_item_;
+  DISALLOW_COPY_AND_ASSIGN(FieldAnnotation);
+};
+
+using FieldAnnotationVector = std::vector<std::unique_ptr<FieldAnnotation>>;
+
+class MethodAnnotation {
+ public:
+  MethodAnnotation(MethodId* method_id, AnnotationSetItem* annotation_set_item)
+      : method_id_(method_id), annotation_set_item_(annotation_set_item) { }
+
+  MethodId* GetMethodId() const { return method_id_; }
+  AnnotationSetItem* GetAnnotationSetItem() const { return annotation_set_item_.get(); }
+
+ private:
+  MethodId* method_id_;
+  std::unique_ptr<AnnotationSetItem> annotation_set_item_;
+  DISALLOW_COPY_AND_ASSIGN(MethodAnnotation);
+};
+
+using MethodAnnotationVector = std::vector<std::unique_ptr<MethodAnnotation>>;
+
+class ParameterAnnotation {
+ public:
+  ParameterAnnotation(MethodId* method_id, AnnotationSetItemVector* annotations)
+      : method_id_(method_id), annotations_(annotations) { }
+
+  MethodId* GetMethodId() const { return method_id_; }
+  AnnotationSetItemVector* GetAnnotations() { return annotations_.get(); }
+
+ private:
+  MethodId* method_id_;
+  std::unique_ptr<AnnotationSetItemVector> annotations_;
+  DISALLOW_COPY_AND_ASSIGN(ParameterAnnotation);
+};
+
+using ParameterAnnotationVector = std::vector<std::unique_ptr<ParameterAnnotation>>;
+
 class AnnotationsDirectoryItem : public Item {
  public:
-  class FieldAnnotation {
-   public:
-    FieldAnnotation(FieldId* field_id, AnnotationSetItem* annotation_set_item) :
-      field_id_(field_id), annotation_set_item_(annotation_set_item) { }
-
-    FieldId* GetFieldId() const { return field_id_; }
-    AnnotationSetItem* GetAnnotationSetItem() const { return annotation_set_item_.get(); }
-
-   private:
-    FieldId* field_id_;
-    std::unique_ptr<AnnotationSetItem> annotation_set_item_;
-    DISALLOW_COPY_AND_ASSIGN(FieldAnnotation);
-  };
-
-  class MethodAnnotation {
-   public:
-    MethodAnnotation(MethodId* method_id, AnnotationSetItem* annotation_set_item) :
-      method_id_(method_id), annotation_set_item_(annotation_set_item) { }
-
-    MethodId* GetMethodId() const { return method_id_; }
-    AnnotationSetItem* GetAnnotationSetItem() const { return annotation_set_item_.get(); }
-
-   private:
-    MethodId* method_id_;
-    std::unique_ptr<AnnotationSetItem> annotation_set_item_;
-    DISALLOW_COPY_AND_ASSIGN(MethodAnnotation);
-  };
-
-  class ParameterAnnotation {
-   public:
-    ParameterAnnotation(MethodId* method_id,
-                        const DexFile::AnnotationSetRefList* annotation_set_ref_list,
-                        Header& header) :
-      method_id_(method_id) {
-      for (uint32_t i = 0; i < annotation_set_ref_list->size_; ++i) {
-        const DexFile::AnnotationSetItem* annotation_set_item =
-            header.GetDexFile().GetSetRefItemItem(&annotation_set_ref_list->list_[i]);
-        annotations_.push_back(std::unique_ptr<AnnotationSetItem>(
-            new AnnotationSetItem(*annotation_set_item, header)));
-      }
-    }
-
-    MethodId* GetMethodId() const { return method_id_; }
-    std::vector<std::unique_ptr<AnnotationSetItem>>& GetAnnotations() { return annotations_; }
-
-   private:
-    MethodId* method_id_;
-    std::vector<std::unique_ptr<AnnotationSetItem>> annotations_;
-    DISALLOW_COPY_AND_ASSIGN(ParameterAnnotation);
-  };
-
-  AnnotationsDirectoryItem(const DexFile::AnnotationsDirectoryItem* disk_annotations_item,
-                           Header& header);
+  AnnotationsDirectoryItem(AnnotationSetItem* class_annotation,
+                           FieldAnnotationVector* field_annotations,
+                           MethodAnnotationVector* method_annotations,
+                           ParameterAnnotationVector* parameter_annotations)
+      : class_annotation_(class_annotation),
+        field_annotations_(field_annotations),
+        method_annotations_(method_annotations),
+        parameter_annotations_(parameter_annotations) { }
 
   AnnotationSetItem* GetClassAnnotation() const { return class_annotation_.get(); }
-
-  std::vector<std::unique_ptr<FieldAnnotation>>& GetFieldAnnotations() {
-    return field_annotations_;
-  }
-
-  std::vector<std::unique_ptr<MethodAnnotation>>& GetMethodAnnotations() {
-    return method_annotations_;
-  }
-
-  std::vector<std::unique_ptr<ParameterAnnotation>>& GetParameterAnnotations() {
-    return parameter_annotations_;
-  }
+  FieldAnnotationVector* GetFieldAnnotations() { return field_annotations_.get(); }
+  MethodAnnotationVector* GetMethodAnnotations() { return method_annotations_.get(); }
+  ParameterAnnotationVector* GetParameterAnnotations() { return parameter_annotations_.get(); }
 
   void Accept(AbstractDispatcher* dispatch) { dispatch->Dispatch(this); }
 
  private:
   std::unique_ptr<AnnotationSetItem> class_annotation_;
-  std::vector<std::unique_ptr<FieldAnnotation>> field_annotations_;
-  std::vector<std::unique_ptr<MethodAnnotation>> method_annotations_;
-  std::vector<std::unique_ptr<ParameterAnnotation>> parameter_annotations_;
+  std::unique_ptr<FieldAnnotationVector> field_annotations_;
+  std::unique_ptr<MethodAnnotationVector> method_annotations_;
+  std::unique_ptr<ParameterAnnotationVector> parameter_annotations_;
   DISALLOW_COPY_AND_ASSIGN(AnnotationsDirectoryItem);
 };
 
diff --git a/dexlayout/dex_ir_builder.cc b/dexlayout/dex_ir_builder.cc
new file mode 100644
index 0000000..30f57d9
--- /dev/null
+++ b/dexlayout/dex_ir_builder.cc
@@ -0,0 +1,507 @@
+/*
+ * 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.
+ *
+ * Header file of an in-memory representation of DEX files.
+ */
+
+#include <stdint.h>
+#include <vector>
+
+#include "dex_ir_builder.h"
+
+namespace art {
+namespace dex_ir {
+
+namespace {
+
+static uint64_t ReadVarWidth(const uint8_t** data, uint8_t length, bool sign_extend) {
+  uint64_t value = 0;
+  for (uint32_t i = 0; i <= length; i++) {
+    value |= static_cast<uint64_t>(*(*data)++) << (i * 8);
+  }
+  if (sign_extend) {
+    int shift = (7 - length) * 8;
+    return (static_cast<int64_t>(value) << shift) >> shift;
+  }
+  return value;
+}
+
+// Prototype to break cyclic dependency.
+void ReadArrayItemVariant(Header& header,
+                          const uint8_t** data,
+                          uint8_t type,
+                          uint8_t length,
+                          ArrayItem::ArrayItemVariant* item);
+
+ArrayItem* ReadArrayItem(Header& header, const uint8_t** data, uint8_t type, uint8_t length) {
+  ArrayItem* item = new ArrayItem(type);
+  ReadArrayItemVariant(header, data, type, length, item->GetArrayItemVariant());
+  return item;
+}
+
+ArrayItem* ReadArrayItem(Header& header, const uint8_t** data) {
+  const uint8_t encoded_value = *(*data)++;
+  const uint8_t type = encoded_value & 0x1f;
+  ArrayItem* item = new ArrayItem(type);
+  ReadArrayItemVariant(header, data, type, encoded_value >> 5, item->GetArrayItemVariant());
+  return item;
+}
+
+void ReadArrayItemVariant(Header& header,
+                          const uint8_t** data,
+                          uint8_t type,
+                          uint8_t length,
+                          ArrayItem::ArrayItemVariant* item) {
+  switch (type) {
+    case DexFile::kDexAnnotationByte:
+      item->u_.byte_val_ = static_cast<int8_t>(ReadVarWidth(data, length, false));
+      break;
+    case DexFile::kDexAnnotationShort:
+      item->u_.short_val_ = static_cast<int16_t>(ReadVarWidth(data, length, true));
+      break;
+    case DexFile::kDexAnnotationChar:
+      item->u_.char_val_ = static_cast<uint16_t>(ReadVarWidth(data, length, false));
+      break;
+    case DexFile::kDexAnnotationInt:
+      item->u_.int_val_ = static_cast<int32_t>(ReadVarWidth(data, length, true));
+      break;
+    case DexFile::kDexAnnotationLong:
+      item->u_.long_val_ = static_cast<int64_t>(ReadVarWidth(data, length, true));
+      break;
+    case DexFile::kDexAnnotationFloat: {
+      // Fill on right.
+      union {
+        float f;
+        uint32_t data;
+      } conv;
+      conv.data = static_cast<uint32_t>(ReadVarWidth(data, length, false)) << (3 - length) * 8;
+      item->u_.float_val_ = conv.f;
+      break;
+    }
+    case DexFile::kDexAnnotationDouble: {
+      // Fill on right.
+      union {
+        double d;
+        uint64_t data;
+      } conv;
+      conv.data = ReadVarWidth(data, length, false) << (7 - length) * 8;
+      item->u_.double_val_ = conv.d;
+      break;
+    }
+    case DexFile::kDexAnnotationString: {
+      const uint32_t string_index = static_cast<uint32_t>(ReadVarWidth(data, length, false));
+      item->u_.string_val_ = header.StringIds()[string_index].get();
+      break;
+    }
+    case DexFile::kDexAnnotationType: {
+      const uint32_t string_index = static_cast<uint32_t>(ReadVarWidth(data, length, false));
+      item->u_.string_val_ = header.TypeIds()[string_index]->GetStringId();
+      break;
+    }
+    case DexFile::kDexAnnotationField:
+    case DexFile::kDexAnnotationEnum: {
+      const uint32_t field_index = static_cast<uint32_t>(ReadVarWidth(data, length, false));
+      item->u_.field_val_ = header.FieldIds()[field_index].get();
+      break;
+    }
+    case DexFile::kDexAnnotationMethod: {
+      const uint32_t method_index = static_cast<uint32_t>(ReadVarWidth(data, length, false));
+      item->u_.method_val_ = header.MethodIds()[method_index].get();
+      break;
+    }
+    case DexFile::kDexAnnotationArray: {
+      item->annotation_array_val_.reset(new ArrayItemVector());
+      // Decode all elements.
+      const uint32_t size = DecodeUnsignedLeb128(data);
+      for (uint32_t i = 0; i < size; i++) {
+        item->annotation_array_val_->push_back(
+            std::unique_ptr<ArrayItem>(ReadArrayItem(header, data)));
+      }
+      break;
+    }
+    case DexFile::kDexAnnotationAnnotation: {
+      const uint32_t type_idx = DecodeUnsignedLeb128(data);
+      item->annotation_annotation_val_.string_ = header.TypeIds()[type_idx]->GetStringId();
+      item->annotation_annotation_val_.array_.reset(
+          new std::vector<std::unique_ptr<ArrayItem::NameValuePair>>());
+      // Decode all name=value pairs.
+      const uint32_t size = DecodeUnsignedLeb128(data);
+      for (uint32_t i = 0; i < size; i++) {
+        const uint32_t name_index = DecodeUnsignedLeb128(data);
+        item->annotation_annotation_val_.array_->push_back(
+            std::unique_ptr<ArrayItem::NameValuePair>(
+                new ArrayItem::NameValuePair(header.StringIds()[name_index].get(),
+                                             ReadArrayItem(header, data))));
+      }
+      break;
+    }
+    case DexFile::kDexAnnotationNull:
+      break;
+    case DexFile::kDexAnnotationBoolean:
+      item->u_.bool_val_ = (length != 0);
+      break;
+    default:
+      break;
+  }
+}
+
+static bool GetPositionsCb(void* context, const DexFile::PositionInfo& entry) {
+  DebugInfoItem* debug_info = reinterpret_cast<DebugInfoItem*>(context);
+  PositionInfoVector& positions = debug_info->GetPositionInfo();
+  positions.push_back(std::unique_ptr<PositionInfo>(new PositionInfo(entry.address_, entry.line_)));
+  return false;
+}
+
+static void GetLocalsCb(void* context, const DexFile::LocalInfo& entry) {
+  DebugInfoItem* debug_info = reinterpret_cast<DebugInfoItem*>(context);
+  LocalInfoVector& locals = debug_info->GetLocalInfo();
+  const char* name = entry.name_ != nullptr ? entry.name_ : "(null)";
+  const char* signature = entry.signature_ != nullptr ? entry.signature_ : "";
+  locals.push_back(std::unique_ptr<LocalInfo>(
+      new LocalInfo(name, entry.descriptor_, signature, entry.start_address_,
+                    entry.end_address_, entry.reg_)));
+}
+
+CodeItem* ReadCodeItem(const DexFile& dex_file,
+                       const DexFile::CodeItem& disk_code_item,
+                       Header& header) {
+  uint16_t registers_size = disk_code_item.registers_size_;
+  uint16_t ins_size = disk_code_item.ins_size_;
+  uint16_t outs_size = disk_code_item.outs_size_;
+  uint32_t tries_size = disk_code_item.tries_size_;
+
+  const uint8_t* debug_info_stream = dex_file.GetDebugInfoStream(&disk_code_item);
+  DebugInfoItem* debug_info = nullptr;
+  if (debug_info_stream != nullptr) {
+    debug_info = new DebugInfoItem();
+  }
+
+  uint32_t insns_size = disk_code_item.insns_size_in_code_units_;
+  uint16_t* insns = new uint16_t[insns_size];
+  memcpy(insns, disk_code_item.insns_, insns_size * sizeof(uint16_t));
+
+  TryItemVector* tries = nullptr;
+  if (tries_size > 0) {
+    tries = new TryItemVector();
+    for (uint32_t i = 0; i < tries_size; ++i) {
+      const DexFile::TryItem* disk_try_item = dex_file.GetTryItems(disk_code_item, i);
+      uint32_t start_addr = disk_try_item->start_addr_;
+      uint16_t insn_count = disk_try_item->insn_count_;
+      CatchHandlerVector* handlers = new CatchHandlerVector();
+      for (CatchHandlerIterator it(disk_code_item, *disk_try_item); it.HasNext(); it.Next()) {
+        const uint16_t type_index = it.GetHandlerTypeIndex();
+        const TypeId* type_id = header.GetTypeIdOrNullPtr(type_index);
+        handlers->push_back(std::unique_ptr<const CatchHandler>(
+            new CatchHandler(type_id, it.GetHandlerAddress())));
+      }
+      TryItem* try_item = new TryItem(start_addr, insn_count, handlers);
+      tries->push_back(std::unique_ptr<const TryItem>(try_item));
+    }
+  }
+  return new CodeItem(registers_size, ins_size, outs_size, debug_info, insns_size, insns, tries);
+}
+
+MethodItem* GenerateMethodItem(const DexFile& dex_file,
+                               dex_ir::Header& header,
+                               ClassDataItemIterator& cdii) {
+  MethodId* method_item = header.MethodIds()[cdii.GetMemberIndex()].get();
+  uint32_t access_flags = cdii.GetRawMemberAccessFlags();
+  const DexFile::CodeItem* disk_code_item = cdii.GetMethodCodeItem();
+  CodeItem* code_item = nullptr;
+  DebugInfoItem* debug_info = nullptr;
+  if (disk_code_item != nullptr) {
+    code_item = ReadCodeItem(dex_file, *disk_code_item, header);
+    code_item->SetOffset(cdii.GetMethodCodeItemOffset());
+    debug_info = code_item->DebugInfo();
+  }
+  if (debug_info != nullptr) {
+    bool is_static = (access_flags & kAccStatic) != 0;
+    dex_file.DecodeDebugLocalInfo(
+        disk_code_item, is_static, cdii.GetMemberIndex(), GetLocalsCb, debug_info);
+    dex_file.DecodeDebugPositionInfo(disk_code_item, GetPositionsCb, debug_info);
+  }
+  return new MethodItem(access_flags, method_item, code_item);
+}
+
+AnnotationSetItem* ReadAnnotationSetItem(const DexFile& dex_file,
+                                         const DexFile::AnnotationSetItem& disk_annotations_item,
+                                         Header& header) {
+  if (disk_annotations_item.size_ == 0) {
+    return nullptr;
+  }
+  AnnotationItemVector* items = new AnnotationItemVector();
+  for (uint32_t i = 0; i < disk_annotations_item.size_; ++i) {
+    const DexFile::AnnotationItem* annotation =
+        dex_file.GetAnnotationItem(&disk_annotations_item, i);
+    if (annotation == nullptr) {
+      continue;
+    }
+    uint8_t visibility = annotation->visibility_;
+    const uint8_t* annotation_data = annotation->annotation_;
+    ArrayItem* array_item =
+        ReadArrayItem(header, &annotation_data, DexFile::kDexAnnotationAnnotation, 0);
+    items->push_back(std::unique_ptr<AnnotationItem>(new AnnotationItem(visibility, array_item)));
+  }
+  return new AnnotationSetItem(items);
+}
+
+ParameterAnnotation* ReadParameterAnnotation(
+    const DexFile& dex_file,
+    MethodId* method_id,
+    const DexFile::AnnotationSetRefList* annotation_set_ref_list,
+    Header& header) {
+  AnnotationSetItemVector* annotations = new AnnotationSetItemVector();
+  for (uint32_t i = 0; i < annotation_set_ref_list->size_; ++i) {
+    const DexFile::AnnotationSetItem* annotation_set_item =
+        dex_file.GetSetRefItemItem(&annotation_set_ref_list->list_[i]);
+    annotations->push_back(std::unique_ptr<AnnotationSetItem>(
+        ReadAnnotationSetItem(dex_file, *annotation_set_item, header)));
+  }
+  return new ParameterAnnotation(method_id, annotations);
+}
+
+AnnotationsDirectoryItem* ReadAnnotationsDirectoryItem(
+    const DexFile& dex_file,
+    const DexFile::AnnotationsDirectoryItem* disk_annotations_item,
+    Header& header) {
+  const DexFile::AnnotationSetItem* class_set_item =
+      dex_file.GetClassAnnotationSet(disk_annotations_item);
+  AnnotationSetItem* class_annotation = nullptr;
+  if (class_set_item != nullptr) {
+    class_annotation = ReadAnnotationSetItem(dex_file, *class_set_item, header);
+  }
+  const DexFile::FieldAnnotationsItem* fields =
+      dex_file.GetFieldAnnotations(disk_annotations_item);
+  FieldAnnotationVector* field_annotations = nullptr;
+  if (fields != nullptr) {
+    field_annotations = new FieldAnnotationVector();
+    for (uint32_t i = 0; i < disk_annotations_item->fields_size_; ++i) {
+      FieldId* field_id = header.FieldIds()[fields[i].field_idx_].get();
+      const DexFile::AnnotationSetItem* field_set_item =
+          dex_file.GetFieldAnnotationSetItem(fields[i]);
+      AnnotationSetItem* annotation_set_item =
+          ReadAnnotationSetItem(dex_file, *field_set_item, header);
+      field_annotations->push_back(std::unique_ptr<FieldAnnotation>(
+          new FieldAnnotation(field_id, annotation_set_item)));
+    }
+  }
+  const DexFile::MethodAnnotationsItem* methods =
+      dex_file.GetMethodAnnotations(disk_annotations_item);
+  MethodAnnotationVector* method_annotations = nullptr;
+  if (methods != nullptr) {
+    method_annotations = new MethodAnnotationVector();
+    for (uint32_t i = 0; i < disk_annotations_item->methods_size_; ++i) {
+      MethodId* method_id = header.MethodIds()[methods[i].method_idx_].get();
+      const DexFile::AnnotationSetItem* method_set_item =
+          dex_file.GetMethodAnnotationSetItem(methods[i]);
+      AnnotationSetItem* annotation_set_item =
+          ReadAnnotationSetItem(dex_file, *method_set_item, header);
+      method_annotations->push_back(std::unique_ptr<MethodAnnotation>(
+          new MethodAnnotation(method_id, annotation_set_item)));
+    }
+  }
+  const DexFile::ParameterAnnotationsItem* parameters =
+      dex_file.GetParameterAnnotations(disk_annotations_item);
+  ParameterAnnotationVector* parameter_annotations = nullptr;
+  if (parameters != nullptr) {
+    parameter_annotations = new ParameterAnnotationVector();
+    for (uint32_t i = 0; i < disk_annotations_item->parameters_size_; ++i) {
+      MethodId* method_id = header.MethodIds()[parameters[i].method_idx_].get();
+      const DexFile::AnnotationSetRefList* list =
+          dex_file.GetParameterAnnotationSetRefList(&parameters[i]);
+      parameter_annotations->push_back(std::unique_ptr<ParameterAnnotation>(
+          ReadParameterAnnotation(dex_file, method_id, list, header)));
+    }
+  }
+
+  return new AnnotationsDirectoryItem(class_annotation,
+                                      field_annotations,
+                                      method_annotations,
+                                      parameter_annotations);
+}
+
+ClassDef* ReadClassDef(const DexFile& dex_file,
+                       const DexFile::ClassDef& disk_class_def,
+                       Header& header) {
+  const TypeId* class_type = header.TypeIds()[disk_class_def.class_idx_].get();
+  uint32_t access_flags = disk_class_def.access_flags_;
+  const TypeId* superclass = header.GetTypeIdOrNullPtr(disk_class_def.superclass_idx_);
+
+  TypeIdVector* interfaces = nullptr;
+  const DexFile::TypeList* type_list = dex_file.GetInterfacesList(disk_class_def);
+  uint32_t interfaces_offset = disk_class_def.interfaces_off_;
+  if (type_list != nullptr) {
+    interfaces = new TypeIdVector();
+    for (uint32_t index = 0; index < type_list->Size(); ++index) {
+      interfaces->push_back(header.TypeIds()[type_list->GetTypeItem(index).type_idx_].get());
+    }
+  }
+  const StringId* source_file = header.GetStringIdOrNullPtr(disk_class_def.source_file_idx_);
+  // Annotations.
+  AnnotationsDirectoryItem* annotations = nullptr;
+  const DexFile::AnnotationsDirectoryItem* disk_annotations_directory_item =
+      dex_file.GetAnnotationsDirectory(disk_class_def);
+  if (disk_annotations_directory_item != nullptr) {
+    annotations = ReadAnnotationsDirectoryItem(dex_file, disk_annotations_directory_item, header);
+    annotations->SetOffset(disk_class_def.annotations_off_);
+  }
+  // Static field initializers.
+  ArrayItemVector* static_values = nullptr;
+  const uint8_t* static_data = dex_file.GetEncodedStaticFieldValuesArray(disk_class_def);
+  if (static_data != nullptr) {
+    uint32_t static_value_count = static_data == nullptr ? 0 : DecodeUnsignedLeb128(&static_data);
+    if (static_value_count > 0) {
+      static_values = new ArrayItemVector();
+      for (uint32_t i = 0; i < static_value_count; ++i) {
+        static_values->push_back(std::unique_ptr<ArrayItem>(ReadArrayItem(header, &static_data)));
+      }
+    }
+  }
+  // Read the fields and methods defined by the class, resolving the circular reference from those
+  // to classes by setting class at the same time.
+  const uint8_t* encoded_data = dex_file.GetClassData(disk_class_def);
+  ClassData* class_data = nullptr;
+  if (encoded_data != nullptr) {
+    uint32_t offset = disk_class_def.class_data_off_;
+    ClassDataItemIterator cdii(dex_file, encoded_data);
+    // Static fields.
+    FieldItemVector* static_fields = new FieldItemVector();
+    for (uint32_t i = 0; cdii.HasNextStaticField(); i++, cdii.Next()) {
+      FieldId* field_item = header.FieldIds()[cdii.GetMemberIndex()].get();
+      uint32_t access_flags = cdii.GetRawMemberAccessFlags();
+      static_fields->push_back(std::unique_ptr<FieldItem>(new FieldItem(access_flags, field_item)));
+    }
+    // Instance fields.
+    FieldItemVector* instance_fields = new FieldItemVector();
+    for (uint32_t i = 0; cdii.HasNextInstanceField(); i++, cdii.Next()) {
+      FieldId* field_item = header.FieldIds()[cdii.GetMemberIndex()].get();
+      uint32_t access_flags = cdii.GetRawMemberAccessFlags();
+      instance_fields->push_back(
+          std::unique_ptr<FieldItem>(new FieldItem(access_flags, field_item)));
+    }
+    // Direct methods.
+    MethodItemVector* direct_methods = new MethodItemVector();
+    for (uint32_t i = 0; cdii.HasNextDirectMethod(); i++, cdii.Next()) {
+      direct_methods->push_back(
+          std::unique_ptr<MethodItem>(GenerateMethodItem(dex_file, header, cdii)));
+    }
+    // Virtual methods.
+    MethodItemVector* virtual_methods = new MethodItemVector();
+    for (uint32_t i = 0; cdii.HasNextVirtualMethod(); i++, cdii.Next()) {
+      virtual_methods->push_back(
+          std::unique_ptr<MethodItem>(GenerateMethodItem(dex_file, header, cdii)));
+    }
+    class_data = new ClassData(static_fields, instance_fields, direct_methods, virtual_methods);
+    class_data->SetOffset(offset);
+  }
+  return new ClassDef(class_type,
+                      access_flags,
+                      superclass,
+                      interfaces,
+                      interfaces_offset,
+                      source_file,
+                      annotations,
+                      static_values,
+                      class_data);
+}
+
+}  // namespace
+
+Header* DexIrBuilder(const DexFile& dex_file) {
+  const DexFile::Header& disk_header = dex_file.GetHeader();
+  Header* header = new Header(disk_header.magic_,
+                              disk_header.checksum_,
+                              disk_header.signature_,
+                              disk_header.endian_tag_,
+                              disk_header.file_size_,
+                              disk_header.header_size_,
+                              disk_header.link_size_,
+                              disk_header.link_off_,
+                              disk_header.data_size_,
+                              disk_header.data_off_);
+  // Walk the rest of the header fields.
+  // StringId table.
+  std::vector<std::unique_ptr<StringId>>& string_ids = header->StringIds();
+  header->SetStringIdsOffset(disk_header.string_ids_off_);
+  for (uint32_t i = 0; i < dex_file.NumStringIds(); ++i) {
+    const DexFile::StringId& disk_string_id = dex_file.GetStringId(i);
+    StringId* string_id = new StringId(dex_file.GetStringData(disk_string_id));
+    string_id->SetOffset(i);
+    string_ids.push_back(std::unique_ptr<StringId>(string_id));
+  }
+  // TypeId table.
+  std::vector<std::unique_ptr<TypeId>>& type_ids = header->TypeIds();
+  header->SetTypeIdsOffset(disk_header.type_ids_off_);
+  for (uint32_t i = 0; i < dex_file.NumTypeIds(); ++i) {
+    const DexFile::TypeId& disk_type_id = dex_file.GetTypeId(i);
+    TypeId* type_id = new TypeId(header->StringIds()[disk_type_id.descriptor_idx_].get());
+    type_id->SetOffset(i);
+    type_ids.push_back(std::unique_ptr<TypeId>(type_id));
+  }
+  // ProtoId table.
+  std::vector<std::unique_ptr<ProtoId>>& proto_ids = header->ProtoIds();
+  header->SetProtoIdsOffset(disk_header.proto_ids_off_);
+  for (uint32_t i = 0; i < dex_file.NumProtoIds(); ++i) {
+    const DexFile::ProtoId& disk_proto_id = dex_file.GetProtoId(i);
+    // Build the parameter type vector.
+    TypeIdVector* parameters = new TypeIdVector();
+    DexFileParameterIterator dfpi(dex_file, disk_proto_id);
+    while (dfpi.HasNext()) {
+      parameters->push_back(header->TypeIds()[dfpi.GetTypeIdx()].get());
+      dfpi.Next();
+    }
+    ProtoId* proto_id = new ProtoId(header->StringIds()[disk_proto_id.shorty_idx_].get(),
+                                    header->TypeIds()[disk_proto_id.return_type_idx_].get(),
+                                    parameters);
+    proto_id->SetOffset(i);
+    proto_ids.push_back(std::unique_ptr<ProtoId>(proto_id));
+  }
+  // FieldId table.
+  std::vector<std::unique_ptr<FieldId>>& field_ids = header->FieldIds();
+  header->SetFieldIdsOffset(disk_header.field_ids_off_);
+  for (uint32_t i = 0; i < dex_file.NumFieldIds(); ++i) {
+    const DexFile::FieldId& disk_field_id = dex_file.GetFieldId(i);
+    FieldId* field_id = new FieldId(header->TypeIds()[disk_field_id.class_idx_].get(),
+                                    header->TypeIds()[disk_field_id.type_idx_].get(),
+                                    header->StringIds()[disk_field_id.name_idx_].get());
+    field_id->SetOffset(i);
+    field_ids.push_back(std::unique_ptr<FieldId>(field_id));
+  }
+  // MethodId table.
+  std::vector<std::unique_ptr<MethodId>>& method_ids = header->MethodIds();
+  header->SetMethodIdsOffset(disk_header.method_ids_off_);
+  for (uint32_t i = 0; i < dex_file.NumMethodIds(); ++i) {
+    const DexFile::MethodId& disk_method_id = dex_file.GetMethodId(i);
+    MethodId* method_id = new MethodId(header->TypeIds()[disk_method_id.class_idx_].get(),
+                                       header->ProtoIds()[disk_method_id.proto_idx_].get(),
+                                       header->StringIds()[disk_method_id.name_idx_].get());
+    method_id->SetOffset(i);
+    method_ids.push_back(std::unique_ptr<MethodId>(method_id));
+  }
+  // ClassDef table.
+  std::vector<std::unique_ptr<ClassDef>>& class_defs = header->ClassDefs();
+  header->SetClassDefsOffset(disk_header.class_defs_off_);
+  for (uint32_t i = 0; i < dex_file.NumClassDefs(); ++i) {
+    const DexFile::ClassDef& disk_class_def = dex_file.GetClassDef(i);
+    ClassDef* class_def = ReadClassDef(dex_file, disk_class_def, *header);
+    class_def->SetOffset(i);
+    class_defs.push_back(std::unique_ptr<ClassDef>(class_def));
+  }
+
+  return header;
+}
+
+}  // namespace dex_ir
+}  // namespace art
diff --git a/dexlayout/dex_ir_builder.h b/dexlayout/dex_ir_builder.h
new file mode 100644
index 0000000..c53157b
--- /dev/null
+++ b/dexlayout/dex_ir_builder.h
@@ -0,0 +1,32 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ * Header file of an in-memory representation of DEX files.
+ */
+
+#ifndef ART_DEXLAYOUT_DEX_IR_BUILDER_H_
+#define ART_DEXLAYOUT_DEX_IR_BUILDER_H_
+
+#include "dex_ir.h"
+
+namespace art {
+namespace dex_ir {
+
+dex_ir::Header* DexIrBuilder(const DexFile& dex_file);
+
+}  // namespace dex_ir
+}  // namespace art
+
+#endif  // ART_DEXLAYOUT_DEX_IR_BUILDER_H_
diff --git a/dexlayout/dexlayout.cc b/dexlayout/dexlayout.cc
index 0b31614..3a3f417 100644
--- a/dexlayout/dexlayout.cc
+++ b/dexlayout/dexlayout.cc
@@ -30,7 +30,7 @@
 #include <sstream>
 #include <vector>
 
-#include "dex_ir.h"
+#include "dex_ir_builder.h"
 #include "dex_file-inl.h"
 #include "dex_instruction-inl.h"
 #include "utils.h"
@@ -501,20 +501,33 @@
   }
   fprintf(out_file_, "annotations_off     : %d (0x%06x)\n",
           annotations_offset, annotations_offset);
-  fprintf(out_file_, "class_data_off      : %d (0x%06x)\n",
-          class_def->GetClassData()->GetOffset(), class_def->GetClassData()->GetOffset());
+  if (class_def->GetClassData() == nullptr) {
+    fprintf(out_file_, "class_data_off      : %d (0x%06x)\n", 0, 0);
+  } else {
+    fprintf(out_file_, "class_data_off      : %d (0x%06x)\n",
+            class_def->GetClassData()->GetOffset(), class_def->GetClassData()->GetOffset());
+  }
 
   // Fields and methods.
   dex_ir::ClassData* class_data = class_def->GetClassData();
-  if (class_data != nullptr) {
-    fprintf(out_file_, "static_fields_size  : %zu\n", class_data->StaticFields().size());
-    fprintf(out_file_, "instance_fields_size: %zu\n", class_data->InstanceFields().size());
-    fprintf(out_file_, "direct_methods_size : %zu\n", class_data->DirectMethods().size());
-    fprintf(out_file_, "virtual_methods_size: %zu\n", class_data->VirtualMethods().size());
+  if (class_data != nullptr && class_data->StaticFields() != nullptr) {
+    fprintf(out_file_, "static_fields_size  : %zu\n", class_data->StaticFields()->size());
   } else {
     fprintf(out_file_, "static_fields_size  : 0\n");
+  }
+  if (class_data != nullptr && class_data->InstanceFields() != nullptr) {
+    fprintf(out_file_, "instance_fields_size: %zu\n", class_data->InstanceFields()->size());
+  } else {
     fprintf(out_file_, "instance_fields_size: 0\n");
+  }
+  if (class_data != nullptr && class_data->DirectMethods() != nullptr) {
+    fprintf(out_file_, "direct_methods_size : %zu\n", class_data->DirectMethods()->size());
+  } else {
     fprintf(out_file_, "direct_methods_size : 0\n");
+  }
+  if (class_data != nullptr && class_data->VirtualMethods() != nullptr) {
+    fprintf(out_file_, "virtual_methods_size: %zu\n", class_data->VirtualMethods()->size());
+  } else {
     fprintf(out_file_, "virtual_methods_size: 0\n");
   }
   fprintf(out_file_, "\n");
@@ -524,12 +537,11 @@
  * Dumps an annotation set item.
  */
 static void DumpAnnotationSetItem(dex_ir::AnnotationSetItem* set_item) {
-  if (set_item == nullptr || set_item->GetItems().size() == 0) {
+  if (set_item == nullptr || set_item->GetItems()->size() == 0) {
     fputs("  empty-annotation-set\n", out_file_);
     return;
   }
-  for (std::unique_ptr<dex_ir::AnnotationSetItem::AnnotationItem>& annotation :
-       set_item->GetItems()) {
+  for (std::unique_ptr<dex_ir::AnnotationItem>& annotation : *set_item->GetItems()) {
     if (annotation == nullptr) {
       continue;
     }
@@ -561,12 +573,9 @@
   fprintf(out_file_, "Class #%d annotations:\n", idx);
 
   dex_ir::AnnotationSetItem* class_set_item = annotations_directory->GetClassAnnotation();
-  std::vector<std::unique_ptr<dex_ir::AnnotationsDirectoryItem::FieldAnnotation>>& fields =
-      annotations_directory->GetFieldAnnotations();
-  std::vector<std::unique_ptr<dex_ir::AnnotationsDirectoryItem::MethodAnnotation>>& methods =
-      annotations_directory->GetMethodAnnotations();
-  std::vector<std::unique_ptr<dex_ir::AnnotationsDirectoryItem::ParameterAnnotation>>& parameters =
-      annotations_directory->GetParameterAnnotations();
+  dex_ir::FieldAnnotationVector* fields = annotations_directory->GetFieldAnnotations();
+  dex_ir::MethodAnnotationVector* methods = annotations_directory->GetMethodAnnotations();
+  dex_ir::ParameterAnnotationVector* parameters = annotations_directory->GetParameterAnnotations();
 
   // Annotations on the class itself.
   if (class_set_item != nullptr) {
@@ -575,34 +584,40 @@
   }
 
   // Annotations on fields.
-  for (auto& field : fields) {
-    const dex_ir::FieldId* field_id = field->GetFieldId();
-    const uint32_t field_idx = field_id->GetOffset();
-    const char* field_name = field_id->Name()->Data();
-    fprintf(out_file_, "Annotations on field #%u '%s'\n", field_idx, field_name);
-    DumpAnnotationSetItem(field->GetAnnotationSetItem());
+  if (fields != nullptr) {
+    for (auto& field : *fields) {
+      const dex_ir::FieldId* field_id = field->GetFieldId();
+      const uint32_t field_idx = field_id->GetOffset();
+      const char* field_name = field_id->Name()->Data();
+      fprintf(out_file_, "Annotations on field #%u '%s'\n", field_idx, field_name);
+      DumpAnnotationSetItem(field->GetAnnotationSetItem());
+    }
   }
 
   // Annotations on methods.
-  for (auto& method : methods) {
-    const dex_ir::MethodId* method_id = method->GetMethodId();
-    const uint32_t method_idx = method_id->GetOffset();
-    const char* method_name = method_id->Name()->Data();
-    fprintf(out_file_, "Annotations on method #%u '%s'\n", method_idx, method_name);
-    DumpAnnotationSetItem(method->GetAnnotationSetItem());
+  if (methods != nullptr) {
+    for (auto& method : *methods) {
+      const dex_ir::MethodId* method_id = method->GetMethodId();
+      const uint32_t method_idx = method_id->GetOffset();
+      const char* method_name = method_id->Name()->Data();
+      fprintf(out_file_, "Annotations on method #%u '%s'\n", method_idx, method_name);
+      DumpAnnotationSetItem(method->GetAnnotationSetItem());
+    }
   }
 
   // Annotations on method parameters.
-  for (auto& parameter : parameters) {
-    const dex_ir::MethodId* method_id = parameter->GetMethodId();
-    const uint32_t method_idx = method_id->GetOffset();
-    const char* method_name = method_id->Name()->Data();
-    fprintf(out_file_, "Annotations on method #%u '%s' parameters\n", method_idx, method_name);
-    uint32_t j = 0;
-    for (auto& annotation : parameter->GetAnnotations()) {
-      fprintf(out_file_, "#%u\n", j);
-      DumpAnnotationSetItem(annotation.get());
-      ++j;
+  if (parameters != nullptr) {
+    for (auto& parameter : *parameters) {
+      const dex_ir::MethodId* method_id = parameter->GetMethodId();
+      const uint32_t method_idx = method_id->GetOffset();
+      const char* method_name = method_id->Name()->Data();
+      fprintf(out_file_, "Annotations on method #%u '%s' parameters\n", method_idx, method_name);
+      uint32_t j = 0;
+      for (auto& annotation : *parameter->GetAnnotations()) {
+        fprintf(out_file_, "#%u\n", j);
+        DumpAnnotationSetItem(annotation.get());
+        ++j;
+      }
     }
   }
 
@@ -612,7 +627,7 @@
 /*
  * Dumps an interface that a class declares to implement.
  */
-static void DumpInterface(dex_ir::TypeId* type_item, int i) {
+static void DumpInterface(const dex_ir::TypeId* type_item, int i) {
   const char* interface_name = type_item->GetStringId()->Data();
   if (options_.output_format_ == kOutputPlain) {
     fprintf(out_file_, "    #%d              : '%s'\n", i, interface_name);
@@ -752,10 +767,10 @@
       if (index < header->MethodIdsSize()) {
         dex_ir::MethodId* method_id = header->MethodIds()[index].get();
         const char* name = method_id->Name()->Data();
-        char* type_descriptor = strdup(GetSignatureForProtoId(method_id->Proto()).c_str());
+        std::string type_descriptor = GetSignatureForProtoId(method_id->Proto());
         const char* back_descriptor = method_id->Class()->GetStringId()->Data();
         outSize = snprintf(buf.get(), buf_size, "%s.%s:%s // method@%0*x",
-                           back_descriptor, name, type_descriptor, width, index);
+                           back_descriptor, name, type_descriptor.c_str(), width, index);
       } else {
         outSize = snprintf(buf.get(), buf_size, "<method?> // method@%0*x", width, index);
       }
@@ -1015,13 +1030,13 @@
                           const dex_ir::CodeItem* code, uint32_t code_offset) {
   dex_ir::MethodId* method_id = header->MethodIds()[idx].get();
   const char* name = method_id->Name()->Data();
-  const char* type_descriptor = strdup(GetSignatureForProtoId(method_id->Proto()).c_str());
+  std::string type_descriptor = GetSignatureForProtoId(method_id->Proto());
   const char* back_descriptor = method_id->Class()->GetStringId()->Data();
 
   // Generate header.
   std::string dot(DescriptorToDotWrapper(back_descriptor));
   fprintf(out_file_, "%06x:                                        |[%06x] %s.%s:%s\n",
-          code_offset, code_offset, dot.c_str(), name, type_descriptor);
+          code_offset, code_offset, dot.c_str(), name, type_descriptor.c_str());
 
   // Iterate over all instructions.
   const uint16_t* insns = code->Insns();
@@ -1260,8 +1275,8 @@
   }
   while (it.HasNextVirtualMethod()) {
     DumpCFG(dex_file,
-                it.GetMemberIndex(),
-                it.GetMethodCodeItem());
+            it.GetMemberIndex(),
+            it.GetMethodCodeItem());
     it.Next();
   }
 }
@@ -1274,7 +1289,10 @@
  * If "*last_package" is nullptr or does not match the current class' package,
  * the value will be replaced with a newly-allocated string.
  */
-static void DumpClass(dex_ir::Header* header, int idx, char** last_package) {
+static void DumpClass(const DexFile* dex_file,
+                      dex_ir::Header* header,
+                      int idx,
+                      char** last_package) {
   dex_ir::ClassDef* class_def = header->ClassDefs()[idx].get();
   // Omitting non-public class.
   if (options_.exports_only_ && (class_def->GetAccessFlags() & kAccPublic) == 0) {
@@ -1290,7 +1308,7 @@
   }
 
   if (options_.show_cfg_) {
-    DumpCFG(&header->GetDexFile(), idx);
+    DumpCFG(dex_file, idx);
     return;
   }
 
@@ -1368,10 +1386,12 @@
   }
 
   // Interfaces.
-  std::vector<dex_ir::TypeId*>* interfaces = class_def->Interfaces();
-  for (uint32_t i = 0; i < interfaces->size(); i++) {
-    DumpInterface((*interfaces)[i], i);
-  }  // for
+  dex_ir::TypeIdVector* interfaces = class_def->Interfaces();
+  if (interfaces != nullptr) {
+    for (uint32_t i = 0; i < interfaces->size(); i++) {
+      DumpInterface((*interfaces)[i], i);
+    }  // for
+  }
 
   // Fields and methods.
   dex_ir::ClassData* class_data = class_def->GetClassData();
@@ -1383,52 +1403,68 @@
   if (options_.output_format_ == kOutputPlain) {
     fprintf(out_file_, "  Static fields     -\n");
   }
-  std::vector<std::unique_ptr<dex_ir::FieldItem>>& static_fields = class_data->StaticFields();
-  for (uint32_t i = 0; i < static_fields.size(); i++) {
-    DumpSField(header,
-               static_fields[i]->GetFieldId()->GetOffset(),
-               static_fields[i]->GetAccessFlags(),
-               i,
-               i < static_values_size ? (*static_values)[i].get() : nullptr);
-  }  // for
+  if (class_data != nullptr) {
+    dex_ir::FieldItemVector* static_fields = class_data->StaticFields();
+    if (static_fields != nullptr) {
+      for (uint32_t i = 0; i < static_fields->size(); i++) {
+        DumpSField(header,
+                   (*static_fields)[i]->GetFieldId()->GetOffset(),
+                   (*static_fields)[i]->GetAccessFlags(),
+                   i,
+                   i < static_values_size ? (*static_values)[i].get() : nullptr);
+      }  // for
+    }
+  }
 
   // Instance fields.
   if (options_.output_format_ == kOutputPlain) {
     fprintf(out_file_, "  Instance fields   -\n");
   }
-  std::vector<std::unique_ptr<dex_ir::FieldItem>>& instance_fields = class_data->InstanceFields();
-  for (uint32_t i = 0; i < instance_fields.size(); i++) {
-    DumpIField(header,
-               instance_fields[i]->GetFieldId()->GetOffset(),
-               instance_fields[i]->GetAccessFlags(),
-               i);
-  }  // for
+  if (class_data != nullptr) {
+    dex_ir::FieldItemVector* instance_fields = class_data->InstanceFields();
+    if (instance_fields != nullptr) {
+      for (uint32_t i = 0; i < instance_fields->size(); i++) {
+        DumpIField(header,
+                   (*instance_fields)[i]->GetFieldId()->GetOffset(),
+                   (*instance_fields)[i]->GetAccessFlags(),
+                   i);
+      }  // for
+    }
+  }
 
   // Direct methods.
   if (options_.output_format_ == kOutputPlain) {
     fprintf(out_file_, "  Direct methods    -\n");
   }
-  std::vector<std::unique_ptr<dex_ir::MethodItem>>& direct_methods = class_data->DirectMethods();
-  for (uint32_t i = 0; i < direct_methods.size(); i++) {
-    DumpMethod(header,
-               direct_methods[i]->GetMethodId()->GetOffset(),
-               direct_methods[i]->GetAccessFlags(),
-               direct_methods[i]->GetCodeItem(),
-               i);
-  }  // for
+  if (class_data != nullptr) {
+    dex_ir::MethodItemVector* direct_methods = class_data->DirectMethods();
+    if (direct_methods != nullptr) {
+      for (uint32_t i = 0; i < direct_methods->size(); i++) {
+        DumpMethod(header,
+                   (*direct_methods)[i]->GetMethodId()->GetOffset(),
+                   (*direct_methods)[i]->GetAccessFlags(),
+                   (*direct_methods)[i]->GetCodeItem(),
+                 i);
+      }  // for
+    }
+  }
 
   // Virtual methods.
   if (options_.output_format_ == kOutputPlain) {
     fprintf(out_file_, "  Virtual methods   -\n");
   }
-  std::vector<std::unique_ptr<dex_ir::MethodItem>>& virtual_methods = class_data->VirtualMethods();
-  for (uint32_t i = 0; i < virtual_methods.size(); i++) {
-    DumpMethod(header,
-               virtual_methods[i]->GetMethodId()->GetOffset(),
-               virtual_methods[i]->GetAccessFlags(),
-               virtual_methods[i]->GetCodeItem(),
-               i);
-  }  // for
+  if (class_data != nullptr) {
+    dex_ir::MethodItemVector* virtual_methods = class_data->VirtualMethods();
+    if (virtual_methods != nullptr) {
+      for (uint32_t i = 0; i < virtual_methods->size(); i++) {
+        DumpMethod(header,
+                   (*virtual_methods)[i]->GetMethodId()->GetOffset(),
+                   (*virtual_methods)[i]->GetAccessFlags(),
+                   (*virtual_methods)[i]->GetCodeItem(),
+                   i);
+      }  // for
+    }
+  }
 
   // End of class.
   if (options_.output_format_ == kOutputPlain) {
@@ -1454,11 +1490,11 @@
     fprintf(out_file_, "Opened '%s', DEX version '%.3s'\n",
             file_name, dex_file->GetHeader().magic_ + 4);
   }
-  dex_ir::Header header(*dex_file);
+  std::unique_ptr<dex_ir::Header> header(dex_ir::DexIrBuilder(*dex_file));
 
   // Headers.
   if (options_.show_file_headers_) {
-    DumpFileHeader(&header);
+    DumpFileHeader(header.get());
   }
 
   // Open XML context.
@@ -1468,9 +1504,9 @@
 
   // Iterate over all classes.
   char* package = nullptr;
-  const uint32_t class_defs_size = header.ClassDefsSize();
+  const uint32_t class_defs_size = header->ClassDefsSize();
   for (uint32_t i = 0; i < class_defs_size; i++) {
-    DumpClass(&header, i, &package);
+    DumpClass(dex_file, header.get(), i, &package);
   }  // for
 
   // Free the last package allocated.
diff --git a/dexlist/Android.bp b/dexlist/Android.bp
new file mode 100644
index 0000000..8e3c91d
--- /dev/null
+++ b/dexlist/Android.bp
@@ -0,0 +1,21 @@
+// Copyright (C) 2015 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_binary {
+    name: "dexlist",
+    host_supported: true,
+    srcs: ["dexlist.cc"],
+    cflags: ["-Wall"],
+    shared_libs: ["libart"],
+}
diff --git a/dexlist/Android.mk b/dexlist/Android.mk
deleted file mode 100755
index 6ec6c97..0000000
--- a/dexlist/Android.mk
+++ /dev/null
@@ -1,52 +0,0 @@
-# Copyright (C) 2015 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.
-
-# TODO(ajcbik): Art-i-fy this makefile
-
-LOCAL_PATH:= $(call my-dir)
-
-dexlist_src_files := dexlist.cc
-dexlist_c_includes := art/runtime
-dexlist_libraries := libart
-
-##
-## Build the device command line tool dexlist.
-##
-
-ifneq ($(SDK_ONLY),true)  # SDK_only doesn't need device version
-include $(CLEAR_VARS)
-LOCAL_CPP_EXTENSION := cc
-LOCAL_SRC_FILES := $(dexlist_src_files)
-LOCAL_C_INCLUDES := $(dexlist_c_includes)
-LOCAL_CFLAGS += -Wall
-LOCAL_SHARED_LIBRARIES += $(dexlist_libraries)
-LOCAL_MODULE := dexlist
-LOCAL_MODULE_TAGS := optional
-LOCAL_MODULE_PATH := $(TARGET_OUT_OPTIONAL_EXECUTABLES)
-include $(BUILD_EXECUTABLE)
-endif # !SDK_ONLY
-
-##
-## Build the host command line tool dexlist.
-##
-
-include $(CLEAR_VARS)
-LOCAL_CPP_EXTENSION := cc
-LOCAL_SRC_FILES := $(dexlist_src_files)
-LOCAL_C_INCLUDES := $(dexlist_c_includes)
-LOCAL_CFLAGS += -Wall
-LOCAL_SHARED_LIBRARIES += $(dexlist_libraries)
-LOCAL_MODULE := dexlist
-LOCAL_MULTILIB := $(ART_MULTILIB_OVERRIDE_host)
-include $(BUILD_HOST_EXECUTABLE)
diff --git a/disassembler/Android.bp b/disassembler/Android.bp
new file mode 100644
index 0000000..d06e4de
--- /dev/null
+++ b/disassembler/Android.bp
@@ -0,0 +1,58 @@
+//
+// Copyright (C) 2012 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: "libart-disassembler-defaults",
+    defaults: ["art_defaults"],
+    host_supported: true,
+    clang: true,
+    srcs: [
+        "disassembler.cc",
+        "disassembler_arm.cc",
+        "disassembler_arm64.cc",
+        "disassembler_mips.cc",
+        "disassembler_x86.cc",
+    ],
+
+    shared_libs: [
+        "liblog",
+        "libbase",
+    ],
+    export_include_dirs: ["."],
+}
+
+art_cc_library {
+    name: "libart-disassembler",
+    defaults: ["libart-disassembler-defaults"],
+    shared_libs: [
+        "libart",
+        // For disassembler_arm64.
+        "libvixld-arm64",
+    ],
+}
+
+art_cc_library {
+    name: "libartd-disassembler",
+    defaults: [
+        "libart-disassembler-defaults",
+        "art_debug_defaults",
+    ],
+    shared_libs: [
+        "libartd",
+        // For disassembler_arm64.
+        "libvixld-arm64",
+    ],
+}
diff --git a/disassembler/Android.mk b/disassembler/Android.mk
deleted file mode 100644
index db327fc..0000000
--- a/disassembler/Android.mk
+++ /dev/null
@@ -1,116 +0,0 @@
-#
-# Copyright (C) 2012 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.common_build.mk
-
-LIBART_DISASSEMBLER_SRC_FILES := \
-	disassembler.cc \
-	disassembler_arm.cc \
-	disassembler_arm64.cc \
-	disassembler_mips.cc \
-	disassembler_x86.cc
-
-# $(1): target or host
-# $(2): ndebug or debug
-define build-libart-disassembler
-  ifneq ($(1),target)
-    ifneq ($(1),host)
-      $$(error expected target or host for argument 1, received $(1))
-    endif
-  endif
-  ifneq ($(2),ndebug)
-    ifneq ($(2),debug)
-      $$(error expected ndebug or debug for argument 2, received $(2))
-    endif
-  endif
-
-  art_target_or_host := $(1)
-  art_ndebug_or_debug := $(2)
-
-  include $(CLEAR_VARS)
-  ifeq ($$(art_target_or_host),host)
-     LOCAL_IS_HOST_MODULE := true
-  endif
-  LOCAL_CPP_EXTENSION := $(ART_CPP_EXTENSION)
-  ifeq ($$(art_ndebug_or_debug),ndebug)
-    LOCAL_MODULE := libart-disassembler
-  else # debug
-    LOCAL_MODULE := libartd-disassembler
-  endif
-
-  LOCAL_MODULE_TAGS := optional
-  LOCAL_MODULE_CLASS := SHARED_LIBRARIES
-
-  LOCAL_SRC_FILES := $$(LIBART_DISASSEMBLER_SRC_FILES)
-
-  ifeq ($$(art_target_or_host),target)
-    LOCAL_CLANG := $(ART_TARGET_CLANG)
-    $(call set-target-local-cflags-vars,$(2))
-  else # host
-    LOCAL_CLANG := $(ART_HOST_CLANG)
-    LOCAL_CFLAGS += $(ART_HOST_CFLAGS)
-    LOCAL_ASFLAGS += $(ART_HOST_ASFLAGS)
-    ifeq ($$(art_ndebug_or_debug),debug)
-      LOCAL_CFLAGS += $(ART_HOST_DEBUG_CFLAGS)
-      LOCAL_ASFLAGS += $(ART_HOST_DEBUG_ASFLAGS)
-    else
-      LOCAL_CFLAGS += $(ART_HOST_NON_DEBUG_CFLAGS)
-      LOCAL_ASFLAGS += $(ART_HOST_NON_DEBUG_ASFLAGS)
-    endif
-  endif
-
-  LOCAL_SHARED_LIBRARIES += liblog
-  ifeq ($$(art_ndebug_or_debug),debug)
-    LOCAL_SHARED_LIBRARIES += libartd
-  else
-    LOCAL_SHARED_LIBRARIES += libart
-  endif
-
-  LOCAL_C_INCLUDES += $(ART_C_INCLUDES) art/runtime
-  LOCAL_EXPORT_C_INCLUDE_DIRS := $(LOCAL_PATH)
-  LOCAL_MULTILIB := both
-
-  LOCAL_ADDITIONAL_DEPENDENCIES := art/build/Android.common_build.mk
-  LOCAL_ADDITIONAL_DEPENDENCIES += $(LOCAL_PATH)/Android.mk
-  LOCAL_NATIVE_COVERAGE := $(ART_COVERAGE)
-  # For disassembler_arm64.
-  ifeq ($$(art_ndebug_or_debug),debug)
-    LOCAL_SHARED_LIBRARIES += libvixld-arm64
-  else
-    LOCAL_SHARED_LIBRARIES += libvixl-arm64
-  endif
-  ifeq ($$(art_target_or_host),target)
-    include $(BUILD_SHARED_LIBRARY)
-  else # host
-    include $(BUILD_HOST_SHARED_LIBRARY)
-  endif
-endef
-
-ifeq ($(ART_BUILD_TARGET_NDEBUG),true)
-  $(eval $(call build-libart-disassembler,target,ndebug))
-endif
-ifeq ($(ART_BUILD_TARGET_DEBUG),true)
-  $(eval $(call build-libart-disassembler,target,debug))
-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-libart-disassembler,host,ndebug))
-endif
-ifeq ($(ART_BUILD_HOST_DEBUG),true)
-  $(eval $(call build-libart-disassembler,host,debug))
-endif
diff --git a/disassembler/disassembler.cc b/disassembler/disassembler.cc
index bcd0d16..8eecc62 100644
--- a/disassembler/disassembler.cc
+++ b/disassembler/disassembler.cc
@@ -18,15 +18,23 @@
 
 #include <ostream>
 
-#include "base/logging.h"
-#include "base/stringprintf.h"
+#include "android-base/logging.h"
+#include "android-base/stringprintf.h"
+
 #include "disassembler_arm.h"
 #include "disassembler_arm64.h"
 #include "disassembler_mips.h"
 #include "disassembler_x86.h"
 
+using android::base::StringPrintf;
+
 namespace art {
 
+Disassembler::Disassembler(DisassemblerOptions* disassembler_options)
+    : disassembler_options_(disassembler_options) {
+  CHECK(disassembler_options_ != nullptr);
+}
+
 Disassembler* Disassembler::Create(InstructionSet instruction_set, DisassemblerOptions* options) {
   if (instruction_set == kArm || instruction_set == kThumb2) {
     return new arm::DisassemblerArm(options);
@@ -39,7 +47,7 @@
   } else if (instruction_set == kX86_64) {
     return new x86::DisassemblerX86(options, true);
   } else {
-    UNIMPLEMENTED(FATAL) << "no disassembler for " << instruction_set;
+    UNIMPLEMENTED(FATAL) << static_cast<uint32_t>(instruction_set);
     return nullptr;
   }
 }
diff --git a/disassembler/disassembler.h b/disassembler/disassembler.h
index 86793cc..1ef456c 100644
--- a/disassembler/disassembler.h
+++ b/disassembler/disassembler.h
@@ -21,8 +21,9 @@
 
 #include <iosfwd>
 
+#include "android-base/macros.h"
+
 #include "arch/instruction_set.h"
-#include "base/macros.h"
 
 namespace art {
 
@@ -81,10 +82,7 @@
   }
 
  protected:
-  explicit Disassembler(DisassemblerOptions* disassembler_options)
-      : disassembler_options_(disassembler_options) {
-    CHECK(disassembler_options_ != nullptr);
-  }
+  explicit Disassembler(DisassemblerOptions* disassembler_options);
 
   std::string FormatInstructionPointer(const uint8_t* begin);
 
diff --git a/disassembler/disassembler_arm.cc b/disassembler/disassembler_arm.cc
index a47b6ad..c3e288d 100644
--- a/disassembler/disassembler_arm.cc
+++ b/disassembler/disassembler_arm.cc
@@ -21,10 +21,13 @@
 #include <ostream>
 #include <sstream>
 
+#include "android-base/logging.h"
+#include "android-base/stringprintf.h"
+
 #include "arch/arm/registers_arm.h"
 #include "base/bit_utils.h"
-#include "base/logging.h"
-#include "base/stringprintf.h"
+
+using android::base::StringPrintf;
 
 namespace art {
 namespace arm {
diff --git a/disassembler/disassembler_arm64.cc b/disassembler/disassembler_arm64.cc
index 80bacb2..49b9623 100644
--- a/disassembler/disassembler_arm64.cc
+++ b/disassembler/disassembler_arm64.cc
@@ -20,8 +20,10 @@
 
 #include <sstream>
 
-#include "base/logging.h"
-#include "base/stringprintf.h"
+#include "android-base/logging.h"
+#include "android-base/stringprintf.h"
+
+using android::base::StringPrintf;
 
 using namespace vixl::aarch64;  // NOLINT(build/namespaces)
 
diff --git a/disassembler/disassembler_mips.cc b/disassembler/disassembler_mips.cc
index 02c6d71..9a73f29 100644
--- a/disassembler/disassembler_mips.cc
+++ b/disassembler/disassembler_mips.cc
@@ -19,8 +19,10 @@
 #include <ostream>
 #include <sstream>
 
-#include "base/logging.h"
-#include "base/stringprintf.h"
+#include "android-base/logging.h"
+#include "android-base/stringprintf.h"
+
+using android::base::StringPrintf;
 
 namespace art {
 namespace mips {
diff --git a/disassembler/disassembler_x86.cc b/disassembler/disassembler_x86.cc
index 2ca84e5..9f49ec6 100644
--- a/disassembler/disassembler_x86.cc
+++ b/disassembler/disassembler_x86.cc
@@ -21,8 +21,10 @@
 #include <ostream>
 #include <sstream>
 
-#include "base/logging.h"
-#include "base/stringprintf.h"
+#include "android-base/logging.h"
+#include "android-base/stringprintf.h"
+
+using android::base::StringPrintf;
 
 namespace art {
 namespace x86 {
diff --git a/oatdump/Android.bp b/oatdump/Android.bp
new file mode 100644
index 0000000..b01bf51
--- /dev/null
+++ b/oatdump/Android.bp
@@ -0,0 +1,89 @@
+//
+// 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: "oatdump-defaults",
+    defaults: ["art_defaults"],
+    host_supported: true,
+    srcs: ["oatdump.cc"],
+    target: {
+        android: {
+            shared_libs: ["libcutils"],
+        },
+    },
+    include_dirs: ["art/cmdline"],
+}
+
+art_cc_binary {
+    name: "oatdump",
+    defaults: ["oatdump-defaults"],
+    shared_libs: [
+        "libart",
+        "libart-compiler",
+        "libart-disassembler",
+    ],
+}
+
+art_cc_binary {
+    name: "oatdumpd",
+    defaults: [
+        "art_debug_defaults",
+        "oatdump-defaults",
+    ],
+    shared_libs: [
+        "libartd",
+        "libartd-compiler",
+        "libartd-disassembler",
+    ],
+}
+
+art_cc_binary {
+    name: "oatdumps",
+    defaults: ["oatdump-defaults"],
+    target: {
+        darwin: {
+            enabled: false,
+        },
+    },
+    static_libs: [
+        "libart",
+        "libart-compiler",
+        "libart-disassembler",
+        "libvixl-arm",
+        "libvixl-arm64",
+    ] + art_static_dependencies,
+}
+
+art_cc_binary {
+    name: "oatdumpds",
+    defaults: [
+        "art_debug_defaults",
+        "oatdump-defaults",
+    ],
+    target: {
+        darwin: {
+            enabled: false,
+        },
+    },
+    static_libs: [
+        "libartd",
+        "libartd-compiler",
+        "libartd-disassembler",
+        "libvixld-arm",
+        "libvixld-arm64",
+    ] + art_static_dependencies,
+}
+
diff --git a/oatdump/Android.mk b/oatdump/Android.mk
index 5c75f20..7be8a8d 100644
--- a/oatdump/Android.mk
+++ b/oatdump/Android.mk
@@ -16,19 +16,6 @@
 
 LOCAL_PATH := $(call my-dir)
 
-include art/build/Android.executable.mk
-
-OATDUMP_SRC_FILES := \
-	oatdump.cc
-
-# Build variants {target,host} x {debug,ndebug}
-$(eval $(call build-art-multi-executable,oatdump,$(OATDUMP_SRC_FILES),libart-compiler libart-disassembler,libcutils,,art/compiler art/disassembler))
-
-########################################################################
-# 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_test.cc b/oatdump/oatdump_test.cc
index db97055..22db818 100644
--- a/oatdump/oatdump_test.cc
+++ b/oatdump/oatdump_test.cc
@@ -42,13 +42,22 @@
     core_oat_location_ = GetSystemImageFilename(GetCoreOatLocation().c_str(), kRuntimeISA);
   }
 
+  // Linking flavor.
+  enum Flavor {
+    kDynamic,  // oatdump(d)
+    kStatic,   // oatdump(d)s
+  };
+
   // Returns path to the oatdump binary.
-  std::string GetOatDumpFilePath() {
+  std::string GetOatDumpFilePath(Flavor flavor) {
     std::string root = GetTestAndroidRoot();
     root += "/bin/oatdump";
     if (kIsDebugBuild) {
       root += "d";
     }
+    if (flavor == kStatic) {
+      root += "s";
+    }
     return root;
   }
 
@@ -58,12 +67,19 @@
     kModeSymbolize,
   };
 
+  // Display style.
+  enum Display {
+    kListOnly,
+    kListAndCode
+  };
+
   // Run the test with custom arguments.
-  bool Exec(Mode mode,
+  bool Exec(Flavor flavor,
+            Mode mode,
             const std::vector<std::string>& args,
-            bool list_only,
+            Display display,
             std::string* error_msg) {
-    std::string file_path = GetOatDumpFilePath();
+    std::string file_path = GetOatDumpFilePath(flavor);
 
     EXPECT_TRUE(OS::FileExists(file_path.c_str())) << file_path << " should be a valid file path";
 
@@ -81,7 +97,7 @@
       expected_prefixes.push_back("LOCATION:");
       expected_prefixes.push_back("MAGIC:");
       expected_prefixes.push_back("DEX FILE COUNT:");
-      if (!list_only) {
+      if (display == kListAndCode) {
         // Code and dex code do not show up if list only.
         expected_prefixes.push_back("DEX CODE:");
         expected_prefixes.push_back("CODE:");
@@ -205,37 +221,73 @@
 #if !defined(__arm__) && !defined(__mips__)
 TEST_F(OatDumpTest, TestImage) {
   std::string error_msg;
-  ASSERT_TRUE(Exec(kModeArt, {}, /*list_only*/ false, &error_msg)) << error_msg;
+  ASSERT_TRUE(Exec(kDynamic, kModeArt, {}, kListAndCode, &error_msg)) << error_msg;
+}
+TEST_F(OatDumpTest, TestImageStatic) {
+  TEST_DISABLED_FOR_NON_STATIC_HOST_BUILDS();
+  std::string error_msg;
+  ASSERT_TRUE(Exec(kStatic, kModeArt, {}, kListAndCode, &error_msg)) << error_msg;
 }
 
 TEST_F(OatDumpTest, TestOatImage) {
   std::string error_msg;
-  ASSERT_TRUE(Exec(kModeOat, {}, /*list_only*/ false, &error_msg)) << error_msg;
+  ASSERT_TRUE(Exec(kDynamic, kModeOat, {}, kListAndCode, &error_msg)) << error_msg;
+}
+TEST_F(OatDumpTest, TestOatImageStatic) {
+  TEST_DISABLED_FOR_NON_STATIC_HOST_BUILDS();
+  std::string error_msg;
+  ASSERT_TRUE(Exec(kStatic, kModeOat, {}, kListAndCode, &error_msg)) << error_msg;
 }
 
 TEST_F(OatDumpTest, TestNoDumpVmap) {
   std::string error_msg;
-  ASSERT_TRUE(Exec(kModeArt, {"--no-dump:vmap"}, /*list_only*/ false, &error_msg)) << error_msg;
+  ASSERT_TRUE(Exec(kDynamic, kModeArt, {"--no-dump:vmap"}, kListAndCode, &error_msg)) << error_msg;
+}
+TEST_F(OatDumpTest, TestNoDumpVmapStatic) {
+  TEST_DISABLED_FOR_NON_STATIC_HOST_BUILDS();
+  std::string error_msg;
+  ASSERT_TRUE(Exec(kStatic, kModeArt, {"--no-dump:vmap"}, kListAndCode, &error_msg)) << error_msg;
 }
 
 TEST_F(OatDumpTest, TestNoDisassemble) {
   std::string error_msg;
-  ASSERT_TRUE(Exec(kModeArt, {"--no-disassemble"}, /*list_only*/ false, &error_msg)) << error_msg;
+  ASSERT_TRUE(Exec(kDynamic, kModeArt, {"--no-disassemble"}, kListAndCode, &error_msg))
+      << error_msg;
+}
+TEST_F(OatDumpTest, TestNoDisassembleStatic) {
+  TEST_DISABLED_FOR_NON_STATIC_HOST_BUILDS();
+  std::string error_msg;
+  ASSERT_TRUE(Exec(kStatic, kModeArt, {"--no-disassemble"}, kListAndCode, &error_msg)) << error_msg;
 }
 
 TEST_F(OatDumpTest, TestListClasses) {
   std::string error_msg;
-  ASSERT_TRUE(Exec(kModeArt, {"--list-classes"}, /*list_only*/ true, &error_msg)) << error_msg;
+  ASSERT_TRUE(Exec(kDynamic, kModeArt, {"--list-classes"}, kListOnly, &error_msg)) << error_msg;
+}
+TEST_F(OatDumpTest, TestListClassesStatic) {
+  TEST_DISABLED_FOR_NON_STATIC_HOST_BUILDS();
+  std::string error_msg;
+  ASSERT_TRUE(Exec(kStatic, kModeArt, {"--list-classes"}, kListOnly, &error_msg)) << error_msg;
 }
 
 TEST_F(OatDumpTest, TestListMethods) {
   std::string error_msg;
-  ASSERT_TRUE(Exec(kModeArt, {"--list-methods"}, /*list_only*/ true, &error_msg)) << error_msg;
+  ASSERT_TRUE(Exec(kDynamic, kModeArt, {"--list-methods"}, kListOnly, &error_msg)) << error_msg;
+}
+TEST_F(OatDumpTest, TestListMethodsStatic) {
+  TEST_DISABLED_FOR_NON_STATIC_HOST_BUILDS();
+  std::string error_msg;
+  ASSERT_TRUE(Exec(kStatic, kModeArt, {"--list-methods"}, kListOnly, &error_msg)) << error_msg;
 }
 
 TEST_F(OatDumpTest, TestSymbolize) {
   std::string error_msg;
-  ASSERT_TRUE(Exec(kModeSymbolize, {}, /*list_only*/ true, &error_msg)) << error_msg;
+  ASSERT_TRUE(Exec(kDynamic, kModeSymbolize, {}, kListOnly, &error_msg)) << error_msg;
+}
+TEST_F(OatDumpTest, TestSymbolizeStatic) {
+  TEST_DISABLED_FOR_NON_STATIC_HOST_BUILDS();
+  std::string error_msg;
+  ASSERT_TRUE(Exec(kStatic, kModeSymbolize, {}, kListOnly, &error_msg)) << error_msg;
 }
 #endif
 }  // namespace art
diff --git a/runtime/Android.bp b/runtime/Android.bp
index 22d79cb..59e4a15 100644
--- a/runtime/Android.bp
+++ b/runtime/Android.bp
@@ -97,7 +97,6 @@
         "intern_table.cc",
         "interpreter/interpreter.cc",
         "interpreter/interpreter_common.cc",
-        "interpreter/interpreter_goto_table_impl.cc",
         "interpreter/interpreter_switch_impl.cc",
         "interpreter/unstarted_runtime.cc",
         "java_vm_ext.cc",
diff --git a/runtime/arch/arm/quick_entrypoints_arm.S b/runtime/arch/arm/quick_entrypoints_arm.S
index c51c336..a3f053b 100644
--- a/runtime/arch/arm/quick_entrypoints_arm.S
+++ b/runtime/arch/arm/quick_entrypoints_arm.S
@@ -1544,7 +1544,7 @@
      */
     .extern artDeoptimizeFromCompiledCode
 ENTRY art_quick_deoptimize_from_compiled_code
-    SETUP_SAVE_ALL_CALLEE_SAVES_FRAME r0
+    SETUP_SAVE_EVERYTHING_FRAME r0
     mov    r0, r9                         @ Set up args.
     blx    artDeoptimizeFromCompiledCode  @ artDeoptimizeFromCompiledCode(Thread*)
 END art_quick_deoptimize_from_compiled_code
diff --git a/runtime/arch/arm64/quick_entrypoints_arm64.S b/runtime/arch/arm64/quick_entrypoints_arm64.S
index 03768af..e0e1e81 100644
--- a/runtime/arch/arm64/quick_entrypoints_arm64.S
+++ b/runtime/arch/arm64/quick_entrypoints_arm64.S
@@ -19,6 +19,42 @@
 #include "arch/quick_alloc_entrypoints.S"
 
 
+.macro SAVE_REG reg, offset
+    str \reg, [sp, #(\offset)]
+    .cfi_rel_offset \reg, (\offset)
+.endm
+
+.macro RESTORE_REG reg, offset
+    ldr \reg, [sp, #(\offset)]
+    .cfi_restore \reg
+.endm
+
+.macro SAVE_TWO_REGS reg1, reg2, offset
+    stp \reg1, \reg2, [sp, #(\offset)]
+    .cfi_rel_offset \reg1, (\offset)
+    .cfi_rel_offset \reg2, (\offset) + 8
+.endm
+
+.macro RESTORE_TWO_REGS reg1, reg2, offset
+    ldp \reg1, \reg2, [sp, #(\offset)]
+    .cfi_restore \reg1
+    .cfi_restore \reg2
+.endm
+
+.macro SAVE_TWO_REGS_INCREASE_FRAME reg1, reg2, frame_adjustment
+    stp \reg1, \reg2, [sp, #-(\frame_adjustment)]!
+    .cfi_adjust_cfa_offset (\frame_adjustment)
+    .cfi_rel_offset \reg1, 0
+    .cfi_rel_offset \reg2, 8
+.endm
+
+.macro RESTORE_TWO_REGS_DECREASE_FRAME reg1, reg2, frame_adjustment
+    ldp \reg1, \reg2, [sp], #(\frame_adjustment)
+    .cfi_restore \reg1
+    .cfi_restore \reg2
+    .cfi_adjust_cfa_offset -(\frame_adjustment)
+.endm
+
     /*
      * Macro that sets up the callee save frame to conform with
      * Runtime::CreateCalleeSaveMethod(kSaveAllCalleeSaves)
@@ -50,29 +86,12 @@
     stp d14, d15, [sp, #64]
 
     // GP callee-saves
-    stp x19, x20, [sp, #80]
-    .cfi_rel_offset x19, 80
-    .cfi_rel_offset x20, 88
-
-    stp x21, x22, [sp, #96]
-    .cfi_rel_offset x21, 96
-    .cfi_rel_offset x22, 104
-
-    stp x23, x24, [sp, #112]
-    .cfi_rel_offset x23, 112
-    .cfi_rel_offset x24, 120
-
-    stp x25, x26, [sp, #128]
-    .cfi_rel_offset x25, 128
-    .cfi_rel_offset x26, 136
-
-    stp x27, x28, [sp, #144]
-    .cfi_rel_offset x27, 144
-    .cfi_rel_offset x28, 152
-
-    stp x29, xLR, [sp, #160]
-    .cfi_rel_offset x29, 160
-    .cfi_rel_offset x30, 168
+    SAVE_TWO_REGS x19, x20, 80
+    SAVE_TWO_REGS x21, x22, 96
+    SAVE_TWO_REGS x23, x24, 112
+    SAVE_TWO_REGS x25, x26, 128
+    SAVE_TWO_REGS x27, x28, 144
+    SAVE_TWO_REGS x29, xLR, 160
 
     // Store ArtMethod* Runtime::callee_save_methods_[kSaveAllCalleeSaves].
     str xIP0, [sp]
@@ -106,25 +125,11 @@
 
     // GP callee-saves.
     // x20 paired with ArtMethod* - see below.
-    stp x21, x22, [sp, #16]
-    .cfi_rel_offset x21, 16
-    .cfi_rel_offset x22, 24
-
-    stp x23, x24, [sp, #32]
-    .cfi_rel_offset x23, 32
-    .cfi_rel_offset x24, 40
-
-    stp x25, x26, [sp, #48]
-    .cfi_rel_offset x25, 48
-    .cfi_rel_offset x26, 56
-
-    stp x27, x28, [sp, #64]
-    .cfi_rel_offset x27, 64
-    .cfi_rel_offset x28, 72
-
-    stp x29, xLR, [sp, #80]
-    .cfi_rel_offset x29, 80
-    .cfi_rel_offset x30, 88
+    SAVE_TWO_REGS x21, x22, 16
+    SAVE_TWO_REGS x23, x24, 32
+    SAVE_TWO_REGS x25, x26, 48
+    SAVE_TWO_REGS x27, x28, 64
+    SAVE_TWO_REGS x29, xLR, 80
 
     // Store ArtMethod* Runtime::callee_save_methods_[kSaveRefsOnly].
     stp xIP0, x20, [sp]
@@ -138,28 +143,12 @@
 // TODO: Probably no need to restore registers preserved by aapcs64.
 .macro RESTORE_SAVE_REFS_ONLY_FRAME
     // Callee-saves.
-    ldr x20, [sp, #8]
-    .cfi_restore x20
-
-    ldp x21, x22, [sp, #16]
-    .cfi_restore x21
-    .cfi_restore x22
-
-    ldp x23, x24, [sp, #32]
-    .cfi_restore x23
-    .cfi_restore x24
-
-    ldp x25, x26, [sp, #48]
-    .cfi_restore x25
-    .cfi_restore x26
-
-    ldp x27, x28, [sp, #64]
-    .cfi_restore x27
-    .cfi_restore x28
-
-    ldp x29, xLR, [sp, #80]
-    .cfi_restore x29
-    .cfi_restore x30
+    RESTORE_REG x20, 8
+    RESTORE_TWO_REGS x21, x22, 16
+    RESTORE_TWO_REGS x23, x24, 32
+    RESTORE_TWO_REGS x25, x26, 48
+    RESTORE_TWO_REGS x27, x28, 64
+    RESTORE_TWO_REGS x29, xLR, 80
 
     add sp, sp, #96
     .cfi_adjust_cfa_offset -96
@@ -193,43 +182,19 @@
     stp d6, d7, [sp, #64]
 
     // Core args.
-    stp x1, x2, [sp, #80]
-    .cfi_rel_offset x1, 80
-    .cfi_rel_offset x2, 88
-
-    stp x3, x4, [sp, #96]
-    .cfi_rel_offset x3, 96
-    .cfi_rel_offset x4, 104
-
-    stp x5, x6, [sp, #112]
-    .cfi_rel_offset x5, 112
-    .cfi_rel_offset x6, 120
+    SAVE_TWO_REGS x1, x2, 80
+    SAVE_TWO_REGS x3, x4, 96
+    SAVE_TWO_REGS x5, x6, 112
 
     // x7, Callee-saves.
-    stp x7, x20, [sp, #128]
-    .cfi_rel_offset x7, 128
-    .cfi_rel_offset x20, 136
-
-    stp x21, x22, [sp, #144]
-    .cfi_rel_offset x21, 144
-    .cfi_rel_offset x22, 152
-
-    stp x23, x24, [sp, #160]
-    .cfi_rel_offset x23, 160
-    .cfi_rel_offset x24, 168
-
-    stp x25, x26, [sp, #176]
-    .cfi_rel_offset x25, 176
-    .cfi_rel_offset x26, 184
-
-    stp x27, x28, [sp, #192]
-    .cfi_rel_offset x27, 192
-    .cfi_rel_offset x28, 200
+    SAVE_TWO_REGS x7, x20, 128
+    SAVE_TWO_REGS x21, x22, 144
+    SAVE_TWO_REGS x23, x24, 160
+    SAVE_TWO_REGS x25, x26, 176
+    SAVE_TWO_REGS x27, x28, 192
 
     // x29(callee-save) and LR.
-    stp x29, xLR, [sp, #208]
-    .cfi_rel_offset x29, 208
-    .cfi_rel_offset x30, 216
+    SAVE_TWO_REGS x29, xLR, 208
 
 .endm
 
@@ -275,43 +240,19 @@
     ldp d6, d7, [sp, #64]
 
     // Core args.
-    ldp x1, x2, [sp, #80]
-    .cfi_restore x1
-    .cfi_restore x2
-
-    ldp x3, x4, [sp, #96]
-    .cfi_restore x3
-    .cfi_restore x4
-
-    ldp x5, x6, [sp, #112]
-    .cfi_restore x5
-    .cfi_restore x6
+    RESTORE_TWO_REGS x1, x2, 80
+    RESTORE_TWO_REGS x3, x4, 96
+    RESTORE_TWO_REGS x5, x6, 112
 
     // x7, Callee-saves.
-    ldp x7, x20, [sp, #128]
-    .cfi_restore x7
-    .cfi_restore x20
-
-    ldp x21, x22, [sp, #144]
-    .cfi_restore x21
-    .cfi_restore x22
-
-    ldp x23, x24, [sp, #160]
-    .cfi_restore x23
-    .cfi_restore x24
-
-    ldp x25, x26, [sp, #176]
-    .cfi_restore x25
-    .cfi_restore x26
-
-    ldp x27, x28, [sp, #192]
-    .cfi_restore x27
-    .cfi_restore x28
+    RESTORE_TWO_REGS x7, x20, 128
+    RESTORE_TWO_REGS x21, x22, 144
+    RESTORE_TWO_REGS x23, x24, 160
+    RESTORE_TWO_REGS x25, x26, 176
+    RESTORE_TWO_REGS x27, x28, 192
 
     // x29(callee-save) and LR.
-    ldp x29, xLR, [sp, #208]
-    .cfi_restore x29
-    .cfi_restore x30
+    RESTORE_TWO_REGS x29, xLR, 208
 
     add sp, sp, #224
     .cfi_adjust_cfa_offset -224
@@ -351,68 +292,22 @@
     str d31,      [sp, #256]
 
     // Save core registers.
-    str x0,       [sp, #264]
-    .cfi_rel_offset x0, 264
-
-    stp x1, x2,   [sp, #272]
-    .cfi_rel_offset x1, 272
-    .cfi_rel_offset x2, 280
-
-    stp x3, x4,   [sp, #288]
-    .cfi_rel_offset x3, 288
-    .cfi_rel_offset x4, 296
-
-    stp x5, x6,   [sp, #304]
-    .cfi_rel_offset x5, 304
-    .cfi_rel_offset x6, 312
-
-    stp x7, x8,   [sp, #320]
-    .cfi_rel_offset x7, 320
-    .cfi_rel_offset x8, 328
-
-    stp x9, x10,  [sp, #336]
-    .cfi_rel_offset x9, 336
-    .cfi_rel_offset x10, 344
-
-    stp x11, x12, [sp, #352]
-    .cfi_rel_offset x11, 352
-    .cfi_rel_offset x12, 360
-
-    stp x13, x14, [sp, #368]
-    .cfi_rel_offset x13, 368
-    .cfi_rel_offset x14, 376
-
-    stp x15, x16, [sp, #384]
-    .cfi_rel_offset x15, 384
-    .cfi_rel_offset x16, 392
-
-    stp x17, x18, [sp, #400]
-    .cfi_rel_offset x17, 400
-    .cfi_rel_offset x18, 408
-
-    stp x19, x20, [sp, #416]
-    .cfi_rel_offset x19, 416
-    .cfi_rel_offset x20, 424
-
-    stp x21, x22, [sp, #432]
-    .cfi_rel_offset x21, 432
-    .cfi_rel_offset x22, 440
-
-    stp x23, x24, [sp, #448]
-    .cfi_rel_offset x23, 448
-    .cfi_rel_offset x24, 456
-
-    stp x25, x26, [sp, #464]
-    .cfi_rel_offset x25, 464
-    .cfi_rel_offset x26, 472
-
-    stp x27, x28, [sp, #480]
-    .cfi_rel_offset x27, 480
-    .cfi_rel_offset x28, 488
-
-    stp x29, xLR, [sp, #496]
-    .cfi_rel_offset x29, 496
-    .cfi_rel_offset x30, 504
+    SAVE_REG            x0, 264
+    SAVE_TWO_REGS  x1,  x2, 272
+    SAVE_TWO_REGS  x3,  x4, 288
+    SAVE_TWO_REGS  x5,  x6, 304
+    SAVE_TWO_REGS  x7,  x8, 320
+    SAVE_TWO_REGS  x9, x10, 336
+    SAVE_TWO_REGS x11, x12, 352
+    SAVE_TWO_REGS x13, x14, 368
+    SAVE_TWO_REGS x15, x16, 384
+    SAVE_TWO_REGS x17, x18, 400
+    SAVE_TWO_REGS x19, x20, 416
+    SAVE_TWO_REGS x21, x22, 432
+    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
@@ -452,68 +347,22 @@
     ldr d31,      [sp, #256]
 
     // Restore core registers.
-    ldr x0,       [sp, #264]
-    .cfi_restore x0
-
-    ldp x1, x2,   [sp, #272]
-    .cfi_restore x1
-    .cfi_restore x2
-
-    ldp x3, x4,   [sp, #288]
-    .cfi_restore x3
-    .cfi_restore x4
-
-    ldp x5, x6,   [sp, #304]
-    .cfi_restore x5
-    .cfi_restore x6
-
-    ldp x7, x8,   [sp, #320]
-    .cfi_restore x7
-    .cfi_restore x8
-
-    ldp x9, x10,  [sp, #336]
-    .cfi_restore x9
-    .cfi_restore x10
-
-    ldp x11, x12, [sp, #352]
-    .cfi_restore x11
-    .cfi_restore x12
-
-    ldp x13, x14, [sp, #368]
-    .cfi_restore x13
-    .cfi_restore x14
-
-    ldp x15, x16, [sp, #384]
-    .cfi_restore x15
-    .cfi_restore x16
-
-    ldp x17, x18, [sp, #400]
-    .cfi_restore x17
-    .cfi_restore x18
-
-    ldp x19, x20, [sp, #416]
-    .cfi_restore x19
-    .cfi_restore x20
-
-    ldp x21, x22, [sp, #432]
-    .cfi_restore x21
-    .cfi_restore x22
-
-    ldp x23, x24, [sp, #448]
-    .cfi_restore x23
-    .cfi_restore x24
-
-    ldp x25, x26, [sp, #464]
-    .cfi_restore x25
-    .cfi_restore x26
-
-    ldp x27, x28, [sp, #480]
-    .cfi_restore x27
-    .cfi_restore x28
-
-    ldp x29, xLR, [sp, #496]
-    .cfi_restore x29
-    .cfi_restore x30
+    RESTORE_REG            x0, 264
+    RESTORE_TWO_REGS  x1,  x2, 272
+    RESTORE_TWO_REGS  x3,  x4, 288
+    RESTORE_TWO_REGS  x5,  x6, 304
+    RESTORE_TWO_REGS  x7,  x8, 320
+    RESTORE_TWO_REGS  x9, x10, 336
+    RESTORE_TWO_REGS x11, x12, 352
+    RESTORE_TWO_REGS x13, x14, 368
+    RESTORE_TWO_REGS x15, x16, 384
+    RESTORE_TWO_REGS x17, x18, 400
+    RESTORE_TWO_REGS x19, x20, 416
+    RESTORE_TWO_REGS x21, x22, 432
+    RESTORE_TWO_REGS x23, x24, 448
+    RESTORE_TWO_REGS x25, x26, 464
+    RESTORE_TWO_REGS x27, x28, 480
+    RESTORE_TWO_REGS x29, xLR, 496
 
     add sp, sp, #512
     .cfi_adjust_cfa_offset -512
@@ -1409,12 +1258,8 @@
 ENTRY art_quick_check_cast
     // Store arguments and link register
     // Stack needs to be 16B aligned on calls.
-    stp x0, x1, [sp,#-32]!
-    .cfi_adjust_cfa_offset 32
-    .cfi_rel_offset x0, 0
-    .cfi_rel_offset x1, 8
-    str xLR, [sp, #24]
-    .cfi_rel_offset x30, 24
+    SAVE_TWO_REGS_INCREASE_FRAME x0, x1, 32
+    SAVE_REG xLR, 24
 
     // Call runtime code
     bl artIsAssignableFromCode
@@ -1423,24 +1268,16 @@
     cbz x0, .Lthrow_class_cast_exception
 
     // Restore and return
-    ldr xLR, [sp, #24]
-    .cfi_restore x30
-    ldp x0, x1, [sp], #32
-    .cfi_restore x0
-    .cfi_restore x1
-    .cfi_adjust_cfa_offset -32
+    RESTORE_REG xLR, 24
+    RESTORE_TWO_REGS_DECREASE_FRAME x0, x1, 32
     ret
 
     .cfi_adjust_cfa_offset 32         // Reset unwind info so following code unwinds.
 
 .Lthrow_class_cast_exception:
     // Restore
-    ldr xLR, [sp, #24]
-    .cfi_restore x30
-    ldp x0, x1, [sp], #32
-    .cfi_restore x0
-    .cfi_restore x1
-    .cfi_adjust_cfa_offset -32
+    RESTORE_REG xLR, 24
+    RESTORE_TWO_REGS_DECREASE_FRAME x0, x1, 32
 
     SETUP_SAVE_ALL_CALLEE_SAVES_FRAME // save all registers as basis for long jump context
     mov x2, xSELF                     // pass Thread::Current
@@ -1492,16 +1329,9 @@
 #endif
 .Lrb_slowpath\number:
     // Store registers used in art_quick_aput_obj (x0-x4, LR), stack is 16B aligned.
-    stp x0, x1, [sp, #-48]!
-    .cfi_adjust_cfa_offset 48
-    .cfi_rel_offset x0, 0
-    .cfi_rel_offset x1, 8
-    stp x2, x3, [sp, #16]
-    .cfi_rel_offset x2, 16
-    .cfi_rel_offset x3, 24
-    stp x4, xLR, [sp, #32]
-    .cfi_rel_offset x4, 32
-    .cfi_rel_offset x30, 40
+    SAVE_TWO_REGS_INCREASE_FRAME x0, x1, 48
+    SAVE_TWO_REGS x2, x3, 16
+    SAVE_TWO_REGS x4, xLR, 32
 
     // mov x0, \xRef                // pass ref in x0 (no-op for now since parameter ref is unused)
     .ifnc \xObj, x1
@@ -1520,8 +1350,7 @@
     POP_REG_NE x2, 16, \xDest
     POP_REG_NE x3, 24, \xDest
     POP_REG_NE x4, 32, \xDest
-    ldr xLR, [sp, #40]
-    .cfi_restore x30
+    RESTORE_REG xLR, 40
     add sp, sp, #48
     .cfi_adjust_cfa_offset -48
 .Lrb_exit\number:
@@ -1587,13 +1416,8 @@
     ret
 .Lcheck_assignability:
     // Store arguments and link register
-    stp x0, x1, [sp,#-32]!
-    .cfi_adjust_cfa_offset 32
-    .cfi_rel_offset x0, 0
-    .cfi_rel_offset x1, 8
-    stp x2, xLR, [sp, #16]
-    .cfi_rel_offset x2, 16
-    .cfi_rel_offset x30, 24
+    SAVE_TWO_REGS_INCREASE_FRAME x0, x1, 32
+    SAVE_TWO_REGS x2, xLR, 16
 
     // Call runtime code
     mov x0, x3              // Heap reference, 32b, "uncompress" = do nothing, already zero-extended
@@ -1604,13 +1428,8 @@
     cbz x0, .Lthrow_array_store_exception
 
     // Restore
-    ldp x2, x30, [sp, #16]
-    .cfi_restore x2
-    .cfi_restore x30
-    ldp x0, x1, [sp], #32
-    .cfi_restore x0
-    .cfi_restore x1
-    .cfi_adjust_cfa_offset -32
+    RESTORE_TWO_REGS x2, xLR, 16
+    RESTORE_TWO_REGS_DECREASE_FRAME x0, x1, 32
 
     add x3, x0, #MIRROR_OBJECT_ARRAY_DATA_OFFSET
                                                           // "Compress" = do nothing
@@ -1622,13 +1441,8 @@
     ret
     .cfi_adjust_cfa_offset 32  // 4 restores after cbz for unwinding.
 .Lthrow_array_store_exception:
-    ldp x2, x30, [sp, #16]
-    .cfi_restore x2
-    .cfi_restore x30
-    ldp x0, x1, [sp], #32
-    .cfi_restore x0
-    .cfi_restore x1
-    .cfi_adjust_cfa_offset -32
+    RESTORE_TWO_REGS x2, xLR, 16
+    RESTORE_TWO_REGS_DECREASE_FRAME x0, x1, 32
 
     SETUP_SAVE_ALL_CALLEE_SAVES_FRAME
     mov x1, x2                    // Pass value.
@@ -1821,15 +1635,9 @@
     ldr   x3, [x0, #MIRROR_OBJECT_LOCK_WORD_OFFSET]
     tbnz  x3, #LOCK_WORD_MARK_BIT_SHIFT, .Lart_quick_resolve_string_no_rb
     // Save LR so that we can return, also x1 for alignment purposes.
-    stp    x1, xLR, [sp, #-16]!                     // Save x1, LR.
-    .cfi_adjust_cfa_offset 16
-    .cfi_rel_offset x1, 0
-    .cfi_rel_offset xLR, 8
+    SAVE_TWO_REGS_INCREASE_FRAME x1, xLR, 16        // Save x1, LR.
     bl     artReadBarrierMark                       // Get the marked string back.
-    ldp    x1, xLR, [sp], #16                       // Restore registers.
-    .cfi_restore xLR
-    .cfi_restore x1
-    .cfi_adjust_cfa_offset -16
+    RESTORE_TWO_REGS_DECREASE_FRAME x1, xLR, 16     // Restore registers.
 .Lart_quick_resolve_string_no_rb:
     ret
 
@@ -2104,22 +1912,13 @@
     tbnz    w3, #LOCK_WORD_MARK_BIT_SHIFT, .Ldo_allocation\name
                                                               // The read barrier slow path. Mark
                                                               // the class.
-    stp    x0, x1, [sp, #-32]!                                // Save registers (x0, x1, lr).
-    .cfi_adjust_cfa_offset 32
-    .cfi_rel_offset x0, 0
-    .cfi_rel_offset x1, 8
-    str    xLR, [sp, #16]                                     // Align sp by 16 bytes.
-    .cfi_rel_offset xLR, 16
+    SAVE_TWO_REGS_INCREASE_FRAME x0, x1, 32                   // Save registers (x0, x1, lr).
+    SAVE_REG xLR, 24                                          // Align sp by 16 bytes.
     mov    x0, x2                                             // Pass the class as the first param.
     bl     artReadBarrierMark
     mov    x2, x0                                             // Get the (marked) class back.
-    ldp    x0, x1, [sp, #0]                                   // Restore registers.
-    .cfi_restore x0
-    .cfi_restore x1
-    ldr    xLR, [sp, #16]
-    .cfi_restore xLR
-    add    sp, sp, #32
-    .cfi_adjust_cfa_offset -32
+    RESTORE_REG xLR, 24
+    RESTORE_TWO_REGS_DECREASE_FRAME x0, x1, 32                // Restore registers.
     b      .Ldo_allocation\name
 .endif
 .Lslow_path\name:
@@ -2503,7 +2302,7 @@
     mov   xLR, x1             // r1 is holding link register if we're to bounce to deoptimize
 
     ldr   d0, [sp, #8]        // Restore floating-point result.
-    ldr   x0, [sp], 16        // Restore integer result, and drop stack area.
+    ldr   x0, [sp], #16       // Restore integer result, and drop stack area.
     .cfi_adjust_cfa_offset 16
 
     POP_SAVE_REFS_ONLY_FRAME
@@ -2529,7 +2328,7 @@
      */
     .extern artDeoptimizeFromCompiledCode
 ENTRY art_quick_deoptimize_from_compiled_code
-    SETUP_SAVE_ALL_CALLEE_SAVES_FRAME
+    SETUP_SAVE_EVERYTHING_FRAME
     mov    x0, xSELF                      // Pass thread.
     bl     artDeoptimizeFromCompiledCode  // artDeoptimizeFromCompiledCode(Thread*)
     brk 0
@@ -2661,37 +2460,16 @@
     ret
 .Lslow_path_rb_\name:
     // Save all potentially live caller-save core registers.
-    stp   x0, x1,   [sp, #-368]!
-    .cfi_adjust_cfa_offset 368
-    .cfi_rel_offset x0, 0
-    .cfi_rel_offset x1, 8
-    stp   x2, x3,   [sp, #16]
-    .cfi_rel_offset x2, 16
-    .cfi_rel_offset x3, 24
-    stp   x4, x5,   [sp, #32]
-    .cfi_rel_offset x4, 32
-    .cfi_rel_offset x5, 40
-    stp   x6, x7,   [sp, #48]
-    .cfi_rel_offset x6, 48
-    .cfi_rel_offset x7, 56
-    stp   x8, x9,   [sp, #64]
-    .cfi_rel_offset x8, 64
-    .cfi_rel_offset x9, 72
-    stp   x10, x11, [sp, #80]
-    .cfi_rel_offset x10, 80
-    .cfi_rel_offset x11, 88
-    stp   x12, x13, [sp, #96]
-    .cfi_rel_offset x12, 96
-    .cfi_rel_offset x13, 104
-    stp   x14, x15, [sp, #112]
-    .cfi_rel_offset x14, 112
-    .cfi_rel_offset x15, 120
-    stp   x16, x17, [sp, #128]
-    .cfi_rel_offset x16, 128
-    .cfi_rel_offset x17, 136
-    stp   x18, x19, [sp, #144]
-    .cfi_rel_offset x18, 144
-    .cfi_rel_offset x19, 152
+    SAVE_TWO_REGS_INCREASE_FRAME x0, x1, 368
+    SAVE_TWO_REGS  x2,  x3, 16
+    SAVE_TWO_REGS  x4,  x5, 32
+    SAVE_TWO_REGS  x6,  x7, 48
+    SAVE_TWO_REGS  x8,  x9, 64
+    SAVE_TWO_REGS x10, x11, 80
+    SAVE_TWO_REGS x12, x13, 96
+    SAVE_TWO_REGS x14, x15, 112
+    SAVE_TWO_REGS   x16, x17, 128
+    SAVE_TWO_REGS   x18, x19, 144
     // Save all potentially live caller-save floating-point registers.
     stp   d0, d1,   [sp, #160]
     stp   d2, d3,   [sp, #176]
@@ -2706,9 +2484,8 @@
     stp   d28, d29, [sp, #320]
     stp   d30, d31, [sp, #336]
     // Save return address.
-    str   xLR,      [sp, #352]
-    .cfi_rel_offset x30, 352
-    // (sp + #360 is a padding slot)
+    // (sp + #352 is a padding slot)
+    SAVE_REG xLR, 360
 
     .ifnc \wreg, w0
       mov   w0, \wreg                   // Pass arg1 - obj from `wreg`
@@ -2744,8 +2521,7 @@
     ldp   d28, d29, [sp, #320]
     ldp   d30, d31, [sp, #336]
     // Restore return address and remove padding.
-    ldr   xLR,      [sp, #352]
-    .cfi_restore x30
+    RESTORE_REG xLR, 360
     add sp, sp, #368
     .cfi_adjust_cfa_offset -368
 .Lret_rb_\name:
diff --git a/runtime/arch/instruction_set.cc b/runtime/arch/instruction_set.cc
index b35e088..8f64dcd 100644
--- a/runtime/arch/instruction_set.cc
+++ b/runtime/arch/instruction_set.cc
@@ -19,11 +19,31 @@
 // Explicitly include our own elf.h to avoid Linux and other dependencies.
 #include "../elf.h"
 #include "base/bit_utils.h"
+#include "base/logging.h"
 #include "globals.h"
 
 namespace art {
 
-const char* GetInstructionSetString(const InstructionSet isa) {
+void InstructionSetAbort(InstructionSet isa) {
+  switch (isa) {
+    case kArm:
+    case kThumb2:
+    case kArm64:
+    case kX86:
+    case kX86_64:
+    case kMips:
+    case kMips64:
+    case kNone:
+      LOG(FATAL) << "Unsupported instruction set " << isa;
+      UNREACHABLE();
+
+    default:
+      LOG(FATAL) << "Unknown ISA " << isa;
+      UNREACHABLE();
+  }
+}
+
+const char* GetInstructionSetString(InstructionSet isa) {
   switch (isa) {
     case kArm:
     case kThumb2:
diff --git a/runtime/arch/instruction_set.h b/runtime/arch/instruction_set.h
index 917acc9..4a8bea4 100644
--- a/runtime/arch/instruction_set.h
+++ b/runtime/arch/instruction_set.h
@@ -21,7 +21,7 @@
 #include <string>
 
 #include "base/enums.h"
-#include "base/logging.h"  // Logging is required for FATAL in the helper functions.
+#include "base/macros.h"
 
 namespace art {
 
@@ -75,7 +75,6 @@
 // X86 instruction alignment. This is the recommended alignment for maximum performance.
 static constexpr size_t kX86Alignment = 16;
 
-
 const char* GetInstructionSetString(InstructionSet isa);
 
 // Note: Returns kNone when the string cannot be parsed to a known value.
@@ -83,6 +82,9 @@
 
 InstructionSet GetInstructionSetFromELF(uint16_t e_machine, uint32_t e_flags);
 
+// Fatal logging out of line to keep the header clean of logging.h.
+NO_RETURN void InstructionSetAbort(InstructionSet isa);
+
 static inline PointerSize GetInstructionSetPointerSize(InstructionSet isa) {
   switch (isa) {
     case kArm:
@@ -99,12 +101,8 @@
       return kMipsPointerSize;
     case kMips64:
       return kMips64PointerSize;
-    case kNone:
-      LOG(FATAL) << "ISA kNone does not have pointer size.";
-      UNREACHABLE();
     default:
-      LOG(FATAL) << "Unknown ISA " << isa;
-      UNREACHABLE();
+      InstructionSetAbort(isa);
   }
 }
 
@@ -139,12 +137,8 @@
     case kMips64:
       return true;
 
-    case kNone:
-      LOG(FATAL) << "ISA kNone does not have bit width.";
-      UNREACHABLE();
     default:
-      LOG(FATAL) << "Unknown ISA " << isa;
-      UNREACHABLE();
+      InstructionSetAbort(isa);
   }
 }
 
@@ -168,12 +162,9 @@
       return 4;
     case kMips64:
       return 8;
-    case kNone:
-      LOG(FATAL) << "ISA kNone does not have spills.";
-      UNREACHABLE();
+
     default:
-      LOG(FATAL) << "Unknown ISA " << isa;
-      UNREACHABLE();
+      InstructionSetAbort(isa);
   }
 }
 
@@ -193,12 +184,9 @@
       return 4;
     case kMips64:
       return 8;
-    case kNone:
-      LOG(FATAL) << "ISA kNone does not have spills.";
-      UNREACHABLE();
+
     default:
-      LOG(FATAL) << "Unknown ISA " << isa;
-      UNREACHABLE();
+      InstructionSetAbort(isa);
   }
 }
 
diff --git a/runtime/arch/instruction_set_features_test.cc b/runtime/arch/instruction_set_features_test.cc
index fb38b47..7bbc709 100644
--- a/runtime/arch/instruction_set_features_test.cc
+++ b/runtime/arch/instruction_set_features_test.cc
@@ -22,6 +22,7 @@
 #include "cutils/properties.h"
 #endif
 
+#include "base/logging.h"
 #include "base/stringprintf.h"
 
 namespace art {
diff --git a/runtime/arch/mips/instruction_set_features_mips.h b/runtime/arch/mips/instruction_set_features_mips.h
index 120dc1c..2d54988 100644
--- a/runtime/arch/mips/instruction_set_features_mips.h
+++ b/runtime/arch/mips/instruction_set_features_mips.h
@@ -18,6 +18,8 @@
 #define ART_RUNTIME_ARCH_MIPS_INSTRUCTION_SET_FEATURES_MIPS_H_
 
 #include "arch/instruction_set_features.h"
+#include "base/logging.h"
+#include "base/macros.h"
 
 namespace art {
 
diff --git a/runtime/arch/mips/quick_entrypoints_mips.S b/runtime/arch/mips/quick_entrypoints_mips.S
index 3d393f6..4bd1314 100644
--- a/runtime/arch/mips/quick_entrypoints_mips.S
+++ b/runtime/arch/mips/quick_entrypoints_mips.S
@@ -2094,7 +2094,7 @@
      */
     .extern artDeoptimizeFromCompiledCode
 ENTRY art_quick_deoptimize_from_compiled_code
-    SETUP_SAVE_ALL_CALLEE_SAVES_FRAME
+    SETUP_SAVE_EVERYTHING_FRAME
     la       $t9, artDeoptimizeFromCompiledCode
     jalr     $t9                            # artDeoptimizeFromCompiledCode(Thread*)
                                             # Returns caller method's frame size.
diff --git a/runtime/arch/mips64/quick_entrypoints_mips64.S b/runtime/arch/mips64/quick_entrypoints_mips64.S
index 9774eb9..0bf2a35 100644
--- a/runtime/arch/mips64/quick_entrypoints_mips64.S
+++ b/runtime/arch/mips64/quick_entrypoints_mips64.S
@@ -2138,8 +2138,8 @@
      * will long jump to the upcall with a special exception of -1.
      */
     .extern artDeoptimizeFromCompiledCode
-ENTRY art_quick_deoptimize_from_compiled_code
-    SETUP_SAVE_ALL_CALLEE_SAVES_FRAME
+ENTRY_NO_GP art_quick_deoptimize_from_compiled_code
+    SETUP_SAVE_EVERYTHING_FRAME
     jal      artDeoptimizeFromCompiledCode    # artDeoptimizeFromCompiledCode(Thread*, SP)
                                               # Returns caller method's frame size.
     move     $a0, rSELF                       # pass Thread::current
diff --git a/runtime/arch/x86/quick_entrypoints_x86.S b/runtime/arch/x86/quick_entrypoints_x86.S
index 67ebf50..646a80c 100644
--- a/runtime/arch/x86/quick_entrypoints_x86.S
+++ b/runtime/arch/x86/quick_entrypoints_x86.S
@@ -1930,7 +1930,7 @@
      * will long jump to the interpreter bridge.
      */
 DEFINE_FUNCTION art_quick_deoptimize_from_compiled_code
-    SETUP_SAVE_ALL_CALLEE_SAVES_FRAME ebx, ebx
+    SETUP_SAVE_EVERYTHING_FRAME ebx, ebx
     subl LITERAL(12), %esp                      // Align stack.
     CFI_ADJUST_CFA_OFFSET(12)
     pushl %fs:THREAD_SELF_OFFSET                // Pass Thread::Current().
diff --git a/runtime/arch/x86_64/quick_entrypoints_x86_64.S b/runtime/arch/x86_64/quick_entrypoints_x86_64.S
index b805703..5ea58af 100644
--- a/runtime/arch/x86_64/quick_entrypoints_x86_64.S
+++ b/runtime/arch/x86_64/quick_entrypoints_x86_64.S
@@ -2053,7 +2053,7 @@
      * will long jump to the interpreter bridge.
      */
 DEFINE_FUNCTION art_quick_deoptimize_from_compiled_code
-    SETUP_SAVE_ALL_CALLEE_SAVES_FRAME
+    SETUP_SAVE_EVERYTHING_FRAME
                                                 // Stack should be aligned now.
     movq %gs:THREAD_SELF_OFFSET, %rdi           // Pass Thread.
     call SYMBOL(artDeoptimizeFromCompiledCode)  // artDeoptimizeFromCompiledCode(Thread*)
diff --git a/runtime/base/bit_utils.h b/runtime/base/bit_utils.h
index 378371d..d2f0fdb 100644
--- a/runtime/base/bit_utils.h
+++ b/runtime/base/bit_utils.h
@@ -21,7 +21,12 @@
 #include <limits>
 #include <type_traits>
 
+// This header is used in the disassembler with libbase's logging. Only include ART logging
+// when no other logging macros are available. b/15436106, b/31338270
+#ifndef CHECK
 #include "base/logging.h"
+#endif
+
 #include "base/iteration_range.h"
 #include "base/stl_util.h"
 
diff --git a/runtime/base/enums.h b/runtime/base/enums.h
index 51b86ea..52cab2a 100644
--- a/runtime/base/enums.h
+++ b/runtime/base/enums.h
@@ -20,9 +20,6 @@
 #include <cstddef>
 #include <ostream>
 
-#include "base/logging.h"
-#include "base/macros.h"
-
 namespace art {
 
 enum class PointerSize : size_t {
@@ -35,16 +32,6 @@
                                                        ? PointerSize::k64
                                                        : PointerSize::k32;
 
-template <typename T>
-static constexpr PointerSize ConvertToPointerSize(T any) {
-  if (any == 4 || any == 8) {
-    return static_cast<PointerSize>(any);
-  } else {
-    LOG(FATAL);
-    UNREACHABLE();
-  }
-}
-
 }  // namespace art
 
 #endif  // ART_RUNTIME_BASE_ENUMS_H_
diff --git a/runtime/base/logging.cc b/runtime/base/logging.cc
index 28352cb..529c391 100644
--- a/runtime/base/logging.cc
+++ b/runtime/base/logging.cc
@@ -139,13 +139,10 @@
 class LogMessageData {
  public:
   LogMessageData(const char* file, unsigned int line, LogSeverity severity, int error)
-      : file_(file),
+      : file_(GetFilenameBase(file)),
         line_number_(line),
         severity_(severity),
-        error_(error) {
-    const char* last_slash = strrchr(file, '/');
-    file = (last_slash == nullptr) ? file : last_slash + 1;
-  }
+        error_(error) {}
 
   const char * GetFile() const {
     return file_;
@@ -178,6 +175,11 @@
   const LogSeverity severity_;
   const int error_;
 
+  static const char* GetFilenameBase(const char* file) {
+    const char* last_slash = strrchr(file, '/');
+    return (last_slash == nullptr) ? file : last_slash + 1;
+  }
+
   DISALLOW_COPY_AND_ASSIGN(LogMessageData);
 };
 
diff --git a/runtime/base/stl_util.h b/runtime/base/stl_util.h
index a53dcea..a4cf249 100644
--- a/runtime/base/stl_util.h
+++ b/runtime/base/stl_util.h
@@ -20,7 +20,11 @@
 #include <algorithm>
 #include <sstream>
 
+// This header is used in the disassembler with libbase's logging. Only include ART logging
+// when no other logging macros are available. b/15436106, b/31338270
+#ifndef CHECK
 #include "base/logging.h"
+#endif
 
 namespace art {
 
diff --git a/runtime/code_simulator_container.h b/runtime/code_simulator_container.h
index 655a247..10178ba 100644
--- a/runtime/code_simulator_container.h
+++ b/runtime/code_simulator_container.h
@@ -18,6 +18,7 @@
 #define ART_RUNTIME_CODE_SIMULATOR_CONTAINER_H_
 
 #include "arch/instruction_set.h"
+#include "base/logging.h"
 #include "simulator/code_simulator.h"
 
 namespace art {
diff --git a/runtime/common_runtime_test.h b/runtime/common_runtime_test.h
index c07c03e..00394e9 100644
--- a/runtime/common_runtime_test.h
+++ b/runtime/common_runtime_test.h
@@ -219,6 +219,12 @@
     return; \
   }
 
+#define TEST_DISABLED_FOR_NON_STATIC_HOST_BUILDS() \
+  if (!kHostStaticBuildEnabled) { \
+    printf("WARNING: TEST DISABLED FOR NON-STATIC HOST BUILDS\n"); \
+    return; \
+  }
+
 }  // namespace art
 
 namespace std {
diff --git a/runtime/gc/collector/semi_space.cc b/runtime/gc/collector/semi_space.cc
index fc04f30..47e6ca3 100644
--- a/runtime/gc/collector/semi_space.cc
+++ b/runtime/gc/collector/semi_space.cc
@@ -265,9 +265,9 @@
   RecordFree(ObjectBytePair(from_objects - to_objects, from_bytes - to_bytes));
   // Clear and protect the from space.
   from_space_->Clear();
-  // b/31172841. Temporarily disable the from-space protection under gcstress mode with debug build
+  // b/31172841. Temporarily disable the from-space protection with host debug build
   // due to some protection issue in the build server.
-  if (kProtectFromSpace && !(kIsDebugBuild && heap_->gc_stress_mode_)) {
+  if (kProtectFromSpace && !(kIsDebugBuild && !kIsTargetBuild)) {
     if (!from_space_->IsRosAllocSpace()) {
       // Protect with PROT_NONE.
       VLOG(heap) << "Protecting from_space_ : " << *from_space_;
@@ -794,9 +794,9 @@
 
 void SemiSpace::FinishPhase() {
   TimingLogger::ScopedTiming t(__FUNCTION__, GetTimings());
-  // b/31172841. Temporarily disable the from-space protection under gcstress mode with debug build
+  // b/31172841. Temporarily disable the from-space protection with host debug build
   // due to some protection issue in the build server.
-  if (kProtectFromSpace && !(kIsDebugBuild && heap_->gc_stress_mode_)) {
+  if (kProtectFromSpace && !(kIsDebugBuild && !kIsTargetBuild)) {
     if (from_space_->IsRosAllocSpace()) {
       VLOG(heap) << "Protecting from_space_ with PROT_NONE : " << *from_space_;
       from_space_->GetMemMap()->Protect(PROT_NONE);
diff --git a/runtime/globals.h b/runtime/globals.h
index 9045d40..aba5661 100644
--- a/runtime/globals.h
+++ b/runtime/globals.h
@@ -67,22 +67,30 @@
 #if defined(ART_TARGET)
 // Useful in conditionals where ART_TARGET isn't.
 static constexpr bool kIsTargetBuild = true;
-#if defined(ART_TARGET_LINUX)
+# if defined(ART_TARGET_LINUX)
 static constexpr bool kIsTargetLinux = true;
-#elif defined(ART_TARGET_ANDROID)
+# elif defined(ART_TARGET_ANDROID)
 static constexpr bool kIsTargetLinux = false;
-#else
-#error "Either ART_TARGET_LINUX or ART_TARGET_ANDROID needs to be defined for target builds."
-#endif
+# else
+# error "Either ART_TARGET_LINUX or ART_TARGET_ANDROID needs to be defined for target builds."
+# endif
 #else
 static constexpr bool kIsTargetBuild = false;
-#if defined(ART_TARGET_LINUX)
-#error "ART_TARGET_LINUX defined for host build."
-#elif defined(ART_TARGET_ANDROID)
-#error "ART_TARGET_ANDROID defined for host build."
-#else
+# if defined(ART_TARGET_LINUX)
+# error "ART_TARGET_LINUX defined for host build."
+# elif defined(ART_TARGET_ANDROID)
+# error "ART_TARGET_ANDROID defined for host build."
+# else
 static constexpr bool kIsTargetLinux = false;
+# endif
 #endif
+
+// Are additional statically-linked ART host binaries (dex2oats,
+// oatdumps, etc.) built and available?
+#if !defined(ART_TARGET) && defined(ART_BUILD_HOST_STATIC)
+static constexpr bool kHostStaticBuildEnabled = true;
+#else
+static constexpr bool kHostStaticBuildEnabled = false;
 #endif
 
 // Garbage collector constants.
diff --git a/runtime/image.cc b/runtime/image.cc
index 6888183..7e6790a 100644
--- a/runtime/image.cc
+++ b/runtime/image.cc
@@ -20,6 +20,7 @@
 #include "mirror/object_array.h"
 #include "mirror/object_array-inl.h"
 #include "mirror/object-inl.h"
+#include "utils.h"
 
 namespace art {
 
@@ -179,4 +180,8 @@
   }
 }
 
+PointerSize ImageHeader::GetPointerSize() const {
+  return ConvertToPointerSize(pointer_size_);
+}
+
 }  // namespace art
diff --git a/runtime/image.h b/runtime/image.h
index 8cd94bb..3a4fa79 100644
--- a/runtime/image.h
+++ b/runtime/image.h
@@ -157,9 +157,7 @@
     return reinterpret_cast<uint8_t*>(oat_file_end_);
   }
 
-  PointerSize GetPointerSize() const {
-    return ConvertToPointerSize(pointer_size_);
-  }
+  PointerSize GetPointerSize() const;
 
   uint32_t GetPointerSizeUnchecked() const {
     return pointer_size_;
diff --git a/runtime/interpreter/interpreter.cc b/runtime/interpreter/interpreter.cc
index 277bda4..0003e72 100644
--- a/runtime/interpreter/interpreter.cc
+++ b/runtime/interpreter/interpreter.cc
@@ -20,7 +20,6 @@
 
 #include "common_throws.h"
 #include "interpreter_common.h"
-#include "interpreter_goto_table_impl.h"
 #include "interpreter_mterp_impl.h"
 #include "interpreter_switch_impl.h"
 #include "mirror/string-inl.h"
@@ -231,15 +230,12 @@
 
 enum InterpreterImplKind {
   kSwitchImplKind,        // Switch-based interpreter implementation.
-  kComputedGotoImplKind,  // Computed-goto-based interpreter implementation.
   kMterpImplKind          // Assembly interpreter
 };
 static std::ostream& operator<<(std::ostream& os, const InterpreterImplKind& rhs) {
   os << ((rhs == kSwitchImplKind)
               ? "Switch-based interpreter"
-              : (rhs == kComputedGotoImplKind)
-                  ? "Computed-goto-based interpreter"
-                  : "Asm interpreter");
+              : "Asm interpreter");
   return os;
 }
 
@@ -323,7 +319,8 @@
           }
         }
       }
-    } else if (kInterpreterImplKind == kSwitchImplKind) {
+    } else {
+      DCHECK_EQ(kInterpreterImplKind, kSwitchImplKind);
       if (transaction_active) {
         return ExecuteSwitchImpl<false, true>(self, code_item, shadow_frame, result_register,
                                               false);
@@ -331,13 +328,6 @@
         return ExecuteSwitchImpl<false, false>(self, code_item, shadow_frame, result_register,
                                                false);
       }
-    } else {
-      DCHECK_EQ(kInterpreterImplKind, kComputedGotoImplKind);
-      if (transaction_active) {
-        return ExecuteGotoImpl<false, true>(self, code_item, shadow_frame, result_register);
-      } else {
-        return ExecuteGotoImpl<false, false>(self, code_item, shadow_frame, result_register);
-      }
     }
   } else {
     // Enter the "with access check" interpreter.
@@ -350,7 +340,8 @@
         return ExecuteSwitchImpl<true, false>(self, code_item, shadow_frame, result_register,
                                               false);
       }
-    } else if (kInterpreterImplKind == kSwitchImplKind) {
+    } else {
+      DCHECK_EQ(kInterpreterImplKind, kSwitchImplKind);
       if (transaction_active) {
         return ExecuteSwitchImpl<true, true>(self, code_item, shadow_frame, result_register,
                                              false);
@@ -358,13 +349,6 @@
         return ExecuteSwitchImpl<true, false>(self, code_item, shadow_frame, result_register,
                                               false);
       }
-    } else {
-      DCHECK_EQ(kInterpreterImplKind, kComputedGotoImplKind);
-      if (transaction_active) {
-        return ExecuteGotoImpl<true, true>(self, code_item, shadow_frame, result_register);
-      } else {
-        return ExecuteGotoImpl<true, false>(self, code_item, shadow_frame, result_register);
-      }
     }
   }
 }
diff --git a/runtime/interpreter/interpreter_goto_table_impl.cc b/runtime/interpreter/interpreter_goto_table_impl.cc
deleted file mode 100644
index 37dd63b..0000000
--- a/runtime/interpreter/interpreter_goto_table_impl.cc
+++ /dev/null
@@ -1,2607 +0,0 @@
-/*
- * Copyright (C) 2012 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 "interpreter_goto_table_impl.h"
-
-// Common includes
-#include "base/logging.h"
-#include "base/macros.h"
-#include "base/mutex.h"
-#include "stack.h"
-#include "thread.h"
-
-// Clang compiles the GOTO interpreter very slowly. So we skip it. These are the implementation
-// details only necessary when compiling it.
-#if !defined(__clang__)
-#include "experimental_flags.h"
-#include "interpreter_common.h"
-#include "jit/jit.h"
-#include "safe_math.h"
-#endif
-
-namespace art {
-namespace interpreter {
-
-#if !defined(__clang__)
-
-// In the following macros, we expect the following local variables exist:
-// - "self": the current Thread*.
-// - "inst" : the current Instruction*.
-// - "inst_data" : the current instruction's first 16 bits.
-// - "dex_pc": the current pc.
-// - "shadow_frame": the current shadow frame.
-// - "currentHandlersTable": the current table of pointer to each instruction handler.
-
-// Advance to the next instruction and updates interpreter state.
-#define ADVANCE(_offset)                                                    \
-  do {                                                                      \
-    int32_t disp = static_cast<int32_t>(_offset);                           \
-    inst = inst->RelativeAt(disp);                                          \
-    dex_pc = static_cast<uint32_t>(static_cast<int32_t>(dex_pc) + disp);    \
-    shadow_frame.SetDexPC(dex_pc);                                          \
-    TraceExecution(shadow_frame, inst, dex_pc);                             \
-    inst_data = inst->Fetch16(0);                                           \
-    goto *currentHandlersTable[inst->Opcode(inst_data)];                    \
-  } while (false)
-
-#define HANDLE_PENDING_EXCEPTION() goto exception_pending_label
-
-#define POSSIBLY_HANDLE_PENDING_EXCEPTION(_is_exception_pending, _offset)   \
-  do {                                                                      \
-    if (UNLIKELY(_is_exception_pending)) {                                  \
-      HANDLE_PENDING_EXCEPTION();                                           \
-    } else {                                                                \
-      ADVANCE(_offset);                                                     \
-    }                                                                       \
-  } while (false)
-
-#define UPDATE_HANDLER_TABLE() \
-  currentHandlersTable = handlersTable[ \
-      Runtime::Current()->GetInstrumentation()->GetInterpreterHandlerTable()]
-
-#define BRANCH_INSTRUMENTATION(offset)                                                          \
-  do {                                                                                          \
-    if (UNLIKELY(instrumentation->HasBranchListeners())) {                                      \
-      instrumentation->Branch(self, method, dex_pc, offset);                                    \
-    }                                                                                           \
-    JValue result;                                                                              \
-    if (jit::Jit::MaybeDoOnStackReplacement(self, method, dex_pc, offset, &result)) {           \
-      return result;                                                                            \
-    }                                                                                           \
-  } while (false)
-
-#define HOTNESS_UPDATE()                                                                       \
-  do {                                                                                         \
-    if (jit != nullptr) {                                                                      \
-      jit->AddSamples(self, method, 1, /*with_backedges*/ true);                               \
-    }                                                                                          \
-  } while (false)
-
-#define UNREACHABLE_CODE_CHECK()                \
-  do {                                          \
-    if (kIsDebugBuild) {                        \
-      LOG(FATAL) << "We should not be here !";  \
-      UNREACHABLE();                            \
-    }                                           \
-  } while (false)
-
-#define HANDLE_INSTRUCTION_START(opcode) op_##opcode:  // NOLINT(whitespace/labels)
-#define HANDLE_INSTRUCTION_END() UNREACHABLE_CODE_CHECK()
-
-#define HANDLE_MONITOR_CHECKS()                                                                   \
-  if (!DoMonitorCheckOnExit<do_assignability_check>(self, &shadow_frame)) {                       \
-    HANDLE_PENDING_EXCEPTION();                                                                   \
-  }
-
-/**
- * Interpreter based on computed goto tables.
- *
- * Each instruction is associated to a handler. This handler is responsible for executing the
- * instruction and jump to the next instruction's handler.
- * In order to limit the cost of instrumentation, we have two handler tables:
- * - the "main" handler table: it contains handlers for normal execution of each instruction without
- * handling of instrumentation.
- * - the "alternative" handler table: it contains alternative handlers which first handle
- * instrumentation before jumping to the corresponding "normal" instruction's handler.
- *
- * When instrumentation is active, the interpreter uses the "alternative" handler table. Otherwise
- * it uses the "main" handler table.
- *
- * The current handler table is the handler table being used by the interpreter. It is updated:
- * - on backward branch (goto, if and switch instructions)
- * - after invoke
- * - when an exception is thrown.
- * This allows to support an attaching debugger to an already running application for instance.
- *
- * For a fast handler table update, handler tables are stored in an array of handler tables. Each
- * handler table is represented by the InterpreterHandlerTable enum which allows to associate it
- * to an index in this array of handler tables ((see Instrumentation::GetInterpreterHandlerTable).
- *
- * Here's the current layout of this array of handler tables:
- *
- * ---------------------+---------------+
- *                      |     NOP       | (handler for NOP instruction)
- *                      +---------------+
- *       "main"         |     MOVE      | (handler for MOVE instruction)
- *    handler table     +---------------+
- *                      |      ...      |
- *                      +---------------+
- *                      |   UNUSED_FF   | (handler for UNUSED_FF instruction)
- * ---------------------+---------------+
- *                      |     NOP       | (alternative handler for NOP instruction)
- *                      +---------------+
- *    "alternative"     |     MOVE      | (alternative handler for MOVE instruction)
- *    handler table     +---------------+
- *                      |      ...      |
- *                      +---------------+
- *                      |   UNUSED_FF   | (alternative handler for UNUSED_FF instruction)
- * ---------------------+---------------+
- *
- */
-template<bool do_access_check, bool transaction_active>
-JValue ExecuteGotoImpl(Thread* self, const DexFile::CodeItem* code_item, ShadowFrame& shadow_frame,
-                       JValue result_register) {
-  // Define handler tables:
-  // - The main handler table contains execution handlers for each instruction.
-  // - The alternative handler table contains prelude handlers which check for thread suspend and
-  //   manage instrumentation before jumping to the execution handler.
-  static const void* const handlersTable[instrumentation::kNumHandlerTables][kNumPackedOpcodes] = {
-    {
-    // Main handler table.
-#define INSTRUCTION_HANDLER(o, code, n, f, i, a, v) &&op_##code,
-#include "dex_instruction_list.h"
-      DEX_INSTRUCTION_LIST(INSTRUCTION_HANDLER)
-#undef DEX_INSTRUCTION_LIST
-#undef INSTRUCTION_HANDLER
-    }, {
-    // Alternative handler table.
-#define INSTRUCTION_HANDLER(o, code, n, f, i, a, v) &&alt_op_##code,
-#include "dex_instruction_list.h"
-      DEX_INSTRUCTION_LIST(INSTRUCTION_HANDLER)
-#undef DEX_INSTRUCTION_LIST
-#undef INSTRUCTION_HANDLER
-    }
-  };
-
-  constexpr bool do_assignability_check = do_access_check;
-  if (UNLIKELY(!shadow_frame.HasReferenceArray())) {
-    LOG(FATAL) << "Invalid shadow frame for interpreter use";
-    return JValue();
-  }
-  self->VerifyStack();
-
-  uint32_t dex_pc = shadow_frame.GetDexPC();
-  const Instruction* inst = Instruction::At(code_item->insns_ + dex_pc);
-  uint16_t inst_data;
-  const void* const* currentHandlersTable;
-  UPDATE_HANDLER_TABLE();
-  const auto* const instrumentation = Runtime::Current()->GetInstrumentation();
-  ArtMethod* method = shadow_frame.GetMethod();
-  jit::Jit* jit = Runtime::Current()->GetJit();
-
-  // Jump to first instruction.
-  ADVANCE(0);
-  UNREACHABLE_CODE_CHECK();
-
-  HANDLE_INSTRUCTION_START(NOP)
-    ADVANCE(1);
-  HANDLE_INSTRUCTION_END();
-
-  HANDLE_INSTRUCTION_START(MOVE)
-    shadow_frame.SetVReg(inst->VRegA_12x(inst_data),
-                         shadow_frame.GetVReg(inst->VRegB_12x(inst_data)));
-    ADVANCE(1);
-  HANDLE_INSTRUCTION_END();
-
-  HANDLE_INSTRUCTION_START(MOVE_FROM16)
-    shadow_frame.SetVReg(inst->VRegA_22x(inst_data),
-                         shadow_frame.GetVReg(inst->VRegB_22x()));
-    ADVANCE(2);
-  HANDLE_INSTRUCTION_END();
-
-  HANDLE_INSTRUCTION_START(MOVE_16)
-    shadow_frame.SetVReg(inst->VRegA_32x(),
-                         shadow_frame.GetVReg(inst->VRegB_32x()));
-    ADVANCE(3);
-  HANDLE_INSTRUCTION_END();
-
-  HANDLE_INSTRUCTION_START(MOVE_WIDE)
-    shadow_frame.SetVRegLong(inst->VRegA_12x(inst_data),
-                             shadow_frame.GetVRegLong(inst->VRegB_12x(inst_data)));
-    ADVANCE(1);
-  HANDLE_INSTRUCTION_END();
-
-  HANDLE_INSTRUCTION_START(MOVE_WIDE_FROM16)
-    shadow_frame.SetVRegLong(inst->VRegA_22x(inst_data),
-                             shadow_frame.GetVRegLong(inst->VRegB_22x()));
-    ADVANCE(2);
-  HANDLE_INSTRUCTION_END();
-
-  HANDLE_INSTRUCTION_START(MOVE_WIDE_16)
-    shadow_frame.SetVRegLong(inst->VRegA_32x(),
-                             shadow_frame.GetVRegLong(inst->VRegB_32x()));
-    ADVANCE(3);
-  HANDLE_INSTRUCTION_END();
-
-  HANDLE_INSTRUCTION_START(MOVE_OBJECT)
-    shadow_frame.SetVRegReference(inst->VRegA_12x(inst_data),
-                                  shadow_frame.GetVRegReference(inst->VRegB_12x(inst_data)));
-    ADVANCE(1);
-  HANDLE_INSTRUCTION_END();
-
-  HANDLE_INSTRUCTION_START(MOVE_OBJECT_FROM16)
-    shadow_frame.SetVRegReference(inst->VRegA_22x(inst_data),
-                                  shadow_frame.GetVRegReference(inst->VRegB_22x()));
-    ADVANCE(2);
-  HANDLE_INSTRUCTION_END();
-
-  HANDLE_INSTRUCTION_START(MOVE_OBJECT_16)
-    shadow_frame.SetVRegReference(inst->VRegA_32x(),
-                                  shadow_frame.GetVRegReference(inst->VRegB_32x()));
-    ADVANCE(3);
-  HANDLE_INSTRUCTION_END();
-
-  HANDLE_INSTRUCTION_START(MOVE_RESULT)
-    shadow_frame.SetVReg(inst->VRegA_11x(inst_data), result_register.GetI());
-    ADVANCE(1);
-  HANDLE_INSTRUCTION_END();
-
-  HANDLE_INSTRUCTION_START(MOVE_RESULT_WIDE)
-    shadow_frame.SetVRegLong(inst->VRegA_11x(inst_data), result_register.GetJ());
-    ADVANCE(1);
-  HANDLE_INSTRUCTION_END();
-
-  HANDLE_INSTRUCTION_START(MOVE_RESULT_OBJECT)
-    shadow_frame.SetVRegReference(inst->VRegA_11x(inst_data), result_register.GetL());
-    ADVANCE(1);
-  HANDLE_INSTRUCTION_END();
-
-  HANDLE_INSTRUCTION_START(MOVE_EXCEPTION) {
-    Throwable* exception = self->GetException();
-    DCHECK(exception != nullptr) << "No pending exception on MOVE_EXCEPTION instruction";
-    shadow_frame.SetVRegReference(inst->VRegA_11x(inst_data), exception);
-    self->ClearException();
-    ADVANCE(1);
-  }
-  HANDLE_INSTRUCTION_END();
-
-  HANDLE_INSTRUCTION_START(RETURN_VOID_NO_BARRIER) {
-    JValue result;
-    self->AllowThreadSuspension();
-    HANDLE_MONITOR_CHECKS();
-    if (UNLIKELY(instrumentation->HasMethodExitListeners())) {
-      instrumentation->MethodExitEvent(self, shadow_frame.GetThisObject(code_item->ins_size_),
-                                       shadow_frame.GetMethod(), dex_pc,
-                                       result);
-    }
-    return result;
-  }
-  HANDLE_INSTRUCTION_END();
-
-  HANDLE_INSTRUCTION_START(RETURN_VOID) {
-    QuasiAtomic::ThreadFenceForConstructor();
-    JValue result;
-    self->AllowThreadSuspension();
-    HANDLE_MONITOR_CHECKS();
-    if (UNLIKELY(instrumentation->HasMethodExitListeners())) {
-      instrumentation->MethodExitEvent(self, shadow_frame.GetThisObject(code_item->ins_size_),
-                                       shadow_frame.GetMethod(), dex_pc,
-                                       result);
-    }
-    return result;
-  }
-  HANDLE_INSTRUCTION_END();
-
-  HANDLE_INSTRUCTION_START(RETURN) {
-    JValue result;
-    result.SetJ(0);
-    result.SetI(shadow_frame.GetVReg(inst->VRegA_11x(inst_data)));
-    self->AllowThreadSuspension();
-    HANDLE_MONITOR_CHECKS();
-    if (UNLIKELY(instrumentation->HasMethodExitListeners())) {
-      instrumentation->MethodExitEvent(self, shadow_frame.GetThisObject(code_item->ins_size_),
-                                       shadow_frame.GetMethod(), dex_pc,
-                                       result);
-    }
-    return result;
-  }
-  HANDLE_INSTRUCTION_END();
-
-  HANDLE_INSTRUCTION_START(RETURN_WIDE) {
-    JValue result;
-    result.SetJ(shadow_frame.GetVRegLong(inst->VRegA_11x(inst_data)));
-    self->AllowThreadSuspension();
-    HANDLE_MONITOR_CHECKS();
-    if (UNLIKELY(instrumentation->HasMethodExitListeners())) {
-      instrumentation->MethodExitEvent(self, shadow_frame.GetThisObject(code_item->ins_size_),
-                                       shadow_frame.GetMethod(), dex_pc,
-                                       result);
-    }
-    return result;
-  }
-  HANDLE_INSTRUCTION_END();
-
-  HANDLE_INSTRUCTION_START(RETURN_OBJECT) {
-    JValue result;
-    self->AllowThreadSuspension();
-    HANDLE_MONITOR_CHECKS();
-    const uint8_t vreg_index = inst->VRegA_11x(inst_data);
-    Object* obj_result = shadow_frame.GetVRegReference(vreg_index);
-    if (do_assignability_check && obj_result != nullptr) {
-      size_t pointer_size = Runtime::Current()->GetClassLinker()->GetImagePointerSize();
-      Class* return_type = shadow_frame.GetMethod()->GetReturnType(true /* resolve */,
-                                                                   pointer_size);
-      obj_result = shadow_frame.GetVRegReference(vreg_index);
-      if (return_type == nullptr) {
-        // Return the pending exception.
-        HANDLE_PENDING_EXCEPTION();
-      }
-      if (!obj_result->VerifierInstanceOf(return_type)) {
-        // This should never happen.
-        std::string temp1, temp2;
-        self->ThrowNewExceptionF("Ljava/lang/VirtualMachineError;",
-                                 "Returning '%s' that is not instance of return type '%s'",
-                                 obj_result->GetClass()->GetDescriptor(&temp1),
-                                 return_type->GetDescriptor(&temp2));
-        HANDLE_PENDING_EXCEPTION();
-      }
-    }
-    result.SetL(obj_result);
-    if (UNLIKELY(instrumentation->HasMethodExitListeners())) {
-      instrumentation->MethodExitEvent(self, shadow_frame.GetThisObject(code_item->ins_size_),
-                                       shadow_frame.GetMethod(), dex_pc,
-                                       result);
-    }
-    return result;
-  }
-  HANDLE_INSTRUCTION_END();
-
-  HANDLE_INSTRUCTION_START(CONST_4) {
-    uint32_t dst = inst->VRegA_11n(inst_data);
-    int32_t val = inst->VRegB_11n(inst_data);
-    shadow_frame.SetVReg(dst, val);
-    if (val == 0) {
-      shadow_frame.SetVRegReference(dst, nullptr);
-    }
-    ADVANCE(1);
-  }
-  HANDLE_INSTRUCTION_END();
-
-  HANDLE_INSTRUCTION_START(CONST_16) {
-    uint32_t dst = inst->VRegA_21s(inst_data);
-    int32_t val = inst->VRegB_21s();
-    shadow_frame.SetVReg(dst, val);
-    if (val == 0) {
-      shadow_frame.SetVRegReference(dst, nullptr);
-    }
-    ADVANCE(2);
-  }
-  HANDLE_INSTRUCTION_END();
-
-  HANDLE_INSTRUCTION_START(CONST) {
-    uint32_t dst = inst->VRegA_31i(inst_data);
-    int32_t val = inst->VRegB_31i();
-    shadow_frame.SetVReg(dst, val);
-    if (val == 0) {
-      shadow_frame.SetVRegReference(dst, nullptr);
-    }
-    ADVANCE(3);
-  }
-  HANDLE_INSTRUCTION_END();
-
-  HANDLE_INSTRUCTION_START(CONST_HIGH16) {
-    uint32_t dst = inst->VRegA_21h(inst_data);
-    int32_t val = static_cast<int32_t>(inst->VRegB_21h() << 16);
-    shadow_frame.SetVReg(dst, val);
-    if (val == 0) {
-      shadow_frame.SetVRegReference(dst, nullptr);
-    }
-    ADVANCE(2);
-  }
-  HANDLE_INSTRUCTION_END();
-
-  HANDLE_INSTRUCTION_START(CONST_WIDE_16)
-    shadow_frame.SetVRegLong(inst->VRegA_21s(inst_data), inst->VRegB_21s());
-    ADVANCE(2);
-  HANDLE_INSTRUCTION_END();
-
-  HANDLE_INSTRUCTION_START(CONST_WIDE_32)
-    shadow_frame.SetVRegLong(inst->VRegA_31i(inst_data), inst->VRegB_31i());
-    ADVANCE(3);
-  HANDLE_INSTRUCTION_END();
-
-  HANDLE_INSTRUCTION_START(CONST_WIDE)
-    shadow_frame.SetVRegLong(inst->VRegA_51l(inst_data), inst->VRegB_51l());
-    ADVANCE(5);
-  HANDLE_INSTRUCTION_END();
-
-  HANDLE_INSTRUCTION_START(CONST_WIDE_HIGH16)
-    shadow_frame.SetVRegLong(inst->VRegA_21h(inst_data),
-                             static_cast<uint64_t>(inst->VRegB_21h()) << 48);
-    ADVANCE(2);
-  HANDLE_INSTRUCTION_END();
-
-  HANDLE_INSTRUCTION_START(CONST_STRING) {
-    String* s = ResolveString(self, shadow_frame, inst->VRegB_21c());
-    if (UNLIKELY(s == nullptr)) {
-      HANDLE_PENDING_EXCEPTION();
-    } else {
-      shadow_frame.SetVRegReference(inst->VRegA_21c(inst_data), s);
-      ADVANCE(2);
-    }
-  }
-  HANDLE_INSTRUCTION_END();
-
-  HANDLE_INSTRUCTION_START(CONST_STRING_JUMBO) {
-    String* s = ResolveString(self, shadow_frame, inst->VRegB_31c());
-    if (UNLIKELY(s == nullptr)) {
-      HANDLE_PENDING_EXCEPTION();
-    } else {
-      shadow_frame.SetVRegReference(inst->VRegA_31c(inst_data), s);
-      ADVANCE(3);
-    }
-  }
-  HANDLE_INSTRUCTION_END();
-
-  HANDLE_INSTRUCTION_START(CONST_CLASS) {
-    Class* c = ResolveVerifyAndClinit(inst->VRegB_21c(), shadow_frame.GetMethod(),
-                                      self, false, do_access_check);
-    if (UNLIKELY(c == nullptr)) {
-      HANDLE_PENDING_EXCEPTION();
-    } else {
-      shadow_frame.SetVRegReference(inst->VRegA_21c(inst_data), c);
-      ADVANCE(2);
-    }
-  }
-  HANDLE_INSTRUCTION_END();
-
-  HANDLE_INSTRUCTION_START(MONITOR_ENTER) {
-    Object* obj = shadow_frame.GetVRegReference(inst->VRegA_11x(inst_data));
-    if (UNLIKELY(obj == nullptr)) {
-      ThrowNullPointerExceptionFromInterpreter();
-      HANDLE_PENDING_EXCEPTION();
-    } else {
-      DoMonitorEnter<do_access_check>(self, &shadow_frame, obj);
-      POSSIBLY_HANDLE_PENDING_EXCEPTION(self->IsExceptionPending(), 1);
-    }
-  }
-  HANDLE_INSTRUCTION_END();
-
-  HANDLE_INSTRUCTION_START(MONITOR_EXIT) {
-    Object* obj = shadow_frame.GetVRegReference(inst->VRegA_11x(inst_data));
-    if (UNLIKELY(obj == nullptr)) {
-      ThrowNullPointerExceptionFromInterpreter();
-      HANDLE_PENDING_EXCEPTION();
-    } else {
-      DoMonitorExit<do_access_check>(self, &shadow_frame, obj);
-      POSSIBLY_HANDLE_PENDING_EXCEPTION(self->IsExceptionPending(), 1);
-    }
-  }
-  HANDLE_INSTRUCTION_END();
-
-  HANDLE_INSTRUCTION_START(CHECK_CAST) {
-    Class* c = ResolveVerifyAndClinit(inst->VRegB_21c(), shadow_frame.GetMethod(),
-                                      self, false, do_access_check);
-    if (UNLIKELY(c == nullptr)) {
-      HANDLE_PENDING_EXCEPTION();
-    } else {
-      Object* obj = shadow_frame.GetVRegReference(inst->VRegA_21c(inst_data));
-      if (UNLIKELY(obj != nullptr && !obj->InstanceOf(c))) {
-        ThrowClassCastException(c, obj->GetClass());
-        HANDLE_PENDING_EXCEPTION();
-      } else {
-        ADVANCE(2);
-      }
-    }
-  }
-  HANDLE_INSTRUCTION_END();
-
-  HANDLE_INSTRUCTION_START(INSTANCE_OF) {
-    Class* c = ResolveVerifyAndClinit(inst->VRegC_22c(), shadow_frame.GetMethod(),
-                                      self, false, do_access_check);
-    if (UNLIKELY(c == nullptr)) {
-      HANDLE_PENDING_EXCEPTION();
-    } else {
-      Object* obj = shadow_frame.GetVRegReference(inst->VRegB_22c(inst_data));
-      shadow_frame.SetVReg(inst->VRegA_22c(inst_data), (obj != nullptr && obj->InstanceOf(c)) ? 1 : 0);
-      ADVANCE(2);
-    }
-  }
-  HANDLE_INSTRUCTION_END();
-
-  HANDLE_INSTRUCTION_START(ARRAY_LENGTH) {
-    Object* array = shadow_frame.GetVRegReference(inst->VRegB_12x(inst_data));
-    if (UNLIKELY(array == nullptr)) {
-      ThrowNullPointerExceptionFromInterpreter();
-      HANDLE_PENDING_EXCEPTION();
-    } else {
-      shadow_frame.SetVReg(inst->VRegA_12x(inst_data), array->AsArray()->GetLength());
-      ADVANCE(1);
-    }
-  }
-  HANDLE_INSTRUCTION_END();
-
-  HANDLE_INSTRUCTION_START(NEW_INSTANCE) {
-    Object* obj = nullptr;
-    Class* c = ResolveVerifyAndClinit(inst->VRegB_21c(), shadow_frame.GetMethod(),
-                                      self, false, do_access_check);
-    if (LIKELY(c != nullptr)) {
-      if (UNLIKELY(c->IsStringClass())) {
-        gc::AllocatorType allocator_type = Runtime::Current()->GetHeap()->GetCurrentAllocator();
-        obj = mirror::String::AllocEmptyString<true>(self, allocator_type);
-      } else {
-        obj = AllocObjectFromCode<do_access_check, true>(
-            inst->VRegB_21c(), shadow_frame.GetMethod(), self,
-            Runtime::Current()->GetHeap()->GetCurrentAllocator());
-      }
-    }
-    if (UNLIKELY(obj == nullptr)) {
-      HANDLE_PENDING_EXCEPTION();
-    } else {
-      obj->GetClass()->AssertInitializedOrInitializingInThread(self);
-      // Don't allow finalizable objects to be allocated during a transaction since these can't be
-      // finalized without a started runtime.
-      if (transaction_active && obj->GetClass()->IsFinalizable()) {
-        AbortTransactionF(self, "Allocating finalizable object in transaction: %s",
-                          PrettyTypeOf(obj).c_str());
-        HANDLE_PENDING_EXCEPTION();
-      }
-      shadow_frame.SetVRegReference(inst->VRegA_21c(inst_data), obj);
-      ADVANCE(2);
-    }
-  }
-  HANDLE_INSTRUCTION_END();
-
-  HANDLE_INSTRUCTION_START(NEW_ARRAY) {
-    int32_t length = shadow_frame.GetVReg(inst->VRegB_22c(inst_data));
-    Object* obj = AllocArrayFromCode<do_access_check, true>(
-        inst->VRegC_22c(), length, shadow_frame.GetMethod(), self,
-        Runtime::Current()->GetHeap()->GetCurrentAllocator());
-    if (UNLIKELY(obj == nullptr)) {
-      HANDLE_PENDING_EXCEPTION();
-    } else {
-      shadow_frame.SetVRegReference(inst->VRegA_22c(inst_data), obj);
-      ADVANCE(2);
-    }
-  }
-  HANDLE_INSTRUCTION_END();
-
-  HANDLE_INSTRUCTION_START(FILLED_NEW_ARRAY) {
-    bool success =
-        DoFilledNewArray<false, do_access_check, transaction_active>(inst, shadow_frame,
-                                                                     self, &result_register);
-    POSSIBLY_HANDLE_PENDING_EXCEPTION(!success, 3);
-  }
-  HANDLE_INSTRUCTION_END();
-
-  HANDLE_INSTRUCTION_START(FILLED_NEW_ARRAY_RANGE) {
-    bool success =
-        DoFilledNewArray<true, do_access_check, transaction_active>(inst, shadow_frame,
-                                                                    self, &result_register);
-    POSSIBLY_HANDLE_PENDING_EXCEPTION(!success, 3);
-  }
-  HANDLE_INSTRUCTION_END();
-
-  HANDLE_INSTRUCTION_START(FILL_ARRAY_DATA) {
-    Object* obj = shadow_frame.GetVRegReference(inst->VRegA_31t(inst_data));
-    const uint16_t* payload_addr = reinterpret_cast<const uint16_t*>(inst) + inst->VRegB_31t();
-    const Instruction::ArrayDataPayload* payload =
-        reinterpret_cast<const Instruction::ArrayDataPayload*>(payload_addr);
-    bool success = FillArrayData(obj, payload);
-    if (transaction_active && success) {
-      RecordArrayElementsInTransaction(obj->AsArray(), payload->element_count);
-    }
-    POSSIBLY_HANDLE_PENDING_EXCEPTION(!success, 3);
-  }
-  HANDLE_INSTRUCTION_END();
-
-  HANDLE_INSTRUCTION_START(THROW) {
-    Object* exception = shadow_frame.GetVRegReference(inst->VRegA_11x(inst_data));
-    if (UNLIKELY(exception == nullptr)) {
-      ThrowNullPointerException("throw with null exception");
-    } else if (do_assignability_check && !exception->GetClass()->IsThrowableClass()) {
-      // This should never happen.
-      std::string temp;
-      self->ThrowNewExceptionF("Ljava/lang/VirtualMachineError;",
-                               "Throwing '%s' that is not instance of Throwable",
-                               exception->GetClass()->GetDescriptor(&temp));
-    } else {
-      self->SetException(exception->AsThrowable());
-    }
-    HANDLE_PENDING_EXCEPTION();
-  }
-  HANDLE_INSTRUCTION_END();
-
-  HANDLE_INSTRUCTION_START(GOTO) {
-    int8_t offset = inst->VRegA_10t(inst_data);
-    BRANCH_INSTRUMENTATION(offset);
-    if (IsBackwardBranch(offset)) {
-      HOTNESS_UPDATE();
-      if (UNLIKELY(self->TestAllFlags())) {
-        self->CheckSuspend();
-        UPDATE_HANDLER_TABLE();
-      }
-    }
-    ADVANCE(offset);
-  }
-  HANDLE_INSTRUCTION_END();
-
-  HANDLE_INSTRUCTION_START(GOTO_16) {
-    int16_t offset = inst->VRegA_20t();
-    BRANCH_INSTRUMENTATION(offset);
-    if (IsBackwardBranch(offset)) {
-      HOTNESS_UPDATE();
-      if (UNLIKELY(self->TestAllFlags())) {
-        self->CheckSuspend();
-        UPDATE_HANDLER_TABLE();
-      }
-    }
-    ADVANCE(offset);
-  }
-  HANDLE_INSTRUCTION_END();
-
-  HANDLE_INSTRUCTION_START(GOTO_32) {
-    int32_t offset = inst->VRegA_30t();
-    BRANCH_INSTRUMENTATION(offset);
-    if (IsBackwardBranch(offset)) {
-      HOTNESS_UPDATE();
-      if (UNLIKELY(self->TestAllFlags())) {
-        self->CheckSuspend();
-        UPDATE_HANDLER_TABLE();
-      }
-    }
-    ADVANCE(offset);
-  }
-  HANDLE_INSTRUCTION_END();
-
-  HANDLE_INSTRUCTION_START(PACKED_SWITCH) {
-    int32_t offset = DoPackedSwitch(inst, shadow_frame, inst_data);
-    BRANCH_INSTRUMENTATION(offset);
-    if (IsBackwardBranch(offset)) {
-      HOTNESS_UPDATE();
-      if (UNLIKELY(self->TestAllFlags())) {
-        self->CheckSuspend();
-        UPDATE_HANDLER_TABLE();
-      }
-    }
-    ADVANCE(offset);
-  }
-  HANDLE_INSTRUCTION_END();
-
-  HANDLE_INSTRUCTION_START(SPARSE_SWITCH) {
-    int32_t offset = DoSparseSwitch(inst, shadow_frame, inst_data);
-    BRANCH_INSTRUMENTATION(offset);
-    if (IsBackwardBranch(offset)) {
-      HOTNESS_UPDATE();
-      if (UNLIKELY(self->TestAllFlags())) {
-        self->CheckSuspend();
-        UPDATE_HANDLER_TABLE();
-      }
-    }
-    ADVANCE(offset);
-  }
-  HANDLE_INSTRUCTION_END();
-
-#if defined(__clang__)
-#pragma clang diagnostic push
-#pragma clang diagnostic ignored "-Wfloat-equal"
-#endif
-
-  HANDLE_INSTRUCTION_START(CMPL_FLOAT) {
-    float val1 = shadow_frame.GetVRegFloat(inst->VRegB_23x());
-    float val2 = shadow_frame.GetVRegFloat(inst->VRegC_23x());
-    int32_t result;
-    if (val1 > val2) {
-      result = 1;
-    } else if (val1 == val2) {
-      result = 0;
-    } else {
-      result = -1;
-    }
-    shadow_frame.SetVReg(inst->VRegA_23x(inst_data), result);
-    ADVANCE(2);
-  }
-  HANDLE_INSTRUCTION_END();
-
-  HANDLE_INSTRUCTION_START(CMPG_FLOAT) {
-    float val1 = shadow_frame.GetVRegFloat(inst->VRegB_23x());
-    float val2 = shadow_frame.GetVRegFloat(inst->VRegC_23x());
-    int32_t result;
-    if (val1 < val2) {
-      result = -1;
-    } else if (val1 == val2) {
-      result = 0;
-    } else {
-      result = 1;
-    }
-    shadow_frame.SetVReg(inst->VRegA_23x(inst_data), result);
-    ADVANCE(2);
-  }
-  HANDLE_INSTRUCTION_END();
-
-  HANDLE_INSTRUCTION_START(CMPL_DOUBLE) {
-    double val1 = shadow_frame.GetVRegDouble(inst->VRegB_23x());
-    double val2 = shadow_frame.GetVRegDouble(inst->VRegC_23x());
-    int32_t result;
-    if (val1 > val2) {
-      result = 1;
-    } else if (val1 == val2) {
-      result = 0;
-    } else {
-      result = -1;
-    }
-    shadow_frame.SetVReg(inst->VRegA_23x(inst_data), result);
-    ADVANCE(2);
-  }
-  HANDLE_INSTRUCTION_END();
-
-  HANDLE_INSTRUCTION_START(CMPG_DOUBLE) {
-    double val1 = shadow_frame.GetVRegDouble(inst->VRegB_23x());
-    double val2 = shadow_frame.GetVRegDouble(inst->VRegC_23x());
-    int32_t result;
-    if (val1 < val2) {
-      result = -1;
-    } else if (val1 == val2) {
-      result = 0;
-    } else {
-      result = 1;
-    }
-    shadow_frame.SetVReg(inst->VRegA_23x(inst_data), result);
-    ADVANCE(2);
-  }
-  HANDLE_INSTRUCTION_END();
-
-#if defined(__clang__)
-#pragma clang diagnostic pop
-#endif
-
-  HANDLE_INSTRUCTION_START(CMP_LONG) {
-    int64_t val1 = shadow_frame.GetVRegLong(inst->VRegB_23x());
-    int64_t val2 = shadow_frame.GetVRegLong(inst->VRegC_23x());
-    int32_t result;
-    if (val1 > val2) {
-      result = 1;
-    } else if (val1 == val2) {
-      result = 0;
-    } else {
-      result = -1;
-    }
-    shadow_frame.SetVReg(inst->VRegA_23x(inst_data), result);
-    ADVANCE(2);
-  }
-  HANDLE_INSTRUCTION_END();
-
-  HANDLE_INSTRUCTION_START(IF_EQ) {
-    if (shadow_frame.GetVReg(inst->VRegA_22t(inst_data)) == shadow_frame.GetVReg(inst->VRegB_22t(inst_data))) {
-      int16_t offset = inst->VRegC_22t();
-      BRANCH_INSTRUMENTATION(offset);
-      if (IsBackwardBranch(offset)) {
-        HOTNESS_UPDATE();
-        if (UNLIKELY(self->TestAllFlags())) {
-          self->CheckSuspend();
-          UPDATE_HANDLER_TABLE();
-        }
-      }
-      ADVANCE(offset);
-    } else {
-      BRANCH_INSTRUMENTATION(2);
-      ADVANCE(2);
-    }
-  }
-  HANDLE_INSTRUCTION_END();
-
-  HANDLE_INSTRUCTION_START(IF_NE) {
-    if (shadow_frame.GetVReg(inst->VRegA_22t(inst_data)) !=
-        shadow_frame.GetVReg(inst->VRegB_22t(inst_data))) {
-      int16_t offset = inst->VRegC_22t();
-      BRANCH_INSTRUMENTATION(offset);
-      if (IsBackwardBranch(offset)) {
-        HOTNESS_UPDATE();
-        if (UNLIKELY(self->TestAllFlags())) {
-          self->CheckSuspend();
-          UPDATE_HANDLER_TABLE();
-        }
-      }
-      ADVANCE(offset);
-    } else {
-      BRANCH_INSTRUMENTATION(2);
-      ADVANCE(2);
-    }
-  }
-  HANDLE_INSTRUCTION_END();
-
-  HANDLE_INSTRUCTION_START(IF_LT) {
-    if (shadow_frame.GetVReg(inst->VRegA_22t(inst_data)) <
-        shadow_frame.GetVReg(inst->VRegB_22t(inst_data))) {
-      int16_t offset = inst->VRegC_22t();
-      BRANCH_INSTRUMENTATION(offset);
-      if (IsBackwardBranch(offset)) {
-        HOTNESS_UPDATE();
-        if (UNLIKELY(self->TestAllFlags())) {
-          self->CheckSuspend();
-          UPDATE_HANDLER_TABLE();
-        }
-      }
-      ADVANCE(offset);
-    } else {
-      BRANCH_INSTRUMENTATION(2);
-      ADVANCE(2);
-    }
-  }
-  HANDLE_INSTRUCTION_END();
-
-  HANDLE_INSTRUCTION_START(IF_GE) {
-    if (shadow_frame.GetVReg(inst->VRegA_22t(inst_data)) >=
-        shadow_frame.GetVReg(inst->VRegB_22t(inst_data))) {
-      int16_t offset = inst->VRegC_22t();
-      BRANCH_INSTRUMENTATION(offset);
-      if (IsBackwardBranch(offset)) {
-        HOTNESS_UPDATE();
-        if (UNLIKELY(self->TestAllFlags())) {
-          self->CheckSuspend();
-          UPDATE_HANDLER_TABLE();
-        }
-      }
-      ADVANCE(offset);
-    } else {
-      BRANCH_INSTRUMENTATION(2);
-      ADVANCE(2);
-    }
-  }
-  HANDLE_INSTRUCTION_END();
-
-  HANDLE_INSTRUCTION_START(IF_GT) {
-    if (shadow_frame.GetVReg(inst->VRegA_22t(inst_data)) >
-    shadow_frame.GetVReg(inst->VRegB_22t(inst_data))) {
-      int16_t offset = inst->VRegC_22t();
-      BRANCH_INSTRUMENTATION(offset);
-      if (IsBackwardBranch(offset)) {
-        HOTNESS_UPDATE();
-        if (UNLIKELY(self->TestAllFlags())) {
-          self->CheckSuspend();
-          UPDATE_HANDLER_TABLE();
-        }
-      }
-      ADVANCE(offset);
-    } else {
-      BRANCH_INSTRUMENTATION(2);
-      ADVANCE(2);
-    }
-  }
-  HANDLE_INSTRUCTION_END();
-
-  HANDLE_INSTRUCTION_START(IF_LE) {
-    if (shadow_frame.GetVReg(inst->VRegA_22t(inst_data)) <=
-        shadow_frame.GetVReg(inst->VRegB_22t(inst_data))) {
-      int16_t offset = inst->VRegC_22t();
-      BRANCH_INSTRUMENTATION(offset);
-      if (IsBackwardBranch(offset)) {
-        HOTNESS_UPDATE();
-        if (UNLIKELY(self->TestAllFlags())) {
-          self->CheckSuspend();
-          UPDATE_HANDLER_TABLE();
-        }
-      }
-      ADVANCE(offset);
-    } else {
-      BRANCH_INSTRUMENTATION(2);
-      ADVANCE(2);
-    }
-  }
-  HANDLE_INSTRUCTION_END();
-
-  HANDLE_INSTRUCTION_START(IF_EQZ) {
-    if (shadow_frame.GetVReg(inst->VRegA_21t(inst_data)) == 0) {
-      int16_t offset = inst->VRegB_21t();
-      BRANCH_INSTRUMENTATION(offset);
-      if (IsBackwardBranch(offset)) {
-        HOTNESS_UPDATE();
-        if (UNLIKELY(self->TestAllFlags())) {
-          self->CheckSuspend();
-          UPDATE_HANDLER_TABLE();
-        }
-      }
-      ADVANCE(offset);
-    } else {
-      BRANCH_INSTRUMENTATION(2);
-      ADVANCE(2);
-    }
-  }
-  HANDLE_INSTRUCTION_END();
-
-  HANDLE_INSTRUCTION_START(IF_NEZ) {
-    if (shadow_frame.GetVReg(inst->VRegA_21t(inst_data)) != 0) {
-      int16_t offset = inst->VRegB_21t();
-      BRANCH_INSTRUMENTATION(offset);
-      if (IsBackwardBranch(offset)) {
-        HOTNESS_UPDATE();
-        if (UNLIKELY(self->TestAllFlags())) {
-          self->CheckSuspend();
-          UPDATE_HANDLER_TABLE();
-        }
-      }
-      ADVANCE(offset);
-    } else {
-      BRANCH_INSTRUMENTATION(2);
-      ADVANCE(2);
-    }
-  }
-  HANDLE_INSTRUCTION_END();
-
-  HANDLE_INSTRUCTION_START(IF_LTZ) {
-    if (shadow_frame.GetVReg(inst->VRegA_21t(inst_data)) < 0) {
-      int16_t offset = inst->VRegB_21t();
-      BRANCH_INSTRUMENTATION(offset);
-      if (IsBackwardBranch(offset)) {
-        HOTNESS_UPDATE();
-        if (UNLIKELY(self->TestAllFlags())) {
-          self->CheckSuspend();
-          UPDATE_HANDLER_TABLE();
-        }
-      }
-      ADVANCE(offset);
-    } else {
-      BRANCH_INSTRUMENTATION(2);
-      ADVANCE(2);
-    }
-  }
-  HANDLE_INSTRUCTION_END();
-
-  HANDLE_INSTRUCTION_START(IF_GEZ) {
-    if (shadow_frame.GetVReg(inst->VRegA_21t(inst_data)) >= 0) {
-      int16_t offset = inst->VRegB_21t();
-      BRANCH_INSTRUMENTATION(offset);
-      if (IsBackwardBranch(offset)) {
-        HOTNESS_UPDATE();
-        if (UNLIKELY(self->TestAllFlags())) {
-          self->CheckSuspend();
-          UPDATE_HANDLER_TABLE();
-        }
-      }
-      ADVANCE(offset);
-    } else {
-      BRANCH_INSTRUMENTATION(2);
-      ADVANCE(2);
-    }
-  }
-  HANDLE_INSTRUCTION_END();
-
-  HANDLE_INSTRUCTION_START(IF_GTZ) {
-    if (shadow_frame.GetVReg(inst->VRegA_21t(inst_data)) > 0) {
-      int16_t offset = inst->VRegB_21t();
-      BRANCH_INSTRUMENTATION(offset);
-      if (IsBackwardBranch(offset)) {
-        HOTNESS_UPDATE();
-        if (UNLIKELY(self->TestAllFlags())) {
-          self->CheckSuspend();
-          UPDATE_HANDLER_TABLE();
-        }
-      }
-      ADVANCE(offset);
-    } else {
-      BRANCH_INSTRUMENTATION(2);
-      ADVANCE(2);
-    }
-  }
-  HANDLE_INSTRUCTION_END();
-
-  HANDLE_INSTRUCTION_START(IF_LEZ)  {
-    if (shadow_frame.GetVReg(inst->VRegA_21t(inst_data)) <= 0) {
-      int16_t offset = inst->VRegB_21t();
-      BRANCH_INSTRUMENTATION(offset);
-      if (IsBackwardBranch(offset)) {
-        HOTNESS_UPDATE();
-        if (UNLIKELY(self->TestAllFlags())) {
-          self->CheckSuspend();
-          UPDATE_HANDLER_TABLE();
-        }
-      }
-      ADVANCE(offset);
-    } else {
-      BRANCH_INSTRUMENTATION(2);
-      ADVANCE(2);
-    }
-  }
-  HANDLE_INSTRUCTION_END();
-
-  HANDLE_INSTRUCTION_START(AGET_BOOLEAN) {
-    Object* a = shadow_frame.GetVRegReference(inst->VRegB_23x());
-    if (UNLIKELY(a == nullptr)) {
-      ThrowNullPointerExceptionFromInterpreter();
-      HANDLE_PENDING_EXCEPTION();
-    } else {
-      int32_t index = shadow_frame.GetVReg(inst->VRegC_23x());
-      BooleanArray* array = a->AsBooleanArray();
-      if (LIKELY(array->CheckIsValidIndex(index))) {
-        shadow_frame.SetVReg(inst->VRegA_23x(inst_data), array->GetWithoutChecks(index));
-        ADVANCE(2);
-      } else {
-        HANDLE_PENDING_EXCEPTION();
-      }
-    }
-  }
-  HANDLE_INSTRUCTION_END();
-
-  HANDLE_INSTRUCTION_START(AGET_BYTE) {
-    Object* a = shadow_frame.GetVRegReference(inst->VRegB_23x());
-    if (UNLIKELY(a == nullptr)) {
-      ThrowNullPointerExceptionFromInterpreter();
-      HANDLE_PENDING_EXCEPTION();
-    } else {
-      int32_t index = shadow_frame.GetVReg(inst->VRegC_23x());
-      ByteArray* array = a->AsByteArray();
-      if (LIKELY(array->CheckIsValidIndex(index))) {
-        shadow_frame.SetVReg(inst->VRegA_23x(inst_data), array->GetWithoutChecks(index));
-        ADVANCE(2);
-      } else {
-        HANDLE_PENDING_EXCEPTION();
-      }
-    }
-  }
-  HANDLE_INSTRUCTION_END();
-
-  HANDLE_INSTRUCTION_START(AGET_CHAR) {
-    Object* a = shadow_frame.GetVRegReference(inst->VRegB_23x());
-    if (UNLIKELY(a == nullptr)) {
-      ThrowNullPointerExceptionFromInterpreter();
-      HANDLE_PENDING_EXCEPTION();
-    } else {
-      int32_t index = shadow_frame.GetVReg(inst->VRegC_23x());
-      CharArray* array = a->AsCharArray();
-      if (LIKELY(array->CheckIsValidIndex(index))) {
-        shadow_frame.SetVReg(inst->VRegA_23x(inst_data), array->GetWithoutChecks(index));
-        ADVANCE(2);
-      } else {
-        HANDLE_PENDING_EXCEPTION();
-      }
-    }
-  }
-  HANDLE_INSTRUCTION_END();
-
-  HANDLE_INSTRUCTION_START(AGET_SHORT) {
-    Object* a = shadow_frame.GetVRegReference(inst->VRegB_23x());
-    if (UNLIKELY(a == nullptr)) {
-      ThrowNullPointerExceptionFromInterpreter();
-      HANDLE_PENDING_EXCEPTION();
-    } else {
-      int32_t index = shadow_frame.GetVReg(inst->VRegC_23x());
-      ShortArray* array = a->AsShortArray();
-      if (LIKELY(array->CheckIsValidIndex(index))) {
-        shadow_frame.SetVReg(inst->VRegA_23x(inst_data), array->GetWithoutChecks(index));
-        ADVANCE(2);
-      } else {
-        HANDLE_PENDING_EXCEPTION();
-      }
-    }
-  }
-  HANDLE_INSTRUCTION_END();
-
-  HANDLE_INSTRUCTION_START(AGET) {
-    Object* a = shadow_frame.GetVRegReference(inst->VRegB_23x());
-    if (UNLIKELY(a == nullptr)) {
-      ThrowNullPointerExceptionFromInterpreter();
-      HANDLE_PENDING_EXCEPTION();
-    } else {
-      int32_t index = shadow_frame.GetVReg(inst->VRegC_23x());
-      DCHECK(a->IsIntArray() || a->IsFloatArray()) << PrettyTypeOf(a);
-      auto* array = down_cast<IntArray*>(a);
-      if (LIKELY(array->CheckIsValidIndex(index))) {
-        shadow_frame.SetVReg(inst->VRegA_23x(inst_data), array->GetWithoutChecks(index));
-        ADVANCE(2);
-      } else {
-        HANDLE_PENDING_EXCEPTION();
-      }
-    }
-  }
-  HANDLE_INSTRUCTION_END();
-
-  HANDLE_INSTRUCTION_START(AGET_WIDE)  {
-    Object* a = shadow_frame.GetVRegReference(inst->VRegB_23x());
-    if (UNLIKELY(a == nullptr)) {
-      ThrowNullPointerExceptionFromInterpreter();
-      HANDLE_PENDING_EXCEPTION();
-    } else {
-      int32_t index = shadow_frame.GetVReg(inst->VRegC_23x());
-      DCHECK(a->IsLongArray() || a->IsDoubleArray()) << PrettyTypeOf(a);
-      auto* array = down_cast<LongArray*>(a);
-      if (LIKELY(array->CheckIsValidIndex(index))) {
-        shadow_frame.SetVRegLong(inst->VRegA_23x(inst_data), array->GetWithoutChecks(index));
-        ADVANCE(2);
-      } else {
-        HANDLE_PENDING_EXCEPTION();
-      }
-    }
-  }
-  HANDLE_INSTRUCTION_END();
-
-  HANDLE_INSTRUCTION_START(AGET_OBJECT) {
-    Object* a = shadow_frame.GetVRegReference(inst->VRegB_23x());
-    if (UNLIKELY(a == nullptr)) {
-      ThrowNullPointerExceptionFromInterpreter();
-      HANDLE_PENDING_EXCEPTION();
-    } else {
-      int32_t index = shadow_frame.GetVReg(inst->VRegC_23x());
-      ObjectArray<Object>* array = a->AsObjectArray<Object>();
-      if (LIKELY(array->CheckIsValidIndex(index))) {
-        shadow_frame.SetVRegReference(inst->VRegA_23x(inst_data), array->GetWithoutChecks(index));
-        ADVANCE(2);
-      } else {
-        HANDLE_PENDING_EXCEPTION();
-      }
-    }
-  }
-  HANDLE_INSTRUCTION_END();
-
-  HANDLE_INSTRUCTION_START(APUT_BOOLEAN) {
-    Object* a = shadow_frame.GetVRegReference(inst->VRegB_23x());
-    if (UNLIKELY(a == nullptr)) {
-      ThrowNullPointerExceptionFromInterpreter();
-      HANDLE_PENDING_EXCEPTION();
-    } else {
-      uint8_t val = shadow_frame.GetVReg(inst->VRegA_23x(inst_data));
-      int32_t index = shadow_frame.GetVReg(inst->VRegC_23x());
-      BooleanArray* array = a->AsBooleanArray();
-      if (LIKELY(array->CheckIsValidIndex(index))) {
-        array->SetWithoutChecks<transaction_active>(index, val);
-        ADVANCE(2);
-      } else {
-        HANDLE_PENDING_EXCEPTION();
-      }
-    }
-  }
-  HANDLE_INSTRUCTION_END();
-
-  HANDLE_INSTRUCTION_START(APUT_BYTE) {
-    Object* a = shadow_frame.GetVRegReference(inst->VRegB_23x());
-    if (UNLIKELY(a == nullptr)) {
-      ThrowNullPointerExceptionFromInterpreter();
-      HANDLE_PENDING_EXCEPTION();
-    } else {
-      int8_t val = shadow_frame.GetVReg(inst->VRegA_23x(inst_data));
-      int32_t index = shadow_frame.GetVReg(inst->VRegC_23x());
-      ByteArray* array = a->AsByteArray();
-      if (LIKELY(array->CheckIsValidIndex(index))) {
-        array->SetWithoutChecks<transaction_active>(index, val);
-        ADVANCE(2);
-      } else {
-        HANDLE_PENDING_EXCEPTION();
-      }
-    }
-  }
-  HANDLE_INSTRUCTION_END();
-
-  HANDLE_INSTRUCTION_START(APUT_CHAR) {
-    Object* a = shadow_frame.GetVRegReference(inst->VRegB_23x());
-    if (UNLIKELY(a == nullptr)) {
-      ThrowNullPointerExceptionFromInterpreter();
-      HANDLE_PENDING_EXCEPTION();
-    } else {
-      uint16_t val = shadow_frame.GetVReg(inst->VRegA_23x(inst_data));
-      int32_t index = shadow_frame.GetVReg(inst->VRegC_23x());
-      CharArray* array = a->AsCharArray();
-      if (LIKELY(array->CheckIsValidIndex(index))) {
-        array->SetWithoutChecks<transaction_active>(index, val);
-        ADVANCE(2);
-      } else {
-        HANDLE_PENDING_EXCEPTION();
-      }
-    }
-  }
-  HANDLE_INSTRUCTION_END();
-
-  HANDLE_INSTRUCTION_START(APUT_SHORT) {
-    Object* a = shadow_frame.GetVRegReference(inst->VRegB_23x());
-    if (UNLIKELY(a == nullptr)) {
-      ThrowNullPointerExceptionFromInterpreter();
-      HANDLE_PENDING_EXCEPTION();
-    } else {
-      int16_t val = shadow_frame.GetVReg(inst->VRegA_23x(inst_data));
-      int32_t index = shadow_frame.GetVReg(inst->VRegC_23x());
-      ShortArray* array = a->AsShortArray();
-      if (LIKELY(array->CheckIsValidIndex(index))) {
-        array->SetWithoutChecks<transaction_active>(index, val);
-        ADVANCE(2);
-      } else {
-        HANDLE_PENDING_EXCEPTION();
-      }
-    }
-  }
-  HANDLE_INSTRUCTION_END();
-
-  HANDLE_INSTRUCTION_START(APUT) {
-    Object* a = shadow_frame.GetVRegReference(inst->VRegB_23x());
-    if (UNLIKELY(a == nullptr)) {
-      ThrowNullPointerExceptionFromInterpreter();
-      HANDLE_PENDING_EXCEPTION();
-    } else {
-      int32_t val = shadow_frame.GetVReg(inst->VRegA_23x(inst_data));
-      int32_t index = shadow_frame.GetVReg(inst->VRegC_23x());
-      DCHECK(a->IsIntArray() || a->IsFloatArray()) << PrettyTypeOf(a);
-      auto* array = down_cast<IntArray*>(a);
-      if (LIKELY(array->CheckIsValidIndex(index))) {
-        array->SetWithoutChecks<transaction_active>(index, val);
-        ADVANCE(2);
-      } else {
-        HANDLE_PENDING_EXCEPTION();
-      }
-    }
-  }
-  HANDLE_INSTRUCTION_END();
-
-  HANDLE_INSTRUCTION_START(APUT_WIDE) {
-    Object* a = shadow_frame.GetVRegReference(inst->VRegB_23x());
-    if (UNLIKELY(a == nullptr)) {
-      ThrowNullPointerExceptionFromInterpreter();
-      HANDLE_PENDING_EXCEPTION();
-    } else {
-      int64_t val = shadow_frame.GetVRegLong(inst->VRegA_23x(inst_data));
-      int32_t index = shadow_frame.GetVReg(inst->VRegC_23x());
-      DCHECK(a->IsLongArray() || a->IsDoubleArray()) << PrettyTypeOf(a);
-      auto* array = down_cast<LongArray*>(a);
-      if (LIKELY(array->CheckIsValidIndex(index))) {
-        array->SetWithoutChecks<transaction_active>(index, val);
-        ADVANCE(2);
-      } else {
-        HANDLE_PENDING_EXCEPTION();
-      }
-    }
-  }
-  HANDLE_INSTRUCTION_END();
-
-  HANDLE_INSTRUCTION_START(APUT_OBJECT) {
-    Object* a = shadow_frame.GetVRegReference(inst->VRegB_23x());
-    if (UNLIKELY(a == nullptr)) {
-      ThrowNullPointerExceptionFromInterpreter();
-      HANDLE_PENDING_EXCEPTION();
-    } else {
-      int32_t index = shadow_frame.GetVReg(inst->VRegC_23x());
-      Object* val = shadow_frame.GetVRegReference(inst->VRegA_23x(inst_data));
-      ObjectArray<Object>* array = a->AsObjectArray<Object>();
-      if (LIKELY(array->CheckIsValidIndex(index) && array->CheckAssignable(val))) {
-        array->SetWithoutChecks<transaction_active>(index, val);
-        ADVANCE(2);
-      } else {
-        HANDLE_PENDING_EXCEPTION();
-      }
-    }
-  }
-  HANDLE_INSTRUCTION_END();
-
-  HANDLE_INSTRUCTION_START(IGET_BOOLEAN) {
-    bool success = DoFieldGet<InstancePrimitiveRead, Primitive::kPrimBoolean, do_access_check>(
-        self, shadow_frame, inst, inst_data);
-    POSSIBLY_HANDLE_PENDING_EXCEPTION(!success, 2);
-  }
-  HANDLE_INSTRUCTION_END();
-
-  HANDLE_INSTRUCTION_START(IGET_BYTE) {
-    bool success = DoFieldGet<InstancePrimitiveRead, Primitive::kPrimByte, do_access_check>(
-        self, shadow_frame, inst, inst_data);
-    POSSIBLY_HANDLE_PENDING_EXCEPTION(!success, 2);
-  }
-  HANDLE_INSTRUCTION_END();
-
-  HANDLE_INSTRUCTION_START(IGET_CHAR) {
-    bool success = DoFieldGet<InstancePrimitiveRead, Primitive::kPrimChar, do_access_check>(
-        self, shadow_frame, inst, inst_data);
-    POSSIBLY_HANDLE_PENDING_EXCEPTION(!success, 2);
-  }
-  HANDLE_INSTRUCTION_END();
-
-  HANDLE_INSTRUCTION_START(IGET_SHORT) {
-    bool success = DoFieldGet<InstancePrimitiveRead, Primitive::kPrimShort, do_access_check>(
-        self, shadow_frame, inst, inst_data);
-    POSSIBLY_HANDLE_PENDING_EXCEPTION(!success, 2);
-  }
-  HANDLE_INSTRUCTION_END();
-
-  HANDLE_INSTRUCTION_START(IGET) {
-    bool success = DoFieldGet<InstancePrimitiveRead, Primitive::kPrimInt, do_access_check>(
-        self, shadow_frame, inst, inst_data);
-    POSSIBLY_HANDLE_PENDING_EXCEPTION(!success, 2);
-  }
-  HANDLE_INSTRUCTION_END();
-
-  HANDLE_INSTRUCTION_START(IGET_WIDE) {
-    bool success = DoFieldGet<InstancePrimitiveRead, Primitive::kPrimLong, do_access_check>(
-        self, shadow_frame, inst, inst_data);
-    POSSIBLY_HANDLE_PENDING_EXCEPTION(!success, 2);
-  }
-  HANDLE_INSTRUCTION_END();
-
-  HANDLE_INSTRUCTION_START(IGET_OBJECT) {
-    bool success = DoFieldGet<InstanceObjectRead, Primitive::kPrimNot, do_access_check>(
-        self, shadow_frame, inst, inst_data);
-    POSSIBLY_HANDLE_PENDING_EXCEPTION(!success, 2);
-  }
-  HANDLE_INSTRUCTION_END();
-
-  HANDLE_INSTRUCTION_START(IGET_QUICK) {
-    bool success = DoIGetQuick<Primitive::kPrimInt>(shadow_frame, inst, inst_data);
-    POSSIBLY_HANDLE_PENDING_EXCEPTION(!success, 2);
-  }
-  HANDLE_INSTRUCTION_END();
-
-  HANDLE_INSTRUCTION_START(IGET_BOOLEAN_QUICK) {
-    bool success = DoIGetQuick<Primitive::kPrimBoolean>(shadow_frame, inst, inst_data);
-    POSSIBLY_HANDLE_PENDING_EXCEPTION(!success, 2);
-  }
-  HANDLE_INSTRUCTION_END();
-
-  HANDLE_INSTRUCTION_START(IGET_BYTE_QUICK) {
-    bool success = DoIGetQuick<Primitive::kPrimByte>(shadow_frame, inst, inst_data);
-    POSSIBLY_HANDLE_PENDING_EXCEPTION(!success, 2);
-  }
-  HANDLE_INSTRUCTION_END();
-
-  HANDLE_INSTRUCTION_START(IGET_CHAR_QUICK) {
-    bool success = DoIGetQuick<Primitive::kPrimChar>(shadow_frame, inst, inst_data);
-    POSSIBLY_HANDLE_PENDING_EXCEPTION(!success, 2);
-  }
-  HANDLE_INSTRUCTION_END();
-
-  HANDLE_INSTRUCTION_START(IGET_SHORT_QUICK) {
-    bool success = DoIGetQuick<Primitive::kPrimShort>(shadow_frame, inst, inst_data);
-    POSSIBLY_HANDLE_PENDING_EXCEPTION(!success, 2);
-  }
-  HANDLE_INSTRUCTION_END();
-
-  HANDLE_INSTRUCTION_START(IGET_WIDE_QUICK) {
-    bool success = DoIGetQuick<Primitive::kPrimLong>(shadow_frame, inst, inst_data);
-    POSSIBLY_HANDLE_PENDING_EXCEPTION(!success, 2);
-  }
-  HANDLE_INSTRUCTION_END();
-
-  HANDLE_INSTRUCTION_START(IGET_OBJECT_QUICK) {
-    bool success = DoIGetQuick<Primitive::kPrimNot>(shadow_frame, inst, inst_data);
-    POSSIBLY_HANDLE_PENDING_EXCEPTION(!success, 2);
-  }
-  HANDLE_INSTRUCTION_END();
-
-  HANDLE_INSTRUCTION_START(SGET_BOOLEAN) {
-    bool success = DoFieldGet<StaticPrimitiveRead, Primitive::kPrimBoolean, do_access_check>(
-        self, shadow_frame, inst, inst_data);
-    POSSIBLY_HANDLE_PENDING_EXCEPTION(!success, 2);
-  }
-  HANDLE_INSTRUCTION_END();
-
-  HANDLE_INSTRUCTION_START(SGET_BYTE) {
-    bool success = DoFieldGet<StaticPrimitiveRead, Primitive::kPrimByte, do_access_check>(
-        self, shadow_frame, inst, inst_data);
-    POSSIBLY_HANDLE_PENDING_EXCEPTION(!success, 2);
-  }
-  HANDLE_INSTRUCTION_END();
-
-  HANDLE_INSTRUCTION_START(SGET_CHAR) {
-    bool success = DoFieldGet<StaticPrimitiveRead, Primitive::kPrimChar, do_access_check>(
-        self, shadow_frame, inst, inst_data);
-    POSSIBLY_HANDLE_PENDING_EXCEPTION(!success, 2);
-  }
-  HANDLE_INSTRUCTION_END();
-
-  HANDLE_INSTRUCTION_START(SGET_SHORT) {
-    bool success = DoFieldGet<StaticPrimitiveRead, Primitive::kPrimShort, do_access_check>(
-        self, shadow_frame, inst, inst_data);
-    POSSIBLY_HANDLE_PENDING_EXCEPTION(!success, 2);
-  }
-  HANDLE_INSTRUCTION_END();
-
-  HANDLE_INSTRUCTION_START(SGET) {
-    bool success = DoFieldGet<StaticPrimitiveRead, Primitive::kPrimInt, do_access_check>(
-        self, shadow_frame, inst, inst_data);
-    POSSIBLY_HANDLE_PENDING_EXCEPTION(!success, 2);
-  }
-  HANDLE_INSTRUCTION_END();
-
-  HANDLE_INSTRUCTION_START(SGET_WIDE) {
-    bool success = DoFieldGet<StaticPrimitiveRead, Primitive::kPrimLong, do_access_check>(
-        self, shadow_frame, inst, inst_data);
-    POSSIBLY_HANDLE_PENDING_EXCEPTION(!success, 2);
-  }
-  HANDLE_INSTRUCTION_END();
-
-  HANDLE_INSTRUCTION_START(SGET_OBJECT) {
-    bool success = DoFieldGet<StaticObjectRead, Primitive::kPrimNot, do_access_check>(
-        self, shadow_frame, inst, inst_data);
-    POSSIBLY_HANDLE_PENDING_EXCEPTION(!success, 2);
-  }
-  HANDLE_INSTRUCTION_END();
-
-  HANDLE_INSTRUCTION_START(IPUT_BOOLEAN) {
-    bool success = DoFieldPut<InstancePrimitiveWrite, Primitive::kPrimBoolean, do_access_check,
-        transaction_active>(self, shadow_frame, inst, inst_data);
-    POSSIBLY_HANDLE_PENDING_EXCEPTION(!success, 2);
-  }
-  HANDLE_INSTRUCTION_END();
-
-  HANDLE_INSTRUCTION_START(IPUT_BYTE) {
-    bool success = DoFieldPut<InstancePrimitiveWrite, Primitive::kPrimByte, do_access_check,
-        transaction_active>(self, shadow_frame, inst, inst_data);
-    POSSIBLY_HANDLE_PENDING_EXCEPTION(!success, 2);
-  }
-  HANDLE_INSTRUCTION_END();
-
-  HANDLE_INSTRUCTION_START(IPUT_CHAR) {
-    bool success = DoFieldPut<InstancePrimitiveWrite, Primitive::kPrimChar, do_access_check,
-        transaction_active>(self, shadow_frame, inst, inst_data);
-    POSSIBLY_HANDLE_PENDING_EXCEPTION(!success, 2);
-  }
-  HANDLE_INSTRUCTION_END();
-
-  HANDLE_INSTRUCTION_START(IPUT_SHORT) {
-    bool success = DoFieldPut<InstancePrimitiveWrite, Primitive::kPrimShort, do_access_check,
-        transaction_active>(self, shadow_frame, inst, inst_data);
-    POSSIBLY_HANDLE_PENDING_EXCEPTION(!success, 2);
-  }
-  HANDLE_INSTRUCTION_END();
-
-  HANDLE_INSTRUCTION_START(IPUT) {
-    bool success = DoFieldPut<InstancePrimitiveWrite, Primitive::kPrimInt, do_access_check,
-        transaction_active>(self, shadow_frame, inst, inst_data);
-    POSSIBLY_HANDLE_PENDING_EXCEPTION(!success, 2);
-  }
-  HANDLE_INSTRUCTION_END();
-
-  HANDLE_INSTRUCTION_START(IPUT_WIDE) {
-    bool success = DoFieldPut<InstancePrimitiveWrite, Primitive::kPrimLong, do_access_check,
-        transaction_active>(self, shadow_frame, inst, inst_data);
-    POSSIBLY_HANDLE_PENDING_EXCEPTION(!success, 2);
-  }
-  HANDLE_INSTRUCTION_END();
-
-  HANDLE_INSTRUCTION_START(IPUT_OBJECT) {
-    bool success = DoFieldPut<InstanceObjectWrite, Primitive::kPrimNot, do_access_check,
-        transaction_active>(self, shadow_frame, inst, inst_data);
-    POSSIBLY_HANDLE_PENDING_EXCEPTION(!success, 2);
-  }
-  HANDLE_INSTRUCTION_END();
-
-  HANDLE_INSTRUCTION_START(IPUT_QUICK) {
-    bool success = DoIPutQuick<Primitive::kPrimInt, transaction_active>(
-        shadow_frame, inst, inst_data);
-    POSSIBLY_HANDLE_PENDING_EXCEPTION(!success, 2);
-  }
-  HANDLE_INSTRUCTION_END();
-
-  HANDLE_INSTRUCTION_START(IPUT_BOOLEAN_QUICK) {
-    bool success = DoIPutQuick<Primitive::kPrimBoolean, transaction_active>(
-        shadow_frame, inst, inst_data);
-    POSSIBLY_HANDLE_PENDING_EXCEPTION(!success, 2);
-  }
-  HANDLE_INSTRUCTION_END();
-
-  HANDLE_INSTRUCTION_START(IPUT_BYTE_QUICK) {
-    bool success = DoIPutQuick<Primitive::kPrimByte, transaction_active>(
-        shadow_frame, inst, inst_data);
-    POSSIBLY_HANDLE_PENDING_EXCEPTION(!success, 2);
-  }
-  HANDLE_INSTRUCTION_END();
-
-  HANDLE_INSTRUCTION_START(IPUT_CHAR_QUICK) {
-    bool success = DoIPutQuick<Primitive::kPrimChar, transaction_active>(
-        shadow_frame, inst, inst_data);
-    POSSIBLY_HANDLE_PENDING_EXCEPTION(!success, 2);
-  }
-  HANDLE_INSTRUCTION_END();
-
-  HANDLE_INSTRUCTION_START(IPUT_SHORT_QUICK) {
-    bool success = DoIPutQuick<Primitive::kPrimShort, transaction_active>(
-        shadow_frame, inst, inst_data);
-    POSSIBLY_HANDLE_PENDING_EXCEPTION(!success, 2);
-  }
-  HANDLE_INSTRUCTION_END();
-
-  HANDLE_INSTRUCTION_START(IPUT_WIDE_QUICK) {
-    bool success = DoIPutQuick<Primitive::kPrimLong, transaction_active>(
-        shadow_frame, inst, inst_data);
-    POSSIBLY_HANDLE_PENDING_EXCEPTION(!success, 2);
-  }
-  HANDLE_INSTRUCTION_END();
-
-  HANDLE_INSTRUCTION_START(IPUT_OBJECT_QUICK) {
-    bool success = DoIPutQuick<Primitive::kPrimNot, transaction_active>(
-        shadow_frame, inst, inst_data);
-    POSSIBLY_HANDLE_PENDING_EXCEPTION(!success, 2);
-  }
-  HANDLE_INSTRUCTION_END();
-
-  HANDLE_INSTRUCTION_START(SPUT_BOOLEAN) {
-    bool success = DoFieldPut<StaticPrimitiveWrite, Primitive::kPrimBoolean, do_access_check,
-        transaction_active>(self, shadow_frame, inst, inst_data);
-    POSSIBLY_HANDLE_PENDING_EXCEPTION(!success, 2);
-  }
-  HANDLE_INSTRUCTION_END();
-
-  HANDLE_INSTRUCTION_START(SPUT_BYTE) {
-    bool success = DoFieldPut<StaticPrimitiveWrite, Primitive::kPrimByte, do_access_check,
-        transaction_active>(self, shadow_frame, inst, inst_data);
-    POSSIBLY_HANDLE_PENDING_EXCEPTION(!success, 2);
-  }
-  HANDLE_INSTRUCTION_END();
-
-  HANDLE_INSTRUCTION_START(SPUT_CHAR) {
-    bool success = DoFieldPut<StaticPrimitiveWrite, Primitive::kPrimChar, do_access_check,
-        transaction_active>(self, shadow_frame, inst, inst_data);
-    POSSIBLY_HANDLE_PENDING_EXCEPTION(!success, 2);
-  }
-  HANDLE_INSTRUCTION_END();
-
-  HANDLE_INSTRUCTION_START(SPUT_SHORT) {
-    bool success = DoFieldPut<StaticPrimitiveWrite, Primitive::kPrimShort, do_access_check,
-        transaction_active>(self, shadow_frame, inst, inst_data);
-    POSSIBLY_HANDLE_PENDING_EXCEPTION(!success, 2);
-  }
-  HANDLE_INSTRUCTION_END();
-
-  HANDLE_INSTRUCTION_START(SPUT) {
-    bool success = DoFieldPut<StaticPrimitiveWrite, Primitive::kPrimInt, do_access_check,
-        transaction_active>(self, shadow_frame, inst, inst_data);
-    POSSIBLY_HANDLE_PENDING_EXCEPTION(!success, 2);
-  }
-  HANDLE_INSTRUCTION_END();
-
-  HANDLE_INSTRUCTION_START(SPUT_WIDE) {
-    bool success = DoFieldPut<StaticPrimitiveWrite, Primitive::kPrimLong, do_access_check,
-        transaction_active>(self, shadow_frame, inst, inst_data);
-    POSSIBLY_HANDLE_PENDING_EXCEPTION(!success, 2);
-  }
-  HANDLE_INSTRUCTION_END();
-
-  HANDLE_INSTRUCTION_START(SPUT_OBJECT) {
-    bool success = DoFieldPut<StaticObjectWrite, Primitive::kPrimNot, do_access_check,
-        transaction_active>(self, shadow_frame, inst, inst_data);
-    POSSIBLY_HANDLE_PENDING_EXCEPTION(!success, 2);
-  }
-  HANDLE_INSTRUCTION_END();
-
-  HANDLE_INSTRUCTION_START(INVOKE_VIRTUAL) {
-    bool success = DoInvoke<kVirtual, false, do_access_check>(
-        self, shadow_frame, inst, inst_data, &result_register);
-    UPDATE_HANDLER_TABLE();
-    POSSIBLY_HANDLE_PENDING_EXCEPTION(!success, 3);
-  }
-  HANDLE_INSTRUCTION_END();
-
-  HANDLE_INSTRUCTION_START(INVOKE_VIRTUAL_RANGE) {
-    bool success = DoInvoke<kVirtual, true, do_access_check>(
-        self, shadow_frame, inst, inst_data, &result_register);
-    UPDATE_HANDLER_TABLE();
-    POSSIBLY_HANDLE_PENDING_EXCEPTION(!success, 3);
-  }
-  HANDLE_INSTRUCTION_END();
-
-  HANDLE_INSTRUCTION_START(INVOKE_SUPER) {
-    bool success = DoInvoke<kSuper, false, do_access_check>(
-        self, shadow_frame, inst, inst_data, &result_register);
-    UPDATE_HANDLER_TABLE();
-    POSSIBLY_HANDLE_PENDING_EXCEPTION(!success, 3);
-  }
-  HANDLE_INSTRUCTION_END();
-
-  HANDLE_INSTRUCTION_START(INVOKE_SUPER_RANGE) {
-    bool success = DoInvoke<kSuper, true, do_access_check>(
-        self, shadow_frame, inst, inst_data, &result_register);
-    UPDATE_HANDLER_TABLE();
-    POSSIBLY_HANDLE_PENDING_EXCEPTION(!success, 3);
-  }
-  HANDLE_INSTRUCTION_END();
-
-  HANDLE_INSTRUCTION_START(INVOKE_DIRECT) {
-    bool success = DoInvoke<kDirect, false, do_access_check>(
-        self, shadow_frame, inst, inst_data, &result_register);
-    UPDATE_HANDLER_TABLE();
-    POSSIBLY_HANDLE_PENDING_EXCEPTION(!success, 3);
-  }
-  HANDLE_INSTRUCTION_END();
-
-  HANDLE_INSTRUCTION_START(INVOKE_DIRECT_RANGE) {
-    bool success = DoInvoke<kDirect, true, do_access_check>(
-        self, shadow_frame, inst, inst_data, &result_register);
-    UPDATE_HANDLER_TABLE();
-    POSSIBLY_HANDLE_PENDING_EXCEPTION(!success, 3);
-  }
-  HANDLE_INSTRUCTION_END();
-
-  HANDLE_INSTRUCTION_START(INVOKE_INTERFACE) {
-    bool success = DoInvoke<kInterface, false, do_access_check>(
-        self, shadow_frame, inst, inst_data, &result_register);
-    UPDATE_HANDLER_TABLE();
-    POSSIBLY_HANDLE_PENDING_EXCEPTION(!success, 3);
-  }
-  HANDLE_INSTRUCTION_END();
-
-  HANDLE_INSTRUCTION_START(INVOKE_INTERFACE_RANGE) {
-    bool success = DoInvoke<kInterface, true, do_access_check>(
-        self, shadow_frame, inst, inst_data, &result_register);
-    UPDATE_HANDLER_TABLE();
-    POSSIBLY_HANDLE_PENDING_EXCEPTION(!success, 3);
-  }
-  HANDLE_INSTRUCTION_END();
-
-  HANDLE_INSTRUCTION_START(INVOKE_STATIC) {
-    bool success = DoInvoke<kStatic, false, do_access_check>(
-        self, shadow_frame, inst, inst_data, &result_register);
-    UPDATE_HANDLER_TABLE();
-    POSSIBLY_HANDLE_PENDING_EXCEPTION(!success, 3);
-  }
-  HANDLE_INSTRUCTION_END();
-
-  HANDLE_INSTRUCTION_START(INVOKE_STATIC_RANGE) {
-    bool success = DoInvoke<kStatic, true, do_access_check>(
-        self, shadow_frame, inst, inst_data, &result_register);
-    UPDATE_HANDLER_TABLE();
-    POSSIBLY_HANDLE_PENDING_EXCEPTION(!success, 3);
-  }
-  HANDLE_INSTRUCTION_END();
-
-  HANDLE_INSTRUCTION_START(INVOKE_VIRTUAL_QUICK) {
-    bool success = DoInvokeVirtualQuick<false>(
-        self, shadow_frame, inst, inst_data, &result_register);
-    UPDATE_HANDLER_TABLE();
-    POSSIBLY_HANDLE_PENDING_EXCEPTION(!success, 3);
-  }
-  HANDLE_INSTRUCTION_END();
-
-  HANDLE_INSTRUCTION_START(INVOKE_VIRTUAL_RANGE_QUICK) {
-    bool success = DoInvokeVirtualQuick<true>(
-        self, shadow_frame, inst, inst_data, &result_register);
-    UPDATE_HANDLER_TABLE();
-    POSSIBLY_HANDLE_PENDING_EXCEPTION(!success, 3);
-  }
-  HANDLE_INSTRUCTION_END();
-
-  HANDLE_INSTRUCTION_START(NEG_INT)
-    shadow_frame.SetVReg(
-        inst->VRegA_12x(inst_data), -shadow_frame.GetVReg(inst->VRegB_12x(inst_data)));
-    ADVANCE(1);
-  HANDLE_INSTRUCTION_END();
-
-  HANDLE_INSTRUCTION_START(NOT_INT)
-    shadow_frame.SetVReg(
-        inst->VRegA_12x(inst_data), ~shadow_frame.GetVReg(inst->VRegB_12x(inst_data)));
-    ADVANCE(1);
-  HANDLE_INSTRUCTION_END();
-
-  HANDLE_INSTRUCTION_START(NEG_LONG)
-    shadow_frame.SetVRegLong(
-        inst->VRegA_12x(inst_data), -shadow_frame.GetVRegLong(inst->VRegB_12x(inst_data)));
-    ADVANCE(1);
-  HANDLE_INSTRUCTION_END();
-
-  HANDLE_INSTRUCTION_START(NOT_LONG)
-    shadow_frame.SetVRegLong(
-        inst->VRegA_12x(inst_data), ~shadow_frame.GetVRegLong(inst->VRegB_12x(inst_data)));
-    ADVANCE(1);
-  HANDLE_INSTRUCTION_END();
-
-  HANDLE_INSTRUCTION_START(NEG_FLOAT)
-    shadow_frame.SetVRegFloat(
-        inst->VRegA_12x(inst_data), -shadow_frame.GetVRegFloat(inst->VRegB_12x(inst_data)));
-    ADVANCE(1);
-  HANDLE_INSTRUCTION_END();
-
-  HANDLE_INSTRUCTION_START(NEG_DOUBLE)
-    shadow_frame.SetVRegDouble(
-        inst->VRegA_12x(inst_data), -shadow_frame.GetVRegDouble(inst->VRegB_12x(inst_data)));
-    ADVANCE(1);
-  HANDLE_INSTRUCTION_END();
-
-  HANDLE_INSTRUCTION_START(INT_TO_LONG)
-    shadow_frame.SetVRegLong(
-        inst->VRegA_12x(inst_data), shadow_frame.GetVReg(inst->VRegB_12x(inst_data)));
-    ADVANCE(1);
-  HANDLE_INSTRUCTION_END();
-
-  HANDLE_INSTRUCTION_START(INT_TO_FLOAT)
-    shadow_frame.SetVRegFloat(
-        inst->VRegA_12x(inst_data), shadow_frame.GetVReg(inst->VRegB_12x(inst_data)));
-    ADVANCE(1);
-  HANDLE_INSTRUCTION_END();
-
-  HANDLE_INSTRUCTION_START(INT_TO_DOUBLE)
-    shadow_frame.SetVRegDouble(
-        inst->VRegA_12x(inst_data), shadow_frame.GetVReg(inst->VRegB_12x(inst_data)));
-    ADVANCE(1);
-  HANDLE_INSTRUCTION_END();
-
-  HANDLE_INSTRUCTION_START(LONG_TO_INT)
-    shadow_frame.SetVReg(
-        inst->VRegA_12x(inst_data), shadow_frame.GetVRegLong(inst->VRegB_12x(inst_data)));
-    ADVANCE(1);
-  HANDLE_INSTRUCTION_END();
-
-  HANDLE_INSTRUCTION_START(LONG_TO_FLOAT)
-    shadow_frame.SetVRegFloat(
-        inst->VRegA_12x(inst_data), shadow_frame.GetVRegLong(inst->VRegB_12x(inst_data)));
-    ADVANCE(1);
-  HANDLE_INSTRUCTION_END();
-
-  HANDLE_INSTRUCTION_START(LONG_TO_DOUBLE)
-    shadow_frame.SetVRegDouble(
-        inst->VRegA_12x(inst_data), shadow_frame.GetVRegLong(inst->VRegB_12x(inst_data)));
-    ADVANCE(1);
-  HANDLE_INSTRUCTION_END();
-
-  HANDLE_INSTRUCTION_START(FLOAT_TO_INT) {
-    float val = shadow_frame.GetVRegFloat(inst->VRegB_12x(inst_data));
-    int32_t result = art_float_to_integral<int32_t, float>(val);
-    shadow_frame.SetVReg(inst->VRegA_12x(inst_data), result);
-    ADVANCE(1);
-  }
-  HANDLE_INSTRUCTION_END();
-
-  HANDLE_INSTRUCTION_START(FLOAT_TO_LONG) {
-    float val = shadow_frame.GetVRegFloat(inst->VRegB_12x(inst_data));
-    int64_t result = art_float_to_integral<int64_t, float>(val);
-    shadow_frame.SetVRegLong(inst->VRegA_12x(inst_data), result);
-    ADVANCE(1);
-  }
-  HANDLE_INSTRUCTION_END();
-
-  HANDLE_INSTRUCTION_START(FLOAT_TO_DOUBLE)
-    shadow_frame.SetVRegDouble(
-        inst->VRegA_12x(inst_data), shadow_frame.GetVRegFloat(inst->VRegB_12x(inst_data)));
-    ADVANCE(1);
-  HANDLE_INSTRUCTION_END();
-
-  HANDLE_INSTRUCTION_START(DOUBLE_TO_INT) {
-    double val = shadow_frame.GetVRegDouble(inst->VRegB_12x(inst_data));
-    int32_t result = art_float_to_integral<int32_t, double>(val);
-    shadow_frame.SetVReg(inst->VRegA_12x(inst_data), result);
-    ADVANCE(1);
-  }
-  HANDLE_INSTRUCTION_END();
-
-  HANDLE_INSTRUCTION_START(DOUBLE_TO_LONG) {
-    double val = shadow_frame.GetVRegDouble(inst->VRegB_12x(inst_data));
-    int64_t result = art_float_to_integral<int64_t, double>(val);
-    shadow_frame.SetVRegLong(inst->VRegA_12x(inst_data), result);
-    ADVANCE(1);
-  }
-  HANDLE_INSTRUCTION_END();
-
-  HANDLE_INSTRUCTION_START(DOUBLE_TO_FLOAT)
-    shadow_frame.SetVRegFloat(
-        inst->VRegA_12x(inst_data), shadow_frame.GetVRegDouble(inst->VRegB_12x(inst_data)));
-    ADVANCE(1);
-  HANDLE_INSTRUCTION_END();
-
-  HANDLE_INSTRUCTION_START(INT_TO_BYTE)
-    shadow_frame.SetVReg(inst->VRegA_12x(inst_data),
-                         static_cast<int8_t>(shadow_frame.GetVReg(inst->VRegB_12x(inst_data))));
-    ADVANCE(1);
-  HANDLE_INSTRUCTION_END();
-
-  HANDLE_INSTRUCTION_START(INT_TO_CHAR)
-    shadow_frame.SetVReg(inst->VRegA_12x(inst_data),
-                         static_cast<uint16_t>(shadow_frame.GetVReg(inst->VRegB_12x(inst_data))));
-    ADVANCE(1);
-  HANDLE_INSTRUCTION_END();
-
-  HANDLE_INSTRUCTION_START(INT_TO_SHORT)
-    shadow_frame.SetVReg(inst->VRegA_12x(inst_data),
-                         static_cast<int16_t>(shadow_frame.GetVReg(inst->VRegB_12x(inst_data))));
-    ADVANCE(1);
-  HANDLE_INSTRUCTION_END();
-
-  HANDLE_INSTRUCTION_START(ADD_INT)
-    shadow_frame.SetVReg(inst->VRegA_23x(inst_data),
-                         SafeAdd(shadow_frame.GetVReg(inst->VRegB_23x()),
-                                 shadow_frame.GetVReg(inst->VRegC_23x())));
-    ADVANCE(2);
-  HANDLE_INSTRUCTION_END();
-
-  HANDLE_INSTRUCTION_START(SUB_INT)
-    shadow_frame.SetVReg(inst->VRegA_23x(inst_data),
-                         SafeSub(shadow_frame.GetVReg(inst->VRegB_23x()),
-                                 shadow_frame.GetVReg(inst->VRegC_23x())));
-    ADVANCE(2);
-  HANDLE_INSTRUCTION_END();
-
-  HANDLE_INSTRUCTION_START(MUL_INT)
-    shadow_frame.SetVReg(inst->VRegA_23x(inst_data),
-                         SafeMul(shadow_frame.GetVReg(inst->VRegB_23x()),
-                                 shadow_frame.GetVReg(inst->VRegC_23x())));
-    ADVANCE(2);
-  HANDLE_INSTRUCTION_END();
-
-  HANDLE_INSTRUCTION_START(DIV_INT) {
-    bool success = DoIntDivide(shadow_frame, inst->VRegA_23x(inst_data),
-                               shadow_frame.GetVReg(inst->VRegB_23x()),
-                               shadow_frame.GetVReg(inst->VRegC_23x()));
-    POSSIBLY_HANDLE_PENDING_EXCEPTION(!success, 2);
-  }
-  HANDLE_INSTRUCTION_END();
-
-  HANDLE_INSTRUCTION_START(REM_INT) {
-    bool success = DoIntRemainder(shadow_frame, inst->VRegA_23x(inst_data),
-                                  shadow_frame.GetVReg(inst->VRegB_23x()),
-                                  shadow_frame.GetVReg(inst->VRegC_23x()));
-    POSSIBLY_HANDLE_PENDING_EXCEPTION(!success, 2);
-  }
-  HANDLE_INSTRUCTION_END();
-
-  HANDLE_INSTRUCTION_START(SHL_INT)
-    shadow_frame.SetVReg(inst->VRegA_23x(inst_data),
-                         shadow_frame.GetVReg(inst->VRegB_23x()) <<
-                         (shadow_frame.GetVReg(inst->VRegC_23x()) & 0x1f));
-    ADVANCE(2);
-  HANDLE_INSTRUCTION_END();
-
-  HANDLE_INSTRUCTION_START(SHR_INT)
-    shadow_frame.SetVReg(inst->VRegA_23x(inst_data),
-                         shadow_frame.GetVReg(inst->VRegB_23x()) >>
-                         (shadow_frame.GetVReg(inst->VRegC_23x()) & 0x1f));
-    ADVANCE(2);
-  HANDLE_INSTRUCTION_END();
-
-  HANDLE_INSTRUCTION_START(USHR_INT)
-    shadow_frame.SetVReg(inst->VRegA_23x(inst_data),
-                         static_cast<uint32_t>(shadow_frame.GetVReg(inst->VRegB_23x())) >>
-                         (shadow_frame.GetVReg(inst->VRegC_23x()) & 0x1f));
-    ADVANCE(2);
-  HANDLE_INSTRUCTION_END();
-
-  HANDLE_INSTRUCTION_START(AND_INT)
-    shadow_frame.SetVReg(inst->VRegA_23x(inst_data),
-                         shadow_frame.GetVReg(inst->VRegB_23x()) &
-                         shadow_frame.GetVReg(inst->VRegC_23x()));
-    ADVANCE(2);
-  HANDLE_INSTRUCTION_END();
-
-  HANDLE_INSTRUCTION_START(OR_INT)
-    shadow_frame.SetVReg(inst->VRegA_23x(inst_data),
-                         shadow_frame.GetVReg(inst->VRegB_23x()) |
-                         shadow_frame.GetVReg(inst->VRegC_23x()));
-    ADVANCE(2);
-  HANDLE_INSTRUCTION_END();
-
-  HANDLE_INSTRUCTION_START(XOR_INT)
-    shadow_frame.SetVReg(inst->VRegA_23x(inst_data),
-                         shadow_frame.GetVReg(inst->VRegB_23x()) ^
-                         shadow_frame.GetVReg(inst->VRegC_23x()));
-    ADVANCE(2);
-  HANDLE_INSTRUCTION_END();
-
-  HANDLE_INSTRUCTION_START(ADD_LONG)
-    shadow_frame.SetVRegLong(inst->VRegA_23x(inst_data),
-                             SafeAdd(shadow_frame.GetVRegLong(inst->VRegB_23x()),
-                                     shadow_frame.GetVRegLong(inst->VRegC_23x())));
-    ADVANCE(2);
-  HANDLE_INSTRUCTION_END();
-
-  HANDLE_INSTRUCTION_START(SUB_LONG)
-    shadow_frame.SetVRegLong(inst->VRegA_23x(inst_data),
-                             SafeSub(shadow_frame.GetVRegLong(inst->VRegB_23x()),
-                                     shadow_frame.GetVRegLong(inst->VRegC_23x())));
-    ADVANCE(2);
-  HANDLE_INSTRUCTION_END();
-
-  HANDLE_INSTRUCTION_START(MUL_LONG)
-    shadow_frame.SetVRegLong(inst->VRegA_23x(inst_data),
-                             SafeMul(shadow_frame.GetVRegLong(inst->VRegB_23x()),
-                                     shadow_frame.GetVRegLong(inst->VRegC_23x())));
-    ADVANCE(2);
-  HANDLE_INSTRUCTION_END();
-
-  HANDLE_INSTRUCTION_START(DIV_LONG) {
-    bool success = DoLongDivide(shadow_frame, inst->VRegA_23x(inst_data),
-                                shadow_frame.GetVRegLong(inst->VRegB_23x()),
-                                shadow_frame.GetVRegLong(inst->VRegC_23x()));
-    POSSIBLY_HANDLE_PENDING_EXCEPTION(!success, 2);
-  }
-  HANDLE_INSTRUCTION_END();
-
-  HANDLE_INSTRUCTION_START(REM_LONG) {
-    bool success = DoLongRemainder(shadow_frame, inst->VRegA_23x(inst_data),
-                                   shadow_frame.GetVRegLong(inst->VRegB_23x()),
-                                   shadow_frame.GetVRegLong(inst->VRegC_23x()));
-    POSSIBLY_HANDLE_PENDING_EXCEPTION(!success, 2);
-  }
-  HANDLE_INSTRUCTION_END();
-
-  HANDLE_INSTRUCTION_START(AND_LONG)
-    shadow_frame.SetVRegLong(inst->VRegA_23x(inst_data),
-                             shadow_frame.GetVRegLong(inst->VRegB_23x()) &
-                             shadow_frame.GetVRegLong(inst->VRegC_23x()));
-    ADVANCE(2);
-  HANDLE_INSTRUCTION_END();
-
-  HANDLE_INSTRUCTION_START(OR_LONG)
-    shadow_frame.SetVRegLong(inst->VRegA_23x(inst_data),
-                             shadow_frame.GetVRegLong(inst->VRegB_23x()) |
-                             shadow_frame.GetVRegLong(inst->VRegC_23x()));
-    ADVANCE(2);
-  HANDLE_INSTRUCTION_END();
-
-  HANDLE_INSTRUCTION_START(XOR_LONG)
-    shadow_frame.SetVRegLong(inst->VRegA_23x(inst_data),
-                             shadow_frame.GetVRegLong(inst->VRegB_23x()) ^
-                             shadow_frame.GetVRegLong(inst->VRegC_23x()));
-    ADVANCE(2);
-  HANDLE_INSTRUCTION_END();
-
-  HANDLE_INSTRUCTION_START(SHL_LONG)
-    shadow_frame.SetVRegLong(inst->VRegA_23x(inst_data),
-                             shadow_frame.GetVRegLong(inst->VRegB_23x()) <<
-                             (shadow_frame.GetVReg(inst->VRegC_23x()) & 0x3f));
-    ADVANCE(2);
-  HANDLE_INSTRUCTION_END();
-
-  HANDLE_INSTRUCTION_START(SHR_LONG)
-    shadow_frame.SetVRegLong(inst->VRegA_23x(inst_data),
-                             shadow_frame.GetVRegLong(inst->VRegB_23x()) >>
-                             (shadow_frame.GetVReg(inst->VRegC_23x()) & 0x3f));
-    ADVANCE(2);
-  HANDLE_INSTRUCTION_END();
-
-  HANDLE_INSTRUCTION_START(USHR_LONG)
-    shadow_frame.SetVRegLong(inst->VRegA_23x(inst_data),
-                             static_cast<uint64_t>(shadow_frame.GetVRegLong(inst->VRegB_23x())) >>
-                             (shadow_frame.GetVReg(inst->VRegC_23x()) & 0x3f));
-    ADVANCE(2);
-  HANDLE_INSTRUCTION_END();
-
-  HANDLE_INSTRUCTION_START(ADD_FLOAT)
-    shadow_frame.SetVRegFloat(inst->VRegA_23x(inst_data),
-                              shadow_frame.GetVRegFloat(inst->VRegB_23x()) +
-                              shadow_frame.GetVRegFloat(inst->VRegC_23x()));
-    ADVANCE(2);
-  HANDLE_INSTRUCTION_END();
-
-  HANDLE_INSTRUCTION_START(SUB_FLOAT)
-    shadow_frame.SetVRegFloat(inst->VRegA_23x(inst_data),
-                              shadow_frame.GetVRegFloat(inst->VRegB_23x()) -
-                              shadow_frame.GetVRegFloat(inst->VRegC_23x()));
-    ADVANCE(2);
-  HANDLE_INSTRUCTION_END();
-
-  HANDLE_INSTRUCTION_START(MUL_FLOAT)
-    shadow_frame.SetVRegFloat(inst->VRegA_23x(inst_data),
-                              shadow_frame.GetVRegFloat(inst->VRegB_23x()) *
-                              shadow_frame.GetVRegFloat(inst->VRegC_23x()));
-    ADVANCE(2);
-  HANDLE_INSTRUCTION_END();
-
-  HANDLE_INSTRUCTION_START(DIV_FLOAT)
-    shadow_frame.SetVRegFloat(inst->VRegA_23x(inst_data),
-                              shadow_frame.GetVRegFloat(inst->VRegB_23x()) /
-                              shadow_frame.GetVRegFloat(inst->VRegC_23x()));
-    ADVANCE(2);
-  HANDLE_INSTRUCTION_END();
-
-  HANDLE_INSTRUCTION_START(REM_FLOAT)
-    shadow_frame.SetVRegFloat(inst->VRegA_23x(inst_data),
-                              fmodf(shadow_frame.GetVRegFloat(inst->VRegB_23x()),
-                                    shadow_frame.GetVRegFloat(inst->VRegC_23x())));
-    ADVANCE(2);
-  HANDLE_INSTRUCTION_END();
-
-  HANDLE_INSTRUCTION_START(ADD_DOUBLE)
-    shadow_frame.SetVRegDouble(inst->VRegA_23x(inst_data),
-                               shadow_frame.GetVRegDouble(inst->VRegB_23x()) +
-                               shadow_frame.GetVRegDouble(inst->VRegC_23x()));
-    ADVANCE(2);
-  HANDLE_INSTRUCTION_END();
-
-  HANDLE_INSTRUCTION_START(SUB_DOUBLE)
-    shadow_frame.SetVRegDouble(inst->VRegA_23x(inst_data),
-                               shadow_frame.GetVRegDouble(inst->VRegB_23x()) -
-                               shadow_frame.GetVRegDouble(inst->VRegC_23x()));
-    ADVANCE(2);
-  HANDLE_INSTRUCTION_END();
-
-  HANDLE_INSTRUCTION_START(MUL_DOUBLE)
-    shadow_frame.SetVRegDouble(inst->VRegA_23x(inst_data),
-                               shadow_frame.GetVRegDouble(inst->VRegB_23x()) *
-                               shadow_frame.GetVRegDouble(inst->VRegC_23x()));
-    ADVANCE(2);
-  HANDLE_INSTRUCTION_END();
-
-  HANDLE_INSTRUCTION_START(DIV_DOUBLE)
-    shadow_frame.SetVRegDouble(inst->VRegA_23x(inst_data),
-                               shadow_frame.GetVRegDouble(inst->VRegB_23x()) /
-                               shadow_frame.GetVRegDouble(inst->VRegC_23x()));
-    ADVANCE(2);
-  HANDLE_INSTRUCTION_END();
-
-  HANDLE_INSTRUCTION_START(REM_DOUBLE)
-    shadow_frame.SetVRegDouble(inst->VRegA_23x(inst_data),
-                               fmod(shadow_frame.GetVRegDouble(inst->VRegB_23x()),
-                                    shadow_frame.GetVRegDouble(inst->VRegC_23x())));
-    ADVANCE(2);
-  HANDLE_INSTRUCTION_END();
-
-  HANDLE_INSTRUCTION_START(ADD_INT_2ADDR) {
-    uint32_t vregA = inst->VRegA_12x(inst_data);
-    shadow_frame.SetVReg(vregA,
-                         SafeAdd(shadow_frame.GetVReg(vregA),
-                                 shadow_frame.GetVReg(inst->VRegB_12x(inst_data))));
-    ADVANCE(1);
-  }
-  HANDLE_INSTRUCTION_END();
-
-  HANDLE_INSTRUCTION_START(SUB_INT_2ADDR) {
-    uint32_t vregA = inst->VRegA_12x(inst_data);
-    shadow_frame.SetVReg(vregA,
-                         SafeSub(shadow_frame.GetVReg(vregA),
-                                 shadow_frame.GetVReg(inst->VRegB_12x(inst_data))));
-    ADVANCE(1);
-  }
-  HANDLE_INSTRUCTION_END();
-
-  HANDLE_INSTRUCTION_START(MUL_INT_2ADDR) {
-    uint32_t vregA = inst->VRegA_12x(inst_data);
-    shadow_frame.SetVReg(vregA,
-                         SafeMul(shadow_frame.GetVReg(vregA),
-                                 shadow_frame.GetVReg(inst->VRegB_12x(inst_data))));
-    ADVANCE(1);
-  }
-  HANDLE_INSTRUCTION_END();
-
-  HANDLE_INSTRUCTION_START(DIV_INT_2ADDR) {
-    uint32_t vregA = inst->VRegA_12x(inst_data);
-    bool success = DoIntDivide(shadow_frame, vregA, shadow_frame.GetVReg(vregA),
-                               shadow_frame.GetVReg(inst->VRegB_12x(inst_data)));
-    POSSIBLY_HANDLE_PENDING_EXCEPTION(!success, 1);
-  }
-  HANDLE_INSTRUCTION_END();
-
-  HANDLE_INSTRUCTION_START(REM_INT_2ADDR) {
-    uint32_t vregA = inst->VRegA_12x(inst_data);
-    bool success = DoIntRemainder(shadow_frame, vregA, shadow_frame.GetVReg(vregA),
-                                  shadow_frame.GetVReg(inst->VRegB_12x(inst_data)));
-    POSSIBLY_HANDLE_PENDING_EXCEPTION(!success, 1);
-  }
-  HANDLE_INSTRUCTION_END();
-
-  HANDLE_INSTRUCTION_START(SHL_INT_2ADDR) {
-    uint32_t vregA = inst->VRegA_12x(inst_data);
-    shadow_frame.SetVReg(vregA,
-                         shadow_frame.GetVReg(vregA) <<
-                         (shadow_frame.GetVReg(inst->VRegB_12x(inst_data)) & 0x1f));
-    ADVANCE(1);
-  }
-  HANDLE_INSTRUCTION_END();
-
-  HANDLE_INSTRUCTION_START(SHR_INT_2ADDR) {
-    uint32_t vregA = inst->VRegA_12x(inst_data);
-    shadow_frame.SetVReg(vregA,
-                         shadow_frame.GetVReg(vregA) >>
-                         (shadow_frame.GetVReg(inst->VRegB_12x(inst_data)) & 0x1f));
-    ADVANCE(1);
-  }
-  HANDLE_INSTRUCTION_END();
-
-  HANDLE_INSTRUCTION_START(USHR_INT_2ADDR) {
-    uint32_t vregA = inst->VRegA_12x(inst_data);
-    shadow_frame.SetVReg(vregA,
-                         static_cast<uint32_t>(shadow_frame.GetVReg(vregA)) >>
-                         (shadow_frame.GetVReg(inst->VRegB_12x(inst_data)) & 0x1f));
-    ADVANCE(1);
-  }
-  HANDLE_INSTRUCTION_END();
-
-  HANDLE_INSTRUCTION_START(AND_INT_2ADDR) {
-    uint32_t vregA = inst->VRegA_12x(inst_data);
-    shadow_frame.SetVReg(vregA,
-                         shadow_frame.GetVReg(vregA) &
-                         shadow_frame.GetVReg(inst->VRegB_12x(inst_data)));
-    ADVANCE(1);
-  }
-  HANDLE_INSTRUCTION_END();
-
-  HANDLE_INSTRUCTION_START(OR_INT_2ADDR) {
-    uint32_t vregA = inst->VRegA_12x(inst_data);
-    shadow_frame.SetVReg(vregA,
-                         shadow_frame.GetVReg(vregA) |
-                         shadow_frame.GetVReg(inst->VRegB_12x(inst_data)));
-    ADVANCE(1);
-  }
-  HANDLE_INSTRUCTION_END();
-
-  HANDLE_INSTRUCTION_START(XOR_INT_2ADDR) {
-    uint32_t vregA = inst->VRegA_12x(inst_data);
-    shadow_frame.SetVReg(vregA,
-                         shadow_frame.GetVReg(vregA) ^
-                         shadow_frame.GetVReg(inst->VRegB_12x(inst_data)));
-    ADVANCE(1);
-  }
-  HANDLE_INSTRUCTION_END();
-
-  HANDLE_INSTRUCTION_START(ADD_LONG_2ADDR) {
-    uint32_t vregA = inst->VRegA_12x(inst_data);
-    shadow_frame.SetVRegLong(vregA,
-                             SafeAdd(shadow_frame.GetVRegLong(vregA),
-                                     shadow_frame.GetVRegLong(inst->VRegB_12x(inst_data))));
-    ADVANCE(1);
-  }
-  HANDLE_INSTRUCTION_END();
-
-  HANDLE_INSTRUCTION_START(SUB_LONG_2ADDR) {
-    uint32_t vregA = inst->VRegA_12x(inst_data);
-    shadow_frame.SetVRegLong(vregA,
-                             SafeSub(shadow_frame.GetVRegLong(vregA),
-                                     shadow_frame.GetVRegLong(inst->VRegB_12x(inst_data))));
-    ADVANCE(1);
-  }
-  HANDLE_INSTRUCTION_END();
-
-  HANDLE_INSTRUCTION_START(MUL_LONG_2ADDR) {
-    uint32_t vregA = inst->VRegA_12x(inst_data);
-    shadow_frame.SetVRegLong(vregA,
-                             SafeMul(shadow_frame.GetVRegLong(vregA),
-                                     shadow_frame.GetVRegLong(inst->VRegB_12x(inst_data))));
-    ADVANCE(1);
-  }
-  HANDLE_INSTRUCTION_END();
-
-  HANDLE_INSTRUCTION_START(DIV_LONG_2ADDR) {
-    uint32_t vregA = inst->VRegA_12x(inst_data);
-    bool success = DoLongDivide(shadow_frame, vregA, shadow_frame.GetVRegLong(vregA),
-                                shadow_frame.GetVRegLong(inst->VRegB_12x(inst_data)));
-    POSSIBLY_HANDLE_PENDING_EXCEPTION(!success, 1);
-  }
-  HANDLE_INSTRUCTION_END();
-
-  HANDLE_INSTRUCTION_START(REM_LONG_2ADDR) {
-    uint32_t vregA = inst->VRegA_12x(inst_data);
-    bool success = DoLongRemainder(shadow_frame, vregA, shadow_frame.GetVRegLong(vregA),
-                                   shadow_frame.GetVRegLong(inst->VRegB_12x(inst_data)));
-    POSSIBLY_HANDLE_PENDING_EXCEPTION(!success, 1);
-  }
-  HANDLE_INSTRUCTION_END();
-
-  HANDLE_INSTRUCTION_START(AND_LONG_2ADDR) {
-    uint32_t vregA = inst->VRegA_12x(inst_data);
-    shadow_frame.SetVRegLong(vregA,
-                             shadow_frame.GetVRegLong(vregA) &
-                             shadow_frame.GetVRegLong(inst->VRegB_12x(inst_data)));
-    ADVANCE(1);
-  }
-  HANDLE_INSTRUCTION_END();
-
-  HANDLE_INSTRUCTION_START(OR_LONG_2ADDR) {
-    uint32_t vregA = inst->VRegA_12x(inst_data);
-    shadow_frame.SetVRegLong(vregA,
-                             shadow_frame.GetVRegLong(vregA) |
-                             shadow_frame.GetVRegLong(inst->VRegB_12x(inst_data)));
-    ADVANCE(1);
-  }
-  HANDLE_INSTRUCTION_END();
-
-  HANDLE_INSTRUCTION_START(XOR_LONG_2ADDR) {
-    uint32_t vregA = inst->VRegA_12x(inst_data);
-    shadow_frame.SetVRegLong(vregA,
-                             shadow_frame.GetVRegLong(vregA) ^
-                             shadow_frame.GetVRegLong(inst->VRegB_12x(inst_data)));
-    ADVANCE(1);
-  }
-  HANDLE_INSTRUCTION_END();
-
-  HANDLE_INSTRUCTION_START(SHL_LONG_2ADDR) {
-    uint32_t vregA = inst->VRegA_12x(inst_data);
-    shadow_frame.SetVRegLong(vregA,
-                             shadow_frame.GetVRegLong(vregA) <<
-                             (shadow_frame.GetVReg(inst->VRegB_12x(inst_data)) & 0x3f));
-    ADVANCE(1);
-  }
-  HANDLE_INSTRUCTION_END();
-
-  HANDLE_INSTRUCTION_START(SHR_LONG_2ADDR) {
-    uint32_t vregA = inst->VRegA_12x(inst_data);
-    shadow_frame.SetVRegLong(vregA,
-                             shadow_frame.GetVRegLong(vregA) >>
-                             (shadow_frame.GetVReg(inst->VRegB_12x(inst_data)) & 0x3f));
-    ADVANCE(1);
-  }
-  HANDLE_INSTRUCTION_END();
-
-  HANDLE_INSTRUCTION_START(USHR_LONG_2ADDR) {
-    uint32_t vregA = inst->VRegA_12x(inst_data);
-    shadow_frame.SetVRegLong(vregA,
-                             static_cast<uint64_t>(shadow_frame.GetVRegLong(vregA)) >>
-                             (shadow_frame.GetVReg(inst->VRegB_12x(inst_data)) & 0x3f));
-    ADVANCE(1);
-  }
-  HANDLE_INSTRUCTION_END();
-
-  HANDLE_INSTRUCTION_START(ADD_FLOAT_2ADDR) {
-    uint32_t vregA = inst->VRegA_12x(inst_data);
-    shadow_frame.SetVRegFloat(vregA,
-                              shadow_frame.GetVRegFloat(vregA) +
-                              shadow_frame.GetVRegFloat(inst->VRegB_12x(inst_data)));
-    ADVANCE(1);
-  }
-  HANDLE_INSTRUCTION_END();
-
-  HANDLE_INSTRUCTION_START(SUB_FLOAT_2ADDR) {
-    uint32_t vregA = inst->VRegA_12x(inst_data);
-    shadow_frame.SetVRegFloat(vregA,
-                              shadow_frame.GetVRegFloat(vregA) -
-                              shadow_frame.GetVRegFloat(inst->VRegB_12x(inst_data)));
-    ADVANCE(1);
-  }
-  HANDLE_INSTRUCTION_END();
-
-  HANDLE_INSTRUCTION_START(MUL_FLOAT_2ADDR) {
-    uint32_t vregA = inst->VRegA_12x(inst_data);
-    shadow_frame.SetVRegFloat(vregA,
-                              shadow_frame.GetVRegFloat(vregA) *
-                              shadow_frame.GetVRegFloat(inst->VRegB_12x(inst_data)));
-    ADVANCE(1);
-  }
-  HANDLE_INSTRUCTION_END();
-
-  HANDLE_INSTRUCTION_START(DIV_FLOAT_2ADDR) {
-    uint32_t vregA = inst->VRegA_12x(inst_data);
-    shadow_frame.SetVRegFloat(vregA,
-                              shadow_frame.GetVRegFloat(vregA) /
-                              shadow_frame.GetVRegFloat(inst->VRegB_12x(inst_data)));
-    ADVANCE(1);
-  }
-  HANDLE_INSTRUCTION_END();
-
-  HANDLE_INSTRUCTION_START(REM_FLOAT_2ADDR) {
-    uint32_t vregA = inst->VRegA_12x(inst_data);
-    shadow_frame.SetVRegFloat(vregA,
-                              fmodf(shadow_frame.GetVRegFloat(vregA),
-                                    shadow_frame.GetVRegFloat(inst->VRegB_12x(inst_data))));
-    ADVANCE(1);
-  }
-  HANDLE_INSTRUCTION_END();
-
-  HANDLE_INSTRUCTION_START(ADD_DOUBLE_2ADDR) {
-    uint32_t vregA = inst->VRegA_12x(inst_data);
-    shadow_frame.SetVRegDouble(vregA,
-                               shadow_frame.GetVRegDouble(vregA) +
-                               shadow_frame.GetVRegDouble(inst->VRegB_12x(inst_data)));
-    ADVANCE(1);
-  }
-  HANDLE_INSTRUCTION_END();
-
-  HANDLE_INSTRUCTION_START(SUB_DOUBLE_2ADDR) {
-    uint32_t vregA = inst->VRegA_12x(inst_data);
-    shadow_frame.SetVRegDouble(vregA,
-                               shadow_frame.GetVRegDouble(vregA) -
-                               shadow_frame.GetVRegDouble(inst->VRegB_12x(inst_data)));
-    ADVANCE(1);
-  }
-  HANDLE_INSTRUCTION_END();
-
-  HANDLE_INSTRUCTION_START(MUL_DOUBLE_2ADDR) {
-    uint32_t vregA = inst->VRegA_12x(inst_data);
-    shadow_frame.SetVRegDouble(vregA,
-                               shadow_frame.GetVRegDouble(vregA) *
-                               shadow_frame.GetVRegDouble(inst->VRegB_12x(inst_data)));
-    ADVANCE(1);
-  }
-  HANDLE_INSTRUCTION_END();
-
-  HANDLE_INSTRUCTION_START(DIV_DOUBLE_2ADDR) {
-    uint32_t vregA = inst->VRegA_12x(inst_data);
-    shadow_frame.SetVRegDouble(vregA,
-                               shadow_frame.GetVRegDouble(vregA) /
-                               shadow_frame.GetVRegDouble(inst->VRegB_12x(inst_data)));
-    ADVANCE(1);
-  }
-  HANDLE_INSTRUCTION_END();
-
-  HANDLE_INSTRUCTION_START(REM_DOUBLE_2ADDR) {
-    uint32_t vregA = inst->VRegA_12x(inst_data);
-    shadow_frame.SetVRegDouble(vregA,
-                               fmod(shadow_frame.GetVRegDouble(vregA),
-                                    shadow_frame.GetVRegDouble(inst->VRegB_12x(inst_data))));
-    ADVANCE(1);
-  }
-  HANDLE_INSTRUCTION_END();
-
-  HANDLE_INSTRUCTION_START(ADD_INT_LIT16)
-    shadow_frame.SetVReg(inst->VRegA_22s(inst_data),
-                         SafeAdd(shadow_frame.GetVReg(inst->VRegB_22s(inst_data)),
-                                 inst->VRegC_22s()));
-    ADVANCE(2);
-  HANDLE_INSTRUCTION_END();
-
-  HANDLE_INSTRUCTION_START(RSUB_INT)
-    shadow_frame.SetVReg(inst->VRegA_22s(inst_data),
-                         SafeSub(inst->VRegC_22s(),
-                                 shadow_frame.GetVReg(inst->VRegB_22s(inst_data))));
-    ADVANCE(2);
-  HANDLE_INSTRUCTION_END();
-
-  HANDLE_INSTRUCTION_START(MUL_INT_LIT16)
-    shadow_frame.SetVReg(inst->VRegA_22s(inst_data),
-                         SafeMul(shadow_frame.GetVReg(inst->VRegB_22s(inst_data)),
-                                 inst->VRegC_22s()));
-    ADVANCE(2);
-  HANDLE_INSTRUCTION_END();
-
-  HANDLE_INSTRUCTION_START(DIV_INT_LIT16) {
-    bool success = DoIntDivide(
-        shadow_frame, inst->VRegA_22s(inst_data), shadow_frame.GetVReg(inst->VRegB_22s(inst_data)),
-        inst->VRegC_22s());
-    POSSIBLY_HANDLE_PENDING_EXCEPTION(!success, 2);
-  }
-  HANDLE_INSTRUCTION_END();
-
-  HANDLE_INSTRUCTION_START(REM_INT_LIT16) {
-    bool success = DoIntRemainder(
-        shadow_frame, inst->VRegA_22s(inst_data), shadow_frame.GetVReg(inst->VRegB_22s(inst_data)),
-        inst->VRegC_22s());
-    POSSIBLY_HANDLE_PENDING_EXCEPTION(!success, 2);
-  }
-  HANDLE_INSTRUCTION_END();
-
-  HANDLE_INSTRUCTION_START(AND_INT_LIT16)
-    shadow_frame.SetVReg(inst->VRegA_22s(inst_data),
-                         shadow_frame.GetVReg(inst->VRegB_22s(inst_data)) &
-                         inst->VRegC_22s());
-    ADVANCE(2);
-  HANDLE_INSTRUCTION_END();
-
-  HANDLE_INSTRUCTION_START(OR_INT_LIT16)
-    shadow_frame.SetVReg(inst->VRegA_22s(inst_data),
-                         shadow_frame.GetVReg(inst->VRegB_22s(inst_data)) |
-                         inst->VRegC_22s());
-    ADVANCE(2);
-  HANDLE_INSTRUCTION_END();
-
-  HANDLE_INSTRUCTION_START(XOR_INT_LIT16)
-    shadow_frame.SetVReg(inst->VRegA_22s(inst_data),
-                         shadow_frame.GetVReg(inst->VRegB_22s(inst_data)) ^
-                         inst->VRegC_22s());
-    ADVANCE(2);
-  HANDLE_INSTRUCTION_END();
-
-  HANDLE_INSTRUCTION_START(ADD_INT_LIT8)
-    shadow_frame.SetVReg(inst->VRegA_22b(inst_data),
-                         SafeAdd(shadow_frame.GetVReg(inst->VRegB_22b()),
-                                 inst->VRegC_22b()));
-    ADVANCE(2);
-  HANDLE_INSTRUCTION_END();
-
-  HANDLE_INSTRUCTION_START(RSUB_INT_LIT8)
-    shadow_frame.SetVReg(inst->VRegA_22b(inst_data),
-                         SafeSub(inst->VRegC_22b(),
-                                 shadow_frame.GetVReg(inst->VRegB_22b())));
-    ADVANCE(2);
-  HANDLE_INSTRUCTION_END();
-
-  HANDLE_INSTRUCTION_START(MUL_INT_LIT8)
-    shadow_frame.SetVReg(inst->VRegA_22b(inst_data),
-                         SafeMul(shadow_frame.GetVReg(inst->VRegB_22b()),
-                                 inst->VRegC_22b()));
-    ADVANCE(2);
-  HANDLE_INSTRUCTION_END();
-
-  HANDLE_INSTRUCTION_START(DIV_INT_LIT8) {
-    bool success = DoIntDivide(shadow_frame, inst->VRegA_22b(inst_data),
-                               shadow_frame.GetVReg(inst->VRegB_22b()), inst->VRegC_22b());
-    POSSIBLY_HANDLE_PENDING_EXCEPTION(!success, 2);
-  }
-  HANDLE_INSTRUCTION_END();
-
-  HANDLE_INSTRUCTION_START(REM_INT_LIT8) {
-    bool success = DoIntRemainder(shadow_frame, inst->VRegA_22b(inst_data),
-                                  shadow_frame.GetVReg(inst->VRegB_22b()), inst->VRegC_22b());
-    POSSIBLY_HANDLE_PENDING_EXCEPTION(!success, 2);
-  }
-  HANDLE_INSTRUCTION_END();
-
-  HANDLE_INSTRUCTION_START(AND_INT_LIT8)
-    shadow_frame.SetVReg(inst->VRegA_22b(inst_data),
-                         shadow_frame.GetVReg(inst->VRegB_22b()) &
-                         inst->VRegC_22b());
-    ADVANCE(2);
-  HANDLE_INSTRUCTION_END();
-
-  HANDLE_INSTRUCTION_START(OR_INT_LIT8)
-    shadow_frame.SetVReg(inst->VRegA_22b(inst_data),
-                         shadow_frame.GetVReg(inst->VRegB_22b()) |
-                         inst->VRegC_22b());
-    ADVANCE(2);
-  HANDLE_INSTRUCTION_END();
-
-  HANDLE_INSTRUCTION_START(XOR_INT_LIT8)
-    shadow_frame.SetVReg(inst->VRegA_22b(inst_data),
-                         shadow_frame.GetVReg(inst->VRegB_22b()) ^
-                         inst->VRegC_22b());
-    ADVANCE(2);
-  HANDLE_INSTRUCTION_END();
-
-  HANDLE_INSTRUCTION_START(SHL_INT_LIT8)
-    shadow_frame.SetVReg(inst->VRegA_22b(inst_data),
-                         shadow_frame.GetVReg(inst->VRegB_22b()) <<
-                         (inst->VRegC_22b() & 0x1f));
-    ADVANCE(2);
-  HANDLE_INSTRUCTION_END();
-
-  HANDLE_INSTRUCTION_START(SHR_INT_LIT8)
-    shadow_frame.SetVReg(inst->VRegA_22b(inst_data),
-                         shadow_frame.GetVReg(inst->VRegB_22b()) >>
-                         (inst->VRegC_22b() & 0x1f));
-    ADVANCE(2);
-  HANDLE_INSTRUCTION_END();
-
-  HANDLE_INSTRUCTION_START(USHR_INT_LIT8)
-    shadow_frame.SetVReg(inst->VRegA_22b(inst_data),
-                         static_cast<uint32_t>(shadow_frame.GetVReg(inst->VRegB_22b())) >>
-                         (inst->VRegC_22b() & 0x1f));
-    ADVANCE(2);
-  HANDLE_INSTRUCTION_END();
-
-  HANDLE_INSTRUCTION_START(UNUSED_3E)
-    UnexpectedOpcode(inst, shadow_frame);
-  HANDLE_INSTRUCTION_END();
-
-  HANDLE_INSTRUCTION_START(UNUSED_3F)
-    UnexpectedOpcode(inst, shadow_frame);
-  HANDLE_INSTRUCTION_END();
-
-  HANDLE_INSTRUCTION_START(UNUSED_40)
-    UnexpectedOpcode(inst, shadow_frame);
-  HANDLE_INSTRUCTION_END();
-
-  HANDLE_INSTRUCTION_START(UNUSED_41)
-    UnexpectedOpcode(inst, shadow_frame);
-  HANDLE_INSTRUCTION_END();
-
-  HANDLE_INSTRUCTION_START(UNUSED_42)
-    UnexpectedOpcode(inst, shadow_frame);
-  HANDLE_INSTRUCTION_END();
-
-  HANDLE_INSTRUCTION_START(UNUSED_43)
-    UnexpectedOpcode(inst, shadow_frame);
-  HANDLE_INSTRUCTION_END();
-
-  HANDLE_INSTRUCTION_START(UNUSED_79)
-    UnexpectedOpcode(inst, shadow_frame);
-  HANDLE_INSTRUCTION_END();
-
-  HANDLE_INSTRUCTION_START(UNUSED_7A)
-    UnexpectedOpcode(inst, shadow_frame);
-  HANDLE_INSTRUCTION_END();
-
-  HANDLE_INSTRUCTION_START(UNUSED_F3)
-    UnexpectedOpcode(inst, shadow_frame);
-  HANDLE_INSTRUCTION_END();
-
-  HANDLE_INSTRUCTION_START(UNUSED_F4)
-    UnexpectedOpcode(inst, shadow_frame);
-  HANDLE_INSTRUCTION_END();
-
-  HANDLE_INSTRUCTION_START(UNUSED_F5)
-    UnexpectedOpcode(inst, shadow_frame);
-  HANDLE_INSTRUCTION_END();
-
-  HANDLE_INSTRUCTION_START(UNUSED_F6)
-    UnexpectedOpcode(inst, shadow_frame);
-  HANDLE_INSTRUCTION_END();
-
-  HANDLE_INSTRUCTION_START(UNUSED_F7)
-    UnexpectedOpcode(inst, shadow_frame);
-  HANDLE_INSTRUCTION_END();
-
-  HANDLE_INSTRUCTION_START(UNUSED_F8)
-    UnexpectedOpcode(inst, shadow_frame);
-  HANDLE_INSTRUCTION_END();
-
-  HANDLE_INSTRUCTION_START(UNUSED_F9)
-    UnexpectedOpcode(inst, shadow_frame);
-  HANDLE_INSTRUCTION_END();
-
-  HANDLE_INSTRUCTION_START(UNUSED_FA)
-    UnexpectedOpcode(inst, shadow_frame);
-  HANDLE_INSTRUCTION_END();
-
-  HANDLE_INSTRUCTION_START(UNUSED_FB)
-    UnexpectedOpcode(inst, shadow_frame);
-  HANDLE_INSTRUCTION_END();
-
-  HANDLE_INSTRUCTION_START(UNUSED_FC)
-    UnexpectedOpcode(inst, shadow_frame);
-  HANDLE_INSTRUCTION_END();
-
-  HANDLE_INSTRUCTION_START(UNUSED_FD)
-    UnexpectedOpcode(inst, shadow_frame);
-  HANDLE_INSTRUCTION_END();
-
-  HANDLE_INSTRUCTION_START(UNUSED_FE)
-    UnexpectedOpcode(inst, shadow_frame);
-  HANDLE_INSTRUCTION_END();
-
-  HANDLE_INSTRUCTION_START(UNUSED_FF)
-    UnexpectedOpcode(inst, shadow_frame);
-  HANDLE_INSTRUCTION_END();
-
-  exception_pending_label: {
-    CHECK(self->IsExceptionPending());
-    if (UNLIKELY(self->TestAllFlags())) {
-      self->CheckSuspend();
-      UPDATE_HANDLER_TABLE();
-    }
-    uint32_t found_dex_pc = FindNextInstructionFollowingException(self, shadow_frame, dex_pc,
-                                                                  instrumentation);
-    if (found_dex_pc == DexFile::kDexNoIndex) {
-      // Structured locking is to be enforced for abnormal termination, too.
-      DoMonitorCheckOnExit<do_assignability_check>(self, &shadow_frame);
-      return JValue(); /* Handled in caller. */
-    } else {
-      int32_t displacement = static_cast<int32_t>(found_dex_pc) - static_cast<int32_t>(dex_pc);
-      ADVANCE(displacement);
-    }
-  }
-
-// Create alternative instruction handlers dedicated to instrumentation.
-// Return instructions must not call Instrumentation::DexPcMovedEvent since they already call
-// Instrumentation::MethodExited. This is to avoid posting debugger events twice for this location.
-// Note: we do not use the kReturn instruction flag here (to test the instruction is a return). The
-// compiler seems to not evaluate "(Instruction::FlagsOf(Instruction::code) & kReturn) != 0" to
-// a constant condition that would remove the "if" statement so the test is free.
-#define INSTRUMENTATION_INSTRUCTION_HANDLER(o, code, n, f, i, a, v)                        \
-  alt_op_##code: {                                                                            \
-    if (UNLIKELY(instrumentation->HasDexPcListeners())) {                                     \
-      Object* this_object = shadow_frame.GetThisObject(code_item->ins_size_);                 \
-      instrumentation->DexPcMovedEvent(self, this_object, shadow_frame.GetMethod(), dex_pc);  \
-    }                                                                                         \
-    UPDATE_HANDLER_TABLE();                                                                   \
-    goto *handlersTable[instrumentation::kMainHandlerTable][Instruction::code];               \
-  }
-#include "dex_instruction_list.h"
-      DEX_INSTRUCTION_LIST(INSTRUMENTATION_INSTRUCTION_HANDLER)
-#undef DEX_INSTRUCTION_LIST
-#undef INSTRUMENTATION_INSTRUCTION_HANDLER
-}  // NOLINT(readability/fn_size)
-
-// Explicit definitions of ExecuteGotoImpl.
-template HOT_ATTR
-JValue ExecuteGotoImpl<true, false>(Thread* self, const DexFile::CodeItem* code_item,
-                                    ShadowFrame& shadow_frame, JValue result_register);
-template HOT_ATTR
-JValue ExecuteGotoImpl<false, false>(Thread* self, const DexFile::CodeItem* code_item,
-                                     ShadowFrame& shadow_frame, JValue result_register);
-template
-JValue ExecuteGotoImpl<true, true>(Thread* self, const DexFile::CodeItem* code_item,
-                                   ShadowFrame& shadow_frame, JValue result_register);
-template
-JValue ExecuteGotoImpl<false, true>(Thread* self, const DexFile::CodeItem* code_item,
-                                    ShadowFrame& shadow_frame, JValue result_register);
-
-#else
-
-template<bool do_access_check, bool transaction_active>
-JValue ExecuteGotoImpl(Thread*, const DexFile::CodeItem*, ShadowFrame&, JValue) {
-  LOG(FATAL) << "UNREACHABLE";
-  UNREACHABLE();
-}
-// Explicit definitions of ExecuteGotoImpl.
-template<>
-JValue ExecuteGotoImpl<true, false>(Thread* self, const DexFile::CodeItem* code_item,
-                                    ShadowFrame& shadow_frame, JValue result_register);
-template<>
-JValue ExecuteGotoImpl<false, false>(Thread* self, const DexFile::CodeItem* code_item,
-                                     ShadowFrame& shadow_frame, JValue result_register);
-template<>
-JValue ExecuteGotoImpl<true, true>(Thread* self,  const DexFile::CodeItem* code_item,
-                                   ShadowFrame& shadow_frame, JValue result_register);
-template<>
-JValue ExecuteGotoImpl<false, true>(Thread* self, const DexFile::CodeItem* code_item,
-                                    ShadowFrame& shadow_frame, JValue result_register);
-#endif
-
-}  // namespace interpreter
-}  // namespace art
diff --git a/runtime/interpreter/interpreter_goto_table_impl.h b/runtime/interpreter/interpreter_goto_table_impl.h
deleted file mode 100644
index c54746d..0000000
--- a/runtime/interpreter/interpreter_goto_table_impl.h
+++ /dev/null
@@ -1,41 +0,0 @@
-/*
- * Copyright (C) 2012 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_INTERPRETER_INTERPRETER_GOTO_TABLE_IMPL_H_
-#define ART_RUNTIME_INTERPRETER_INTERPRETER_GOTO_TABLE_IMPL_H_
-
-#include "base/macros.h"
-#include "base/mutex.h"
-#include "dex_file.h"
-#include "jvalue.h"
-
-namespace art {
-
-class ShadowFrame;
-class Thread;
-
-namespace interpreter {
-
-template<bool do_access_check, bool transaction_active>
-JValue ExecuteGotoImpl(Thread* self,
-                       const DexFile::CodeItem* code_item,
-                       ShadowFrame& shadow_frame,
-                       JValue result_register) REQUIRES_SHARED(Locks::mutator_lock_);
-
-}  // namespace interpreter
-}  // namespace art
-
-#endif  // ART_RUNTIME_INTERPRETER_INTERPRETER_GOTO_TABLE_IMPL_H_
diff --git a/runtime/mirror/dex_cache-inl.h b/runtime/mirror/dex_cache-inl.h
index a3071b7..220979a 100644
--- a/runtime/mirror/dex_cache-inl.h
+++ b/runtime/mirror/dex_cache-inl.h
@@ -44,13 +44,29 @@
 
 inline void DexCache::SetResolvedString(uint32_t string_idx, mirror::String* resolved) {
   DCHECK_LT(string_idx % NumStrings(), NumStrings());
-  // TODO default transaction support.
-  StringDexCachePair idx_ptr;
-  idx_ptr.string_index = string_idx;
-  idx_ptr.string_pointer = GcRoot<String>(resolved);
-  GetStrings()[string_idx % NumStrings()].store(idx_ptr, std::memory_order_relaxed);
+  GetStrings()[string_idx % NumStrings()].store(
+      StringDexCachePair(resolved, string_idx),
+      std::memory_order_relaxed);
+  Runtime* const runtime = Runtime::Current();
+  if (UNLIKELY(runtime->IsActiveTransaction())) {
+    DCHECK(runtime->IsAotCompiler());
+    runtime->RecordResolveString(this, string_idx);
+  }
   // TODO: Fine-grained marking, so that we don't need to go through all arrays in full.
-  Runtime::Current()->GetHeap()->WriteBarrierEveryFieldOf(this);
+  runtime->GetHeap()->WriteBarrierEveryFieldOf(this);
+}
+
+inline void DexCache::ClearString(uint32_t string_idx) {
+  const uint32_t slot_idx = string_idx % NumStrings();
+  DCHECK(Runtime::Current()->IsAotCompiler());
+  StringDexCacheType* slot = &GetStrings()[slot_idx];
+  // This is racy but should only be called from the transactional interpreter.
+  if (slot->load(std::memory_order_relaxed).string_index == string_idx) {
+    StringDexCachePair cleared(
+        nullptr,
+        StringDexCachePair::InvalidStringIndexForSlot(slot_idx));
+    slot->store(cleared, std::memory_order_relaxed);
+  }
 }
 
 inline Class* DexCache::GetResolvedType(uint32_t type_idx) {
diff --git a/runtime/mirror/dex_cache.h b/runtime/mirror/dex_cache.h
index caf00c2..7d4021f 100644
--- a/runtime/mirror/dex_cache.h
+++ b/runtime/mirror/dex_cache.h
@@ -56,12 +56,20 @@
   // it's always non-null if the string id branch succeeds (except for the 0th string id).
   // Set the initial state for the 0th entry to be {0,1} which is guaranteed to fail
   // the lookup string id == stored id branch.
+  StringDexCachePair(String* string, uint32_t string_idx)
+      : string_pointer(string),
+        string_index(string_idx) {}
+  StringDexCachePair() = default;
+  StringDexCachePair(const StringDexCachePair&) = default;
+  StringDexCachePair& operator=(const StringDexCachePair&) = default;
+
   static void Initialize(StringDexCacheType* strings) {
     mirror::StringDexCachePair first_elem;
     first_elem.string_pointer = GcRoot<String>(nullptr);
-    first_elem.string_index = 1;
+    first_elem.string_index = InvalidStringIndexForSlot(0);
     strings[0].store(first_elem, std::memory_order_relaxed);
   }
+
   static GcRoot<String> LookupString(StringDexCacheType* dex_cache,
                                      uint32_t string_idx,
                                      uint32_t cache_size) {
@@ -71,10 +79,15 @@
     DCHECK(!index_string.string_pointer.IsNull());
     return index_string.string_pointer;
   }
+
+  static uint32_t InvalidStringIndexForSlot(uint32_t slot) {
+    // Since the cache size is a power of two, 0 will always map to slot 0.
+    // Use 1 for slot 0 and 0 for all other slots.
+    return (slot == 0) ? 1u : 0u;
+  }
 };
 using StringDexCacheType = std::atomic<StringDexCachePair>;
 
-
 // C++ mirror of java.lang.DexCache.
 class MANAGED DexCache FINAL : public Object {
  public:
@@ -164,6 +177,10 @@
   void SetResolvedString(uint32_t string_idx, mirror::String* resolved) ALWAYS_INLINE
       REQUIRES_SHARED(Locks::mutator_lock_);
 
+  // Clear a string for a string_idx, used to undo string intern transactions to make sure
+  // the string isn't kept live.
+  void ClearString(uint32_t string_idx) REQUIRES_SHARED(Locks::mutator_lock_);
+
   Class* GetResolvedType(uint32_t type_idx) REQUIRES_SHARED(Locks::mutator_lock_);
 
   void SetResolvedType(uint32_t type_idx, Class* resolved) REQUIRES_SHARED(Locks::mutator_lock_);
diff --git a/runtime/oat.h b/runtime/oat.h
index 7c84fe9..35d0c92 100644
--- a/runtime/oat.h
+++ b/runtime/oat.h
@@ -32,7 +32,7 @@
 class PACKED(4) OatHeader {
  public:
   static constexpr uint8_t kOatMagic[] = { 'o', 'a', 't', '\n' };
-  static constexpr uint8_t kOatVersion[] = { '0', '8', '6', '\0' };
+  static constexpr uint8_t kOatVersion[] = { '0', '8', '7', '\0' };
 
   static constexpr const char* kImageLocationKey = "image-location";
   static constexpr const char* kDex2OatCmdLineKey = "dex2oat-cmdline";
diff --git a/runtime/runtime.cc b/runtime/runtime.cc
index a365a73..ba12d33 100644
--- a/runtime/runtime.cc
+++ b/runtime/runtime.cc
@@ -1929,6 +1929,12 @@
   preinitialization_transaction_->RecordWeakStringRemoval(s);
 }
 
+void Runtime::RecordResolveString(mirror::DexCache* dex_cache, uint32_t string_idx) const {
+  DCHECK(IsAotCompiler());
+  DCHECK(IsActiveTransaction());
+  preinitialization_transaction_->RecordResolveString(dex_cache, string_idx);
+}
+
 void Runtime::SetFaultMessage(const std::string& message) {
   MutexLock mu(Thread::Current(), fault_message_lock_);
   fault_message_ = message;
diff --git a/runtime/runtime.h b/runtime/runtime.h
index 44f765a..dc14c04 100644
--- a/runtime/runtime.h
+++ b/runtime/runtime.h
@@ -55,8 +55,9 @@
 }  // namespace jit
 
 namespace mirror {
-  class ClassLoader;
   class Array;
+  class ClassLoader;
+  class DexCache;
   template<class T> class ObjectArray;
   template<class T> class PrimitiveArray;
   typedef PrimitiveArray<int8_t> ByteArray;
@@ -508,6 +509,8 @@
       REQUIRES(Locks::intern_table_lock_);
   void RecordWeakStringRemoval(mirror::String* s) const
       REQUIRES(Locks::intern_table_lock_);
+  void RecordResolveString(mirror::DexCache* dex_cache, uint32_t string_idx) const
+      REQUIRES_SHARED(Locks::mutator_lock_);
 
   void SetFaultMessage(const std::string& message) REQUIRES(!fault_message_lock_);
   // Only read by the signal handler, NO_THREAD_SAFETY_ANALYSIS to prevent lock order violations
diff --git a/runtime/simulator/Android.bp b/runtime/simulator/Android.bp
index ec0b49e..49322fc 100644
--- a/runtime/simulator/Android.bp
+++ b/runtime/simulator/Android.bp
@@ -16,6 +16,9 @@
 
 cc_defaults {
     name: "libart_simulator_defaults",
+    host_supported: true,
+    device_supported: false,
+
     defaults: ["art_defaults"],
     srcs: [
         "code_simulator.cc",
@@ -29,7 +32,7 @@
     include_dirs: ["art/runtime"],
 }
 
-cc_library_host_shared {
+art_cc_library {
     name: "libart-simulator",
     defaults: ["libart_simulator_defaults"],
     shared_libs: [
@@ -38,7 +41,7 @@
     ],
 }
 
-cc_library_host_shared {
+art_cc_library {
     name: "libartd-simulator",
     defaults: [
         "art_debug_defaults",
diff --git a/runtime/simulator/code_simulator_arm64.cc b/runtime/simulator/code_simulator_arm64.cc
index 897d4f5..c7ad1fd 100644
--- a/runtime/simulator/code_simulator_arm64.cc
+++ b/runtime/simulator/code_simulator_arm64.cc
@@ -16,6 +16,8 @@
 
 #include "simulator/code_simulator_arm64.h"
 
+#include "base/logging.h"
+
 using namespace vixl::aarch64;  // NOLINT(build/namespaces)
 
 namespace art {
diff --git a/runtime/stack.cc b/runtime/stack.cc
index ec492ed..4678ac6 100644
--- a/runtime/stack.cc
+++ b/runtime/stack.cc
@@ -319,8 +319,11 @@
 bool StackVisitor::GetRegisterIfAccessible(uint32_t reg, VRegKind kind, uint32_t* val) const {
   const bool is_float = (kind == kFloatVReg) || (kind == kDoubleLoVReg) || (kind == kDoubleHiVReg);
 
-  // X86 float registers are 64-bit and the logic below does not apply.
-  DCHECK(!is_float || kRuntimeISA != InstructionSet::kX86);
+  if (kRuntimeISA == InstructionSet::kX86 && is_float) {
+    // X86 float registers are 64-bit and each XMM register is provided as two separate
+    // 32-bit registers by the context.
+    reg = (kind == kDoubleHiVReg) ? (2 * reg + 1) : (2 * reg);
+  }
 
   if (!IsAccessibleRegister(reg, is_float)) {
     return false;
diff --git a/runtime/transaction.cc b/runtime/transaction.cc
index d91860b..9f8d981 100644
--- a/runtime/transaction.cc
+++ b/runtime/transaction.cc
@@ -49,13 +49,15 @@
     for (auto it : array_logs_) {
       array_values_count += it.second.Size();
     }
-    size_t string_count = intern_string_logs_.size();
+    size_t intern_string_count = intern_string_logs_.size();
+    size_t resolve_string_count = resolve_string_logs_.size();
     LOG(INFO) << "Transaction::~Transaction"
               << ": objects_count=" << objects_count
               << ", field_values_count=" << field_values_count
               << ", array_count=" << array_count
               << ", array_values_count=" << array_values_count
-              << ", string_count=" << string_count;
+              << ", intern_string_count=" << intern_string_count
+              << ", resolve_string_count=" << resolve_string_count;
   }
 }
 
@@ -165,6 +167,13 @@
   array_log.LogValue(index, value);
 }
 
+void Transaction::RecordResolveString(mirror::DexCache* dex_cache, uint32_t string_idx) {
+  DCHECK(dex_cache != nullptr);
+  DCHECK_LT(string_idx, dex_cache->GetDexFile()->NumStringIds());
+  MutexLock mu(Thread::Current(), log_lock_);
+  resolve_string_logs_.push_back(ResolveStringLog(dex_cache, string_idx));
+}
+
 void Transaction::RecordStrongStringInsertion(mirror::String* s) {
   InternStringLog log(s, InternStringLog::kStrongString, InternStringLog::kInsert);
   LogInternedString(log);
@@ -200,6 +209,7 @@
   UndoObjectModifications();
   UndoArrayModifications();
   UndoInternStringTableModifications();
+  UndoResolveStringModifications();
 }
 
 void Transaction::UndoObjectModifications() {
@@ -230,11 +240,19 @@
   intern_string_logs_.clear();
 }
 
+void Transaction::UndoResolveStringModifications() {
+  for (ResolveStringLog& string_log : resolve_string_logs_) {
+    string_log.Undo();
+  }
+  resolve_string_logs_.clear();
+}
+
 void Transaction::VisitRoots(RootVisitor* visitor) {
   MutexLock mu(Thread::Current(), log_lock_);
   VisitObjectLogs(visitor);
   VisitArrayLogs(visitor);
-  VisitStringLogs(visitor);
+  VisitInternStringLogs(visitor);
+  VisitResolveStringLogs(visitor);
 }
 
 void Transaction::VisitObjectLogs(RootVisitor* visitor) {
@@ -292,12 +310,18 @@
   }
 }
 
-void Transaction::VisitStringLogs(RootVisitor* visitor) {
+void Transaction::VisitInternStringLogs(RootVisitor* visitor) {
   for (InternStringLog& log : intern_string_logs_) {
     log.VisitRoots(visitor);
   }
 }
 
+void Transaction::VisitResolveStringLogs(RootVisitor* visitor) {
+  for (ResolveStringLog& log : resolve_string_logs_) {
+    log.VisitRoots(visitor);
+  }
+}
+
 void Transaction::ObjectLog::LogBooleanValue(MemberOffset offset, uint8_t value, bool is_volatile) {
   LogValue(ObjectLog::kBoolean, offset, value, is_volatile);
 }
@@ -481,6 +505,21 @@
   visitor->VisitRoot(reinterpret_cast<mirror::Object**>(&str_), RootInfo(kRootInternedString));
 }
 
+void Transaction::ResolveStringLog::Undo() {
+  dex_cache_.Read()->ClearString(string_idx_);
+}
+
+Transaction::ResolveStringLog::ResolveStringLog(mirror::DexCache* dex_cache, uint32_t string_idx)
+    : dex_cache_(dex_cache),
+      string_idx_(string_idx) {
+  DCHECK(dex_cache != nullptr);
+  DCHECK_LT(string_idx_, dex_cache->GetDexFile()->NumStringIds());
+}
+
+void Transaction::ResolveStringLog::VisitRoots(RootVisitor* visitor) {
+  dex_cache_.VisitRoot(visitor, RootInfo(kRootVMInternal));
+}
+
 void Transaction::ArrayLog::LogValue(size_t index, uint64_t value) {
   auto it = array_values_.find(index);
   if (it == array_values_.end()) {
diff --git a/runtime/transaction.h b/runtime/transaction.h
index bc9c640..584dfb8 100644
--- a/runtime/transaction.h
+++ b/runtime/transaction.h
@@ -32,6 +32,7 @@
 namespace art {
 namespace mirror {
 class Array;
+class DexCache;
 class Object;
 class String;
 }
@@ -95,6 +96,11 @@
       REQUIRES(Locks::intern_table_lock_)
       REQUIRES(!log_lock_);
 
+  // Record resolve string.
+  void RecordResolveString(mirror::DexCache* dex_cache, uint32_t string_idx)
+      REQUIRES_SHARED(Locks::mutator_lock_)
+      REQUIRES(!log_lock_);
+
   // Abort transaction by undoing all recorded changes.
   void Rollback()
       REQUIRES_SHARED(Locks::mutator_lock_)
@@ -192,6 +198,19 @@
     const StringOp string_op_;
   };
 
+  class ResolveStringLog : public ValueObject {
+   public:
+    ResolveStringLog(mirror::DexCache* dex_cache, uint32_t string_idx);
+
+    void Undo() REQUIRES_SHARED(Locks::mutator_lock_);
+
+    void VisitRoots(RootVisitor* visitor) REQUIRES_SHARED(Locks::mutator_lock_);
+
+   private:
+    GcRoot<mirror::DexCache> dex_cache_;
+    const uint32_t string_idx_;
+  };
+
   void LogInternedString(const InternStringLog& log)
       REQUIRES(Locks::intern_table_lock_)
       REQUIRES(!log_lock_);
@@ -206,6 +225,9 @@
       REQUIRES(Locks::intern_table_lock_)
       REQUIRES(log_lock_)
       REQUIRES_SHARED(Locks::mutator_lock_);
+  void UndoResolveStringModifications()
+      REQUIRES(log_lock_)
+      REQUIRES_SHARED(Locks::mutator_lock_);
 
   void VisitObjectLogs(RootVisitor* visitor)
       REQUIRES(log_lock_)
@@ -213,7 +235,10 @@
   void VisitArrayLogs(RootVisitor* visitor)
       REQUIRES(log_lock_)
       REQUIRES_SHARED(Locks::mutator_lock_);
-  void VisitStringLogs(RootVisitor* visitor)
+  void VisitInternStringLogs(RootVisitor* visitor)
+      REQUIRES(log_lock_)
+      REQUIRES_SHARED(Locks::mutator_lock_);
+  void VisitResolveStringLogs(RootVisitor* visitor)
       REQUIRES(log_lock_)
       REQUIRES_SHARED(Locks::mutator_lock_);
 
@@ -223,6 +248,7 @@
   std::map<mirror::Object*, ObjectLog> object_logs_ GUARDED_BY(log_lock_);
   std::map<mirror::Array*, ArrayLog> array_logs_  GUARDED_BY(log_lock_);
   std::list<InternStringLog> intern_string_logs_ GUARDED_BY(log_lock_);
+  std::list<ResolveStringLog> resolve_string_logs_ GUARDED_BY(log_lock_);
   bool aborted_ GUARDED_BY(log_lock_);
   std::string abort_message_ GUARDED_BY(log_lock_);
 
diff --git a/runtime/transaction_test.cc b/runtime/transaction_test.cc
index 8279a26..82e529c 100644
--- a/runtime/transaction_test.cc
+++ b/runtime/transaction_test.cc
@@ -20,11 +20,14 @@
 #include "art_method-inl.h"
 #include "class_linker-inl.h"
 #include "common_runtime_test.h"
+#include "dex_file.h"
 #include "mirror/array-inl.h"
 #include "scoped_thread_state_change.h"
 
 namespace art {
 
+static const size_t kDexNoIndex = DexFile::kDexNoIndex;  // Make copy to prevent linking errors.
+
 class TransactionTest : public CommonRuntimeTest {
  public:
   // Tests failing class initialization due to native call with transaction rollback.
@@ -482,6 +485,55 @@
   EXPECT_EQ(objectArray->GetWithoutChecks(0), nullptr);
 }
 
+// Tests rolling back interned strings and resolved strings.
+TEST_F(TransactionTest, ResolveString) {
+  ScopedObjectAccess soa(Thread::Current());
+  StackHandleScope<3> hs(soa.Self());
+  Handle<mirror::ClassLoader> class_loader(
+      hs.NewHandle(soa.Decode<mirror::ClassLoader*>(LoadDex("Transaction"))));
+  ASSERT_TRUE(class_loader.Get() != nullptr);
+
+  Handle<mirror::Class> h_klass(
+      hs.NewHandle(class_linker_->FindClass(soa.Self(), "LTransaction$ResolveString;",
+                                            class_loader)));
+  ASSERT_TRUE(h_klass.Get() != nullptr);
+
+  Handle<mirror::DexCache> h_dex_cache(hs.NewHandle(h_klass->GetDexCache()));
+  ASSERT_TRUE(h_dex_cache.Get() != nullptr);
+  const DexFile* const dex_file = h_dex_cache->GetDexFile();
+  ASSERT_TRUE(dex_file != nullptr);
+
+  // Go search the dex file to find the string id of our string.
+  static const char* kResolvedString = "ResolvedString";
+  const DexFile::StringId* string_id = dex_file->FindStringId(kResolvedString);
+  ASSERT_TRUE(string_id != nullptr);
+  uint32_t string_idx = dex_file->GetIndexForStringId(*string_id);
+  ASSERT_NE(string_idx, kDexNoIndex);
+  // String should only get resolved by the initializer.
+  EXPECT_TRUE(class_linker_->LookupString(*dex_file, string_idx, h_dex_cache) == nullptr);
+  EXPECT_TRUE(h_dex_cache->GetResolvedString(string_idx) == nullptr);
+  // Do the transaction, then roll back.
+  Transaction transaction;
+  Runtime::Current()->EnterTransactionMode(&transaction);
+  bool success = class_linker_->EnsureInitialized(soa.Self(), h_klass, true, true);
+  ASSERT_TRUE(success);
+  ASSERT_TRUE(h_klass->IsInitialized());
+  // Make sure the string got resolved by the transaction.
+  {
+    mirror::String* s = class_linker_->LookupString(*dex_file, string_idx, h_dex_cache);
+    ASSERT_TRUE(s != nullptr);
+    EXPECT_STREQ(s->ToModifiedUtf8().c_str(), kResolvedString);
+    EXPECT_EQ(s, h_dex_cache->GetResolvedString(string_idx));
+  }
+  Runtime::Current()->ExitTransactionMode();
+  transaction.Rollback();
+  // Check that the string did not stay resolved.
+  EXPECT_TRUE(class_linker_->LookupString(*dex_file, string_idx, h_dex_cache) == nullptr);
+  EXPECT_TRUE(h_dex_cache->GetResolvedString(string_idx) == nullptr);
+  ASSERT_FALSE(h_klass->IsInitialized());
+  ASSERT_FALSE(soa.Self()->IsExceptionPending());
+}
+
 // Tests successful class initialization without class initializer.
 TEST_F(TransactionTest, EmptyClass) {
   ScopedObjectAccess soa(Thread::Current());
diff --git a/runtime/utils.h b/runtime/utils.h
index 2389ce7..958f0a3 100644
--- a/runtime/utils.h
+++ b/runtime/utils.h
@@ -386,6 +386,16 @@
   __builtin___clear_cache(begin, end);
 }
 
+template <typename T>
+constexpr PointerSize ConvertToPointerSize(T any) {
+  if (any == 4 || any == 8) {
+    return static_cast<PointerSize>(any);
+  } else {
+    LOG(FATAL);
+    UNREACHABLE();
+  }
+}
+
 }  // namespace art
 
 #endif  // ART_RUNTIME_UTILS_H_
diff --git a/runtime/utils/dex_cache_arrays_layout-inl.h b/runtime/utils/dex_cache_arrays_layout-inl.h
index 4c63156..a85d033 100644
--- a/runtime/utils/dex_cache_arrays_layout-inl.h
+++ b/runtime/utils/dex_cache_arrays_layout-inl.h
@@ -55,7 +55,8 @@
 
 template <typename T>
 static constexpr PointerSize GcRootAsPointerSize() {
-  return ConvertToPointerSize(sizeof(GcRoot<T>));
+  static_assert(sizeof(GcRoot<T>) == 4U, "Unexpected GcRoot size");
+  return PointerSize::k32;
 }
 
 inline size_t DexCacheArraysLayout::TypeOffset(uint32_t type_idx) const {
diff --git a/test/137-cfi/cfi.cc b/test/137-cfi/cfi.cc
index 45251b8..9f1499e 100644
--- a/test/137-cfi/cfi.cc
+++ b/test/137-cfi/cfi.cc
@@ -29,6 +29,7 @@
 
 #include "base/logging.h"
 #include "base/macros.h"
+#include "base/stringprintf.h"
 #include "gc/heap.h"
 #include "gc/space/image_space.h"
 #include "oat_file.h"
@@ -55,7 +56,7 @@
   // Keep pausing.
   printf("Going to sleep\n");
   for (;;) {
-    pause();
+    sleep(1);
   }
 }
 
@@ -86,6 +87,19 @@
 
   return false;
 }
+
+static void MoreErrorInfo(pid_t pid, bool sig_quit_on_fail) {
+  printf("Secondary pid is %d\n", pid);
+
+  PrintFileToLog(StringPrintf("/proc/%d/maps", pid), ERROR);
+
+  if (sig_quit_on_fail) {
+    int res = kill(pid, SIGQUIT);
+    if (res != 0) {
+      PLOG(ERROR) << "Failed to send signal";
+    }
+  }
+}
 #endif
 
 // Currently we have to fall back to our own loader for the boot image when it's compiled PIC
@@ -254,10 +268,20 @@
     result = CheckStack(bt.get(), full_signatrues ? full_seq : seq);
   }
 
+  constexpr bool kSigQuitOnFail = true;
+  if (!result) {
+    MoreErrorInfo(pid, kSigQuitOnFail);
+  }
+
   if (ptrace(PTRACE_DETACH, pid, 0, 0) != 0) {
     PLOG(ERROR) << "Detach failed";
   }
 
+  // If we failed to unwind and induced an ANR dump, give the child some time (20s).
+  if (!result && kSigQuitOnFail) {
+    sleep(20);
+  }
+
   // Kill the other process once we are done with it.
   kill(pid, SIGKILL);
 
diff --git a/test/137-cfi/src/Main.java b/test/137-cfi/src/Main.java
index 5cfe33d..1ec7072 100644
--- a/test/137-cfi/src/Main.java
+++ b/test/137-cfi/src/Main.java
@@ -101,9 +101,10 @@
           }
 
           // Wait until the forked process had time to run until its sleep phase.
+          BufferedReader lineReader;
           try {
               InputStreamReader stdout = new InputStreamReader(p.getInputStream(), "UTF-8");
-              BufferedReader lineReader = new BufferedReader(stdout);
+              lineReader = new BufferedReader(stdout);
               while (!lineReader.readLine().contains("Going to sleep")) {
               }
           } catch (Exception e) {
@@ -112,6 +113,26 @@
 
           if (!unwindOtherProcess(fullSignatures, pid)) {
               System.out.println("Unwinding other process failed.");
+
+              // In this case, log all the output.
+              // Note: this is potentially non-terminating code, if the secondary is totally stuck.
+              //       We rely on the run-test timeout infrastructure to terminate the primary in
+              //       such a case.
+              try {
+                  String tmp;
+                  System.out.println("Output from the secondary:");
+                  while ((tmp = lineReader.readLine()) != null) {
+                      System.out.println("Secondary: " + tmp);
+                  }
+              } catch (Exception e) {
+                  e.printStackTrace(System.out);
+              }
+          }
+
+          try {
+              lineReader.close();
+          } catch (Exception e) {
+              e.printStackTrace(System.out);
           }
       } finally {
           // Kill the forked process if it is not already dead.
diff --git a/test/412-new-array/smali/fill_array_data.smali b/test/412-new-array/smali/fill_array_data.smali
index 2b24e56..f163084 100644
--- a/test/412-new-array/smali/fill_array_data.smali
+++ b/test/412-new-array/smali/fill_array_data.smali
@@ -2,6 +2,18 @@
 
 .super Ljava/lang/Object;
 
+.method public static emptyIntArray([I)V
+   .registers 1
+
+   fill-array-data v0, :ArrayData
+   return-void
+
+:ArrayData
+    .array-data 4
+    .end array-data
+
+.end method
+
 .method public static intArray([I)V
    .registers 1
 
diff --git a/test/412-new-array/src/Main.java b/test/412-new-array/src/Main.java
index d95d2c5..fb348ba 100644
--- a/test/412-new-array/src/Main.java
+++ b/test/412-new-array/src/Main.java
@@ -220,6 +220,38 @@
   public static void testSmaliFillArrayData() throws Exception {
     Class<?> c = Class.forName("FillArrayData");
     {
+      Method m = c.getMethod("emptyIntArray", int[].class);
+      int[] array = new int[0];
+      Object[] args = { array };
+      m.invoke(null, args);
+      assertEquals(0, array.length);
+
+      array = new int[2];
+      args[0] = array;
+      m.invoke(null, args);
+      // Test that nothing has been written to the array.
+      assertEquals(0, array[0]);
+      assertEquals(0, array[1]);
+
+      array = new int[] { 42, -42 };
+      args[0] = array;
+      m.invoke(null, args);
+      // Test that nothing has been written to the array.
+      assertEquals(42, array[0]);
+      assertEquals(-42, array[1]);
+
+      Throwable exception = null;
+      args[0] = null;
+      try {
+        m.invoke(null, args);
+      } catch (InvocationTargetException e) {
+        exception = e.getCause();
+        assertTrue(exception instanceof NullPointerException);
+      }
+      assertNotNull(exception);
+    }
+
+    {
       Method m = c.getMethod("intArray", int[].class);
       int[] array = new int[7];
       Object[] args = { array };
@@ -235,7 +267,7 @@
 
       array = new int[2];
       args[0] = array;
-      Throwable exception  = null;
+      Throwable exception = null;
       try {
         m.invoke(null, args);
       } catch (InvocationTargetException e) {
@@ -274,7 +306,7 @@
 
       array = new int[2];
       args[0] = array;
-      Throwable exception  = null;
+      Throwable exception = null;
       try {
         m.invoke(null, args);
       } catch (InvocationTargetException e) {
@@ -313,7 +345,7 @@
 
       array = new short[2];
       args[0] = array;
-      Throwable exception  = null;
+      Throwable exception = null;
       try {
         m.invoke(null, args);
       } catch (InvocationTargetException e) {
@@ -352,7 +384,7 @@
 
       array = new long[2];
       args[0] = array;
-      Throwable exception  = null;
+      Throwable exception = null;
       try {
         m.invoke(null, args);
       } catch (InvocationTargetException e) {
@@ -391,7 +423,7 @@
 
       array = new char[2];
       args[0] = array;
-      Throwable exception  = null;
+      Throwable exception = null;
       try {
         m.invoke(null, args);
       } catch (InvocationTargetException e) {
@@ -430,7 +462,7 @@
 
       array = new byte[2];
       args[0] = array;
-      Throwable exception  = null;
+      Throwable exception = null;
       try {
         m.invoke(null, args);
       } catch (InvocationTargetException e) {
@@ -467,7 +499,7 @@
 
       array = new boolean[2];
       args[0] = array;
-      Throwable exception  = null;
+      Throwable exception = null;
       try {
         m.invoke(null, args);
       } catch (InvocationTargetException e) {
diff --git a/test/534-checker-bce-deoptimization/expected.txt b/test/534-checker-bce-deoptimization/expected.txt
index 3823a29..b9a1e27 100644
--- a/test/534-checker-bce-deoptimization/expected.txt
+++ b/test/534-checker-bce-deoptimization/expected.txt
@@ -1 +1,5 @@
+array[0]=2.5f
+array[1]=2.625f
+array[0]=3.5
+array[1]=3.625
 finish
diff --git a/test/534-checker-bce-deoptimization/src/Main.java b/test/534-checker-bce-deoptimization/src/Main.java
index 8cd20f6..c4e4cbf 100644
--- a/test/534-checker-bce-deoptimization/src/Main.java
+++ b/test/534-checker-bce-deoptimization/src/Main.java
@@ -17,6 +17,8 @@
 public class Main {
     public static void main(String[] args) {
         new Main().run();
+        testPreserveFloat();
+        testPreserveDouble();
         System.out.println("finish");
     }
 
@@ -53,5 +55,77 @@
             b[i + 1] += c * b[i + 1];
         }
     }
+
+    /*
+     * Test that we correctly preserve floating point registers when we deoptimize.
+     *
+     * Note: These tests rely on the deoptimization happening before the loop,
+     * so that the loop is interpreted and fills the provided arrays. However,
+     * the BCE transformation can be modified to execute the loop as many times
+     * as the compiler can guarantee no AIOOBE and only deoptimize thereafter,
+     * just before the throwing iteration. Then the floating point registers
+     * would no longer be used after the deoptimization and another approach
+     * would be needed to test this.
+     */
+
+    static public void testPreserveFloat() {
+        float[] array = new float[2];
+        try {
+            $noinline$FloatFill(1.125f, 2.5f, array, 3);
+            throw new Error();
+        } catch (ArrayIndexOutOfBoundsException expected) {
+            System.out.println("array[0]=" + array[0] + "f");
+            System.out.println("array[1]=" + array[1] + "f");
+        }
+    }
+
+    /// CHECK-START: void Main.$noinline$FloatFill(float, float, float[], int) BCE (after)
+    /// CHECK-DAG:          Deoptimize
+    /// CHECK-DAG:          Deoptimize
+    /// CHECK-DAG:          Deoptimize
+    /// CHECK-NOT:          Deoptimize
+
+    /// CHECK-START: void Main.$noinline$FloatFill(float, float, float[], int) BCE (after)
+    /// CHECK-NOT:          BoundsCheck
+
+    public static void $noinline$FloatFill(float f1, float f2, float[] array, int n) {
+        if (doThrow) { throw new Error(); }
+        for (int i = 0; i < n; ++i) {
+            array[i] = ((i & 1) == 1) ? f1 : f2;
+            f1 += 1.5f;
+            f2 += 2.25f;
+        }
+    }
+
+    static public void testPreserveDouble() {
+        double[] array = new double[2];
+        try {
+            $noinline$DoubleFill(2.125, 3.5, array, 3);
+            throw new Error();
+        } catch (ArrayIndexOutOfBoundsException expected) {
+            System.out.println("array[0]=" + array[0]);
+            System.out.println("array[1]=" + array[1]);
+        }
+    }
+
+    /// CHECK-START: void Main.$noinline$DoubleFill(double, double, double[], int) BCE (after)
+    /// CHECK-DAG:          Deoptimize
+    /// CHECK-DAG:          Deoptimize
+    /// CHECK-DAG:          Deoptimize
+    /// CHECK-NOT:          Deoptimize
+
+    /// CHECK-START: void Main.$noinline$DoubleFill(double, double, double[], int) BCE (after)
+    /// CHECK-NOT:          BoundsCheck
+
+    public static void $noinline$DoubleFill(double d1, double d2, double[] array, int n) {
+        if (doThrow) { throw new Error(); }
+        for (int i = 0; i < n; ++i) {
+            array[i] = ((i & 1) == 1) ? d1 : d2;
+            d1 += 1.5;
+            d2 += 2.25;
+        }
+    }
+
+    public static boolean doThrow = false;
 }
 
diff --git a/test/538-checker-embed-constants/src/Main.java b/test/538-checker-embed-constants/src/Main.java
index f6713a2..04a12fa 100644
--- a/test/538-checker-embed-constants/src/Main.java
+++ b/test/538-checker-embed-constants/src/Main.java
@@ -102,12 +102,12 @@
 
   /// CHECK-START-ARM: long Main.and255(long) disassembly (after)
   /// CHECK-NOT:            movs {{r\d+}}, #255
-  /// CHECK-NOT:            and
-  /// CHECK-NOT:            bic
+  /// CHECK-NOT:            and{{(\.w)?}}
+  /// CHECK-NOT:            bic{{(\.w)?}}
   /// CHECK-DAG:            and {{r\d+}}, {{r\d+}}, #255
   /// CHECK-DAG:            movs {{r\d+}}, #0
-  /// CHECK-NOT:            and
-  /// CHECK-NOT:            bic
+  /// CHECK-NOT:            and{{(\.w)?}}
+  /// CHECK-NOT:            bic{{(\.w)?}}
 
   public static long and255(long arg) {
     return arg & 255L;
@@ -115,12 +115,13 @@
 
   /// CHECK-START-ARM: long Main.and511(long) disassembly (after)
   /// CHECK:                movw {{r\d+}}, #511
-  /// CHECK-NOT:            and
-  /// CHECK-NOT:            bic
-  /// CHECK-DAG:            and{{(\.w)?}} {{r\d+}}, {{r\d+}}, {{r\d+}}
-  /// CHECK-DAG:            movs {{r\d+}}, #0
-  /// CHECK-NOT:            and
-  /// CHECK-NOT:            bic
+  /// CHECK-NEXT:           movs {{r\d+}}, #0
+  /// CHECK-NOT:            and{{(\.w)?}}
+  /// CHECK-NOT:            bic{{(\.w)?}}
+  /// CHECK:                and{{(\.w)?}} {{r\d+}}, {{r\d+}}, {{r\d+}}
+  /// CHECK-NEXT:           and{{(\.w)?}} {{r\d+}}, {{r\d+}}, {{r\d+}}
+  /// CHECK-NOT:            and{{(\.w)?}}
+  /// CHECK-NOT:            bic{{(\.w)?}}
 
   public static long and511(long arg) {
     return arg & 511L;
@@ -128,11 +129,11 @@
 
   /// CHECK-START-ARM: long Main.andNot15(long) disassembly (after)
   /// CHECK-NOT:            mvn {{r\d+}}, #15
-  /// CHECK-NOT:            and
-  /// CHECK-NOT:            bic
+  /// CHECK-NOT:            and{{(\.w)?}}
+  /// CHECK-NOT:            bic{{(\.w)?}}
   /// CHECK:                bic {{r\d+}}, {{r\d+}}, #15
-  /// CHECK-NOT:            and
-  /// CHECK-NOT:            bic
+  /// CHECK-NOT:            and{{(\.w)?}}
+  /// CHECK-NOT:            bic{{(\.w)?}}
 
   public static long andNot15(long arg) {
     return arg & ~15L;
@@ -141,12 +142,12 @@
   /// CHECK-START-ARM: long Main.and0xfffffff00000000f(long) disassembly (after)
   /// CHECK-NOT:            movs {{r\d+}}, #15
   /// CHECK-NOT:            mvn {{r\d+}}, #15
-  /// CHECK-NOT:            and
-  /// CHECK-NOT:            bic
+  /// CHECK-NOT:            and{{(\.w)?}}
+  /// CHECK-NOT:            bic{{(\.w)?}}
   /// CHECK-DAG:            and {{r\d+}}, {{r\d+}}, #15
   /// CHECK-DAG:            bic {{r\d+}}, {{r\d+}}, #15
-  /// CHECK-NOT:            and
-  /// CHECK-NOT:            bic
+  /// CHECK-NOT:            and{{(\.w)?}}
+  /// CHECK-NOT:            bic{{(\.w)?}}
 
   public static long and0xfffffff00000000f(long arg) {
     return arg & 0xfffffff00000000fL;
@@ -154,10 +155,10 @@
 
   /// CHECK-START-ARM: long Main.or255(long) disassembly (after)
   /// CHECK-NOT:            movs {{r\d+}}, #255
-  /// CHECK-NOT:            orr
+  /// CHECK-NOT:            orr{{(\.w)?}}
   /// CHECK-NOT:            orn
   /// CHECK:                orr {{r\d+}}, {{r\d+}}, #255
-  /// CHECK-NOT:            orr
+  /// CHECK-NOT:            orr{{(\.w)?}}
   /// CHECK-NOT:            orn
 
   public static long or255(long arg) {
@@ -166,10 +167,12 @@
 
   /// CHECK-START-ARM: long Main.or511(long) disassembly (after)
   /// CHECK:                movw {{r\d+}}, #511
-  /// CHECK-NOT:            orr
+  /// CHECK-NEXT:           movs {{r\d+}}, #0
+  /// CHECK-NOT:            orr{{(\.w)?}}
   /// CHECK-NOT:            orn
   /// CHECK:                orr{{(\.w)?}} {{r\d+}}, {{r\d+}}, {{r\d+}}
-  /// CHECK-NOT:            orr
+  /// CHECK-NEXT:           orr{{(\.w)?}} {{r\d+}}, {{r\d+}}, {{r\d+}}
+  /// CHECK-NOT:            orr{{(\.w)?}}
   /// CHECK-NOT:            orn
 
   public static long or511(long arg) {
@@ -178,11 +181,11 @@
 
   /// CHECK-START-ARM: long Main.orNot15(long) disassembly (after)
   /// CHECK-NOT:            mvn {{r\d+}}, #15
-  /// CHECK-NOT:            orr
+  /// CHECK-NOT:            orr{{(\.w)?}}
   /// CHECK-NOT:            orn
   /// CHECK-DAG:            orn {{r\d+}}, {{r\d+}}, #15
   /// CHECK-DAG:            mvn {{r\d+}}, #0
-  /// CHECK-NOT:            orr
+  /// CHECK-NOT:            orr{{(\.w)?}}
   /// CHECK-NOT:            orn
 
   public static long orNot15(long arg) {
@@ -192,11 +195,11 @@
   /// CHECK-START-ARM: long Main.or0xfffffff00000000f(long) disassembly (after)
   /// CHECK-NOT:            movs {{r\d+}}, #15
   /// CHECK-NOT:            mvn {{r\d+}}, #15
-  /// CHECK-NOT:            orr
+  /// CHECK-NOT:            orr{{(\.w)?}}
   /// CHECK-NOT:            orn
   /// CHECK-DAG:            orr {{r\d+}}, {{r\d+}}, #15
   /// CHECK-DAG:            orn {{r\d+}}, {{r\d+}}, #15
-  /// CHECK-NOT:            orr
+  /// CHECK-NOT:            orr{{(\.w)?}}
   /// CHECK-NOT:            orn
 
   public static long or0xfffffff00000000f(long arg) {
@@ -205,9 +208,9 @@
 
   /// CHECK-START-ARM: long Main.xor255(long) disassembly (after)
   /// CHECK-NOT:            movs {{r\d+}}, #255
-  /// CHECK-NOT:            eor
+  /// CHECK-NOT:            eor{{(\.w)?}}
   /// CHECK:                eor {{r\d+}}, {{r\d+}}, #255
-  /// CHECK-NOT:            eor
+  /// CHECK-NOT:            eor{{(\.w)?}}
 
   public static long xor255(long arg) {
     return arg ^ 255L;
@@ -215,9 +218,11 @@
 
   /// CHECK-START-ARM: long Main.xor511(long) disassembly (after)
   /// CHECK:                movw {{r\d+}}, #511
-  /// CHECK-NOT:            eor
-  /// CHECK-DAG:            eor{{(\.w)?}} {{r\d+}}, {{r\d+}}, {{r\d+}}
-  /// CHECK-NOT:            eor
+  /// CHECK-NEXT:           movs {{r\d+}}, #0
+  /// CHECK-NOT:            eor{{(\.w)?}}
+  /// CHECK:                eor{{(\.w)?}} {{r\d+}}, {{r\d+}}, {{r\d+}}
+  /// CHECK-NEXT:           eor{{(\.w)?}} {{r\d+}}, {{r\d+}}, {{r\d+}}
+  /// CHECK-NOT:            eor{{(\.w)?}}
 
   public static long xor511(long arg) {
     return arg ^ 511L;
@@ -226,10 +231,10 @@
   /// CHECK-START-ARM: long Main.xorNot15(long) disassembly (after)
   /// CHECK-DAG:            mvn {{r\d+}}, #15
   /// CHECK-DAG:            mov.w {{r\d+}}, #-1
-  /// CHECK-NOT:            eor
+  /// CHECK-NOT:            eor{{(\.w)?}}
   /// CHECK-DAG:            eor{{(\.w)?}} {{r\d+}}, {{r\d+}}, {{r\d+}}
   /// CHECK-DAG:            eor{{(\.w)?}} {{r\d+}}, {{r\d+}}, {{r\d+}}
-  /// CHECK-NOT:            eor
+  /// CHECK-NOT:            eor{{(\.w)?}}
 
   public static long xorNot15(long arg) {
     return arg ^ ~15L;
@@ -239,10 +244,10 @@
   /// CHECK-START-ARM: long Main.xor0xfffffff00000000f(long) disassembly (after)
   /// CHECK-DAG:            movs {{r\d+}}, #15
   /// CHECK-DAG:            mvn {{r\d+}}, #15
-  /// CHECK-NOT:            eor
+  /// CHECK-NOT:            eor{{(\.w)?}}
   /// CHECK-DAG:            eor{{(\.w)?}} {{r\d+}}, {{r\d+}}, {{r\d+}}
   /// CHECK-DAG:            eor{{(\.w)?}} {{r\d+}}, {{r\d+}}, {{r\d+}}
-  /// CHECK-NOT:            eor
+  /// CHECK-NOT:            eor{{(\.w)?}}
 
   public static long xor0xfffffff00000000f(long arg) {
     return arg ^ 0xfffffff00000000fL;
@@ -251,10 +256,10 @@
   /// CHECK-START-ARM: long Main.xor0xf00000000000000f(long) disassembly (after)
   /// CHECK-NOT:            movs {{r\d+}}, #15
   /// CHECK-NOT:            mov.w {{r\d+}}, #-268435456
-  /// CHECK-NOT:            eor
+  /// CHECK-NOT:            eor{{(\.w)?}}
   /// CHECK-DAG:            eor {{r\d+}}, {{r\d+}}, #15
   /// CHECK-DAG:            eor {{r\d+}}, {{r\d+}}, #-268435456
-  /// CHECK-NOT:            eor
+  /// CHECK-NOT:            eor{{(\.w)?}}
 
   public static long xor0xf00000000000000f(long arg) {
     return arg ^ 0xf00000000000000fL;
diff --git a/test/Transaction/Transaction.java b/test/Transaction/Transaction.java
index 00e1fbb..e7085c1 100644
--- a/test/Transaction/Transaction.java
+++ b/test/Transaction/Transaction.java
@@ -18,6 +18,10 @@
     static class EmptyStatic {
     }
 
+    static class ResolveString {
+      static String s = "ResolvedString";
+    }
+
     static class StaticFieldClass {
       public static int intField;
       static {
diff --git a/tools/art b/tools/art
index d91b451..1a3bba7 100644
--- a/tools/art
+++ b/tools/art
@@ -87,7 +87,7 @@
 fi
 
 if [ z"$PERF" != z ]; then
-  invoke_with="perf record -o $ANDROID_DATA/perf.data -e cycles:u $invoke_with"
+  invoke_with="perf record -g -o $ANDROID_DATA/perf.data -e cycles:u $invoke_with"
   DEBUG_OPTION="-Xcompiler-option --generate-debug-info"
 fi
 
diff --git a/tools/bisection-search/README.md b/tools/bisection-search/README.md
deleted file mode 100644
index 857c930..0000000
--- a/tools/bisection-search/README.md
+++ /dev/null
@@ -1,43 +0,0 @@
-Bisection Bug Search
-====================
-
-Bisection Bug Search is a tool for finding compiler optimizations bugs. It
-accepts a program which exposes a bug by producing incorrect output and expected
-output for the program. It then attempts to narrow down the issue to a single
-method and optimization pass under the assumption that interpreter is correct.
-
-Given methods in order M0..Mn finds smallest i such that compiling Mi and
-interpreting all other methods produces incorrect output. Then, given ordered
-optimization passes P0..Pl, finds smallest j such that compiling Mi with passes
-P0..Pj-1 produces expected output and compiling Mi with passes P0..Pj produces
-incorrect output. Prints Mi and Pj.
-
-How to run Bisection Bug Search
-===============================
-
-    bisection_search.py [-h] -cp CLASSPATH
-                        [--expected-output EXPECTED_OUTPUT] [--device]
-                        [--lib LIB] [--64]
-                        [--dalvikvm-option [OPTION [OPTION ...]]]
-                        [--arg [TEST_ARGS [TEST_ARGS ...]]] [--image IMAGE]
-                        [--verbose]
-                        classname
-
-    positional arguments:
-      classname             name of class to run
-
-    optional arguments:
-      -h, --help            show this help message and exit
-      -cp CLASSPATH, --classpath CLASSPATH
-                            classpath
-      --expected-output EXPECTED_OUTPUT
-                            file containing expected output
-      --device              run on device
-      --lib LIB             lib to use, default: libart.so
-      --64                  x64 mode
-      --dalvikvm-option [OPTION [OPTION ...]]
-                            additional dalvikvm option
-      --arg [TEST_ARGS [TEST_ARGS ...]]
-                            argument to pass to program
-      --image IMAGE         path to image
-      --verbose             enable verbose output
diff --git a/tools/bisection-search/bisection_search.py b/tools/bisection-search/bisection_search.py
deleted file mode 100755
index d6c1749..0000000
--- a/tools/bisection-search/bisection_search.py
+++ /dev/null
@@ -1,300 +0,0 @@
-#!/usr/bin/env python3.4
-#
-# 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.
-
-"""Performs bisection bug search on methods and optimizations.
-
-See README.md.
-
-Example usage:
-./bisection-search.py -cp classes.dex --expected-output output Test
-"""
-
-import argparse
-import re
-import sys
-
-from common import DeviceTestEnv
-from common import FatalError
-from common import GetEnvVariableOrError
-from common import HostTestEnv
-
-# Passes that are never disabled during search process because disabling them
-# would compromise correctness.
-MANDATORY_PASSES = ['dex_cache_array_fixups_arm',
-                    'dex_cache_array_fixups_mips',
-                    'instruction_simplifier$before_codegen',
-                    'pc_relative_fixups_x86',
-                    'pc_relative_fixups_mips',
-                    'x86_memory_operand_generation']
-
-# Passes that show up as optimizations in compiler verbose output but aren't
-# driven by run-passes mechanism. They are mandatory and will always run, we
-# never pass them to --run-passes.
-NON_PASSES = ['builder', 'prepare_for_register_allocation',
-              'liveness', 'register']
-
-
-class Dex2OatWrapperTestable(object):
-  """Class representing a testable compilation.
-
-  Accepts filters on compiled methods and optimization passes.
-  """
-
-  def __init__(self, base_cmd, test_env, class_name, args,
-               expected_output=None, verbose=False):
-    """Constructor.
-
-    Args:
-      base_cmd: list of strings, base command to run.
-      test_env: ITestEnv.
-      class_name: string, name of class to run.
-      args: list of strings, program arguments to pass.
-      expected_output: string, expected output to compare against or None.
-      verbose: bool, enable verbose output.
-    """
-    self._base_cmd = base_cmd
-    self._test_env = test_env
-    self._class_name = class_name
-    self._args = args
-    self._expected_output = expected_output
-    self._compiled_methods_path = self._test_env.CreateFile('compiled_methods')
-    self._passes_to_run_path = self._test_env.CreateFile('run_passes')
-    self._verbose = verbose
-
-  def Test(self, compiled_methods, passes_to_run=None):
-    """Tests compilation with compiled_methods and run_passes switches active.
-
-    If compiled_methods is None then compiles all methods.
-    If passes_to_run is None then runs default passes.
-
-    Args:
-      compiled_methods: list of strings representing methods to compile or None.
-      passes_to_run: list of strings representing passes to run or None.
-
-    Returns:
-      True if test passes with given settings. False otherwise.
-    """
-    if self._verbose:
-      print('Testing methods: {0} passes:{1}.'.format(
-          compiled_methods, passes_to_run))
-    cmd = self._PrepareCmd(compiled_methods=compiled_methods,
-                           passes_to_run=passes_to_run,
-                           verbose_compiler=True)
-    (output, _, ret_code) = self._test_env.RunCommand(cmd)
-    res = ret_code == 0 and (self._expected_output is None
-                             or output == self._expected_output)
-    if self._verbose:
-      print('Test passed: {0}.'.format(res))
-    return res
-
-  def GetAllMethods(self):
-    """Get methods compiled during the test.
-
-    Returns:
-      List of strings representing methods compiled during the test.
-
-    Raises:
-      FatalError: An error occurred when retrieving methods list.
-    """
-    cmd = self._PrepareCmd(verbose_compiler=True)
-    (_, err_output, _) = self._test_env.RunCommand(cmd)
-    match_methods = re.findall(r'Building ([^\n]+)\n', err_output)
-    if not match_methods:
-      raise FatalError('Failed to retrieve methods list. '
-                       'Not recognized output format.')
-    return match_methods
-
-  def GetAllPassesForMethod(self, compiled_method):
-    """Get all optimization passes ran for a method during the test.
-
-    Args:
-      compiled_method: string representing method to compile.
-
-    Returns:
-      List of strings representing passes ran for compiled_method during test.
-
-    Raises:
-      FatalError: An error occurred when retrieving passes list.
-    """
-    cmd = self._PrepareCmd(compiled_methods=[compiled_method],
-                           verbose_compiler=True)
-    (_, err_output, _) = self._test_env.RunCommand(cmd)
-    match_passes = re.findall(r'Starting pass: ([^\n]+)\n', err_output)
-    if not match_passes:
-      raise FatalError('Failed to retrieve passes list. '
-                       'Not recognized output format.')
-    return [p for p in match_passes if p not in NON_PASSES]
-
-  def _PrepareCmd(self, compiled_methods=None, passes_to_run=None,
-                  verbose_compiler=False):
-    """Prepare command to run."""
-    cmd = list(self._base_cmd)
-    if compiled_methods is not None:
-      self._test_env.WriteLines(self._compiled_methods_path, compiled_methods)
-      cmd += ['-Xcompiler-option', '--compiled-methods={0}'.format(
-          self._compiled_methods_path)]
-    if passes_to_run is not None:
-      self._test_env.WriteLines(self._passes_to_run_path, passes_to_run)
-      cmd += ['-Xcompiler-option', '--run-passes={0}'.format(
-          self._passes_to_run_path)]
-    if verbose_compiler:
-      cmd += ['-Xcompiler-option', '--runtime-arg', '-Xcompiler-option',
-              '-verbose:compiler']
-    cmd += ['-classpath', self._test_env.classpath, self._class_name]
-    cmd += self._args
-    return cmd
-
-
-def BinarySearch(start, end, test):
-  """Binary search integers using test function to guide the process."""
-  while start < end:
-    mid = (start + end) // 2
-    if test(mid):
-      start = mid + 1
-    else:
-      end = mid
-  return start
-
-
-def FilterPasses(passes, cutoff_idx):
-  """Filters passes list according to cutoff_idx but keeps mandatory passes."""
-  return [opt_pass for idx, opt_pass in enumerate(passes)
-          if opt_pass in MANDATORY_PASSES or idx < cutoff_idx]
-
-
-def BugSearch(testable):
-  """Find buggy (method, optimization pass) pair for a given testable.
-
-  Args:
-    testable: Dex2OatWrapperTestable.
-
-  Returns:
-    (string, string) tuple. First element is name of method which when compiled
-    exposes test failure. Second element is name of optimization pass such that
-    for aforementioned method running all passes up to and excluding the pass
-    results in test passing but running all passes up to and including the pass
-    results in test failing.
-
-    (None, None) if test passes when compiling all methods.
-    (string, None) if a method is found which exposes the failure, but the
-      failure happens even when running just mandatory passes.
-
-  Raises:
-    FatalError: Testable fails with no methods compiled.
-    AssertionError: Method failed for all passes when bisecting methods, but
-    passed when bisecting passes. Possible sporadic failure.
-  """
-  all_methods = testable.GetAllMethods()
-  faulty_method_idx = BinarySearch(
-      0,
-      len(all_methods),
-      lambda mid: testable.Test(all_methods[0:mid]))
-  if faulty_method_idx == len(all_methods):
-    return (None, None)
-  if faulty_method_idx == 0:
-    raise FatalError('Testable fails with no methods compiled. '
-                     'Perhaps issue lies outside of compiler.')
-  faulty_method = all_methods[faulty_method_idx - 1]
-  all_passes = testable.GetAllPassesForMethod(faulty_method)
-  faulty_pass_idx = BinarySearch(
-      0,
-      len(all_passes),
-      lambda mid: testable.Test([faulty_method],
-                                FilterPasses(all_passes, mid)))
-  if faulty_pass_idx == 0:
-    return (faulty_method, None)
-  assert faulty_pass_idx != len(all_passes), 'Method must fail for some passes.'
-  faulty_pass = all_passes[faulty_pass_idx - 1]
-  return (faulty_method, faulty_pass)
-
-
-def PrepareParser():
-  """Prepares argument parser."""
-  parser = argparse.ArgumentParser()
-  parser.add_argument(
-      '-cp', '--classpath', required=True, type=str, help='classpath')
-  parser.add_argument('--expected-output', type=str,
-                      help='file containing expected output')
-  parser.add_argument(
-      '--device', action='store_true', default=False, help='run on device')
-  parser.add_argument('classname', type=str, help='name of class to run')
-  parser.add_argument('--lib', dest='lib', type=str, default='libart.so',
-                      help='lib to use, default: libart.so')
-  parser.add_argument('--64', dest='x64', action='store_true',
-                      default=False, help='x64 mode')
-  parser.add_argument('--dalvikvm-option', dest='dalvikvm_opts',
-                      metavar='OPTION', nargs='*', default=[],
-                      help='additional dalvikvm option')
-  parser.add_argument('--arg', dest='test_args', nargs='*', default=[],
-                      help='argument to pass to program')
-  parser.add_argument('--image', type=str, help='path to image')
-  parser.add_argument('--verbose', action='store_true',
-                      default=False, help='enable verbose output')
-  return parser
-
-
-def main():
-  # Parse arguments
-  parser = PrepareParser()
-  args = parser.parse_args()
-
-  # Prepare environment
-  if args.expected_output is not None:
-    with open(args.expected_output, 'r') as f:
-      expected_output = f.read()
-  else:
-    expected_output = None
-  if args.device:
-    run_cmd = ['dalvikvm64'] if args.x64 else ['dalvikvm32']
-    test_env = DeviceTestEnv(args.classpath)
-  else:
-    run_cmd = ['dalvikvm64'] if args.x64 else ['dalvikvm32']
-    run_cmd += ['-XXlib:{0}'.format(args.lib)]
-    if not args.image:
-      image_path = '{0}/framework/core-optimizing-pic.art'.format(
-          GetEnvVariableOrError('ANDROID_HOST_OUT'))
-    else:
-      image_path = args.image
-    run_cmd += ['-Ximage:{0}'.format(image_path)]
-    if args.dalvikvm_opts:
-      run_cmd += args.dalvikvm_opts
-    test_env = HostTestEnv(args.classpath, args.x64)
-
-  # Perform the search
-  try:
-    testable = Dex2OatWrapperTestable(run_cmd, test_env, args.classname,
-                                      args.test_args, expected_output,
-                                      args.verbose)
-    (method, opt_pass) = BugSearch(testable)
-  except Exception as e:
-    print('Error. Refer to logfile: {0}'.format(test_env.logfile.name))
-    test_env.logfile.write('Exception: {0}\n'.format(e))
-    raise
-
-  # Report results
-  if method is None:
-    print('Couldn\'t find any bugs.')
-  elif opt_pass is None:
-    print('Faulty method: {0}. Fails with just mandatory passes.'.format(
-        method))
-  else:
-    print('Faulty method and pass: {0}, {1}.'.format(method, opt_pass))
-  print('Logfile: {0}'.format(test_env.logfile.name))
-  sys.exit(0)
-
-
-if __name__ == '__main__':
-  main()
diff --git a/tools/bisection_search/README.md b/tools/bisection_search/README.md
new file mode 100644
index 0000000..a7485c2
--- /dev/null
+++ b/tools/bisection_search/README.md
@@ -0,0 +1,43 @@
+Bisection Bug Search
+====================
+
+Bisection Bug Search is a tool for finding compiler optimizations bugs. It
+accepts a program which exposes a bug by producing incorrect output and expected
+output for the program. It then attempts to narrow down the issue to a single
+method and optimization pass under the assumption that interpreter is correct.
+
+Given methods in order M0..Mn finds smallest i such that compiling Mi and
+interpreting all other methods produces incorrect output. Then, given ordered
+optimization passes P0..Pl, finds smallest j such that compiling Mi with passes
+P0..Pj-1 produces expected output and compiling Mi with passes P0..Pj produces
+incorrect output. Prints Mi and Pj.
+
+How to run Bisection Bug Search
+===============================
+
+    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]
+
+    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
+
+    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
+
+    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
diff --git a/tools/bisection_search/__init__.py b/tools/bisection_search/__init__.py
new file mode 100644
index 0000000..0a42789
--- /dev/null
+++ b/tools/bisection_search/__init__.py
@@ -0,0 +1,17 @@
+#
+# 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.
+#
+
+# This file is intentionally left empty. It indicates that the directory is a Python package.
diff --git a/tools/bisection_search/bisection_search.py b/tools/bisection_search/bisection_search.py
new file mode 100755
index 0000000..110ef82
--- /dev/null
+++ b/tools/bisection_search/bisection_search.py
@@ -0,0 +1,396 @@
+#!/usr/bin/env python3.4
+#
+# 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.
+
+"""Performs bisection bug search on methods and optimizations.
+
+See README.md.
+
+Example usage:
+./bisection-search.py -cp classes.dex --expected-output output Test
+"""
+
+import abc
+import argparse
+import re
+import shlex
+from subprocess import call
+import sys
+from tempfile import NamedTemporaryFile
+
+from common import DeviceTestEnv
+from common import FatalError
+from common import GetEnvVariableOrError
+from common import HostTestEnv
+
+
+# Passes that are never disabled during search process because disabling them
+# would compromise correctness.
+MANDATORY_PASSES = ['dex_cache_array_fixups_arm',
+                    'dex_cache_array_fixups_mips',
+                    'instruction_simplifier$before_codegen',
+                    'pc_relative_fixups_x86',
+                    'pc_relative_fixups_mips',
+                    'x86_memory_operand_generation']
+
+# Passes that show up as optimizations in compiler verbose output but aren't
+# driven by run-passes mechanism. They are mandatory and will always run, we
+# never pass them to --run-passes.
+NON_PASSES = ['builder', 'prepare_for_register_allocation',
+              'liveness', 'register']
+
+
+class Dex2OatWrapperTestable(object):
+  """Class representing a testable compilation.
+
+  Accepts filters on compiled methods and optimization passes.
+  """
+
+  def __init__(self, base_cmd, test_env, output_checker=None, verbose=False):
+    """Constructor.
+
+    Args:
+      base_cmd: list of strings, base command to run.
+      test_env: ITestEnv.
+      output_checker: IOutputCheck, output checker.
+      verbose: bool, enable verbose output.
+    """
+    self._base_cmd = base_cmd
+    self._test_env = test_env
+    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
+
+  def Test(self, compiled_methods, passes_to_run=None):
+    """Tests compilation with compiled_methods and run_passes switches active.
+
+    If compiled_methods is None then compiles all methods.
+    If passes_to_run is None then runs default passes.
+
+    Args:
+      compiled_methods: list of strings representing methods to compile or None.
+      passes_to_run: list of strings representing passes to run or None.
+
+    Returns:
+      True if test passes with given settings. False otherwise.
+    """
+    if self._verbose:
+      print('Testing methods: {0} passes: {1}.'.format(
+          compiled_methods, passes_to_run))
+    cmd = self._PrepareCmd(compiled_methods=compiled_methods,
+                           passes_to_run=passes_to_run,
+                           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))
+    if self._verbose:
+      print('Test passed: {0}.'.format(res))
+    return res
+
+  def GetAllMethods(self):
+    """Get methods compiled during the test.
+
+    Returns:
+      List of strings representing methods compiled during the test.
+
+    Raises:
+      FatalError: An error occurred when retrieving methods list.
+    """
+    cmd = self._PrepareCmd(verbose_compiler=True)
+    (output, _) = self._test_env.RunCommand(cmd, {'ANDROID_LOG_TAGS': '*:i'})
+    match_methods = re.findall(r'Building ([^\n]+)\n', output)
+    if not match_methods:
+      raise FatalError('Failed to retrieve methods list. '
+                       'Not recognized output format.')
+    return match_methods
+
+  def GetAllPassesForMethod(self, compiled_method):
+    """Get all optimization passes ran for a method during the test.
+
+    Args:
+      compiled_method: string representing method to compile.
+
+    Returns:
+      List of strings representing passes ran for compiled_method during test.
+
+    Raises:
+      FatalError: An error occurred when retrieving passes list.
+    """
+    cmd = self._PrepareCmd(compiled_methods=[compiled_method],
+                           verbose_compiler=True)
+    (output, _) = self._test_env.RunCommand(cmd, {'ANDROID_LOG_TAGS': '*:i'})
+    match_passes = re.findall(r'Starting pass: ([^\n]+)\n', output)
+    if not match_passes:
+      raise FatalError('Failed to retrieve passes list. '
+                       'Not recognized output format.')
+    return [p for p in match_passes if p not in NON_PASSES]
+
+  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
+    if compiled_methods is not None:
+      self._test_env.WriteLines(self._compiled_methods_path, compiled_methods)
+      cmd += ['-Xcompiler-option', '--compiled-methods={0}'.format(
+          self._compiled_methods_path)]
+    if passes_to_run is not None:
+      self._test_env.WriteLines(self._passes_to_run_path, passes_to_run)
+      cmd += ['-Xcompiler-option', '--run-passes={0}'.format(
+          self._passes_to_run_path)]
+    if verbose_compiler:
+      cmd += ['-Xcompiler-option', '--runtime-arg', '-Xcompiler-option',
+              '-verbose:compiler', '-Xcompiler-option', '-j1']
+    cmd += self._base_cmd[1:]
+    return cmd
+
+
+class IOutputCheck(object):
+  """Abstract output checking class.
+
+  Checks if output is correct.
+  """
+  __meta_class__ = abc.ABCMeta
+
+  @abc.abstractmethod
+  def Check(self, output):
+    """Check if output is correct.
+
+    Args:
+      output: string, output to check.
+
+    Returns:
+      boolean, True if output is correct, False otherwise.
+    """
+
+
+class EqualsOutputCheck(IOutputCheck):
+  """Concrete output checking class checking for equality to expected output."""
+
+  def __init__(self, expected_output):
+    """Constructor.
+
+    Args:
+      expected_output: string, expected output.
+    """
+    self._expected_output = expected_output
+
+  def Check(self, output):
+    """See base class."""
+    return self._expected_output == output
+
+
+class ExternalScriptOutputCheck(IOutputCheck):
+  """Concrete output checking class calling an external script.
+
+  The script should accept two arguments, path to expected output and path to
+  program output. It should exit with 0 return code if outputs are equivalent
+  and with different return code otherwise.
+  """
+
+  def __init__(self, script_path, expected_output_path, logfile):
+    """Constructor.
+
+    Args:
+      script_path: string, path to checking script.
+      expected_output_path: string, path to file with expected output.
+      logfile: file handle, logfile.
+    """
+    self._script_path = script_path
+    self._expected_output_path = expected_output_path
+    self._logfile = logfile
+
+  def Check(self, output):
+    """See base class."""
+    ret_code = None
+    with NamedTemporaryFile(mode='w', delete=False) as temp_file:
+      temp_file.write(output)
+      temp_file.flush()
+      ret_code = call(
+          [self._script_path, self._expected_output_path, temp_file.name],
+          stdout=self._logfile, stderr=self._logfile, universal_newlines=True)
+    return ret_code == 0
+
+
+def BinarySearch(start, end, test):
+  """Binary search integers using test function to guide the process."""
+  while start < end:
+    mid = (start + end) // 2
+    if test(mid):
+      start = mid + 1
+    else:
+      end = mid
+  return start
+
+
+def FilterPasses(passes, cutoff_idx):
+  """Filters passes list according to cutoff_idx but keeps mandatory passes."""
+  return [opt_pass for idx, opt_pass in enumerate(passes)
+          if opt_pass in MANDATORY_PASSES or idx < cutoff_idx]
+
+
+def BugSearch(testable):
+  """Find buggy (method, optimization pass) pair for a given testable.
+
+  Args:
+    testable: Dex2OatWrapperTestable.
+
+  Returns:
+    (string, string) tuple. First element is name of method which when compiled
+    exposes test failure. Second element is name of optimization pass such that
+    for aforementioned method running all passes up to and excluding the pass
+    results in test passing but running all passes up to and including the pass
+    results in test failing.
+
+    (None, None) if test passes when compiling all methods.
+    (string, None) if a method is found which exposes the failure, but the
+      failure happens even when running just mandatory passes.
+
+  Raises:
+    FatalError: Testable fails with no methods compiled.
+    AssertionError: Method failed for all passes when bisecting methods, but
+    passed when bisecting passes. Possible sporadic failure.
+  """
+  all_methods = testable.GetAllMethods()
+  faulty_method_idx = BinarySearch(
+      0,
+      len(all_methods) + 1,
+      lambda mid: testable.Test(all_methods[0:mid]))
+  if faulty_method_idx == len(all_methods) + 1:
+    return (None, None)
+  if faulty_method_idx == 0:
+    raise FatalError('Testable fails with no methods compiled. '
+                     'Perhaps issue lies outside of compiler.')
+  faulty_method = all_methods[faulty_method_idx - 1]
+  all_passes = testable.GetAllPassesForMethod(faulty_method)
+  faulty_pass_idx = BinarySearch(
+      0,
+      len(all_passes) + 1,
+      lambda mid: testable.Test([faulty_method],
+                                FilterPasses(all_passes, mid)))
+  if faulty_pass_idx == 0:
+    return (faulty_method, None)
+  assert faulty_pass_idx != len(all_passes) + 1, ('Method must fail for some '
+                                                  'passes.')
+  faulty_pass = all_passes[faulty_pass_idx - 1]
+  return (faulty_method, faulty_pass)
+
+
+def PrepareParser():
+  """Prepares argument parser."""
+  parser = argparse.ArgumentParser(
+      description='Tool for finding compiler bugs. Either --raw-cmd or both '
+                  '-cp and --class are required.')
+  command_opts = parser.add_argument_group('dalvikvm command options')
+  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',
+                            help='lib to use, default: libart.so')
+  command_opts.add_argument('--dalvikvm-option', dest='dalvikvm_opts',
+                            metavar='OPT', nargs='*', default=[],
+                            help='additional dalvikvm option')
+  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,
+                            help='bisect with this command, ignore other '
+                                 'command options')
+  bisection_opts = parser.add_argument_group('bisection options')
+  bisection_opts.add_argument('--64', dest='x64', action='store_true',
+                              default=False, help='x64 mode')
+  bisection_opts.add_argument(
+      '--device', action='store_true', default=False, help='run on 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,
+      help='script comparing output and expected output')
+  bisection_opts.add_argument('--verbose', action='store_true',
+                              default=False, help='enable verbose output')
+  return parser
+
+
+def PrepareBaseCommand(args, classpath):
+  """Prepares base command used to run test."""
+  if args.raw_cmd:
+    return shlex.split(args.raw_cmd)
+  else:
+    base_cmd = ['dalvikvm64'] if args.x64 else ['dalvikvm32']
+    if not args.device:
+      base_cmd += ['-XXlib:{0}'.format(args.lib)]
+      if not args.image:
+        image_path = '{0}/framework/core-optimizing-pic.art'.format(
+            GetEnvVariableOrError('ANDROID_HOST_OUT'))
+      else:
+        image_path = args.image
+      base_cmd += ['-Ximage:{0}'.format(image_path)]
+    if args.dalvikvm_opts:
+      base_cmd += args.dalvikvm_opts
+    base_cmd += ['-cp', classpath, args.classname] + args.test_args
+  return base_cmd
+
+
+def main():
+  # Parse arguments
+  parser = PrepareParser()
+  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')
+
+  # Prepare environment
+  classpath = args.classpath
+  if args.device:
+    test_env = DeviceTestEnv()
+    if classpath:
+      classpath = test_env.PushClasspath(classpath)
+  else:
+    test_env = HostTestEnv(args.x64)
+  base_cmd = PrepareBaseCommand(args, classpath)
+  output_checker = None
+  if args.expected_output:
+    if args.check_script:
+      output_checker = ExternalScriptOutputCheck(
+          args.check_script, args.expected_output, test_env.logfile)
+    else:
+      with open(args.expected_output, 'r') as expected_output_file:
+        output_checker = EqualsOutputCheck(expected_output_file.read())
+
+  # Perform the search
+  try:
+    testable = Dex2OatWrapperTestable(base_cmd, test_env, output_checker,
+                                      args.verbose)
+    (method, opt_pass) = BugSearch(testable)
+  except Exception as e:
+    print('Error. Refer to logfile: {0}'.format(test_env.logfile.name))
+    test_env.logfile.write('Exception: {0}\n'.format(e))
+    raise
+
+  # Report results
+  if method is None:
+    print('Couldn\'t find any bugs.')
+  elif opt_pass is None:
+    print('Faulty method: {0}. Fails with just mandatory passes.'.format(
+        method))
+  else:
+    print('Faulty method and pass: {0}, {1}.'.format(method, opt_pass))
+  print('Logfile: {0}'.format(test_env.logfile.name))
+  sys.exit(0)
+
+
+if __name__ == '__main__':
+  main()
diff --git a/tools/bisection-search/bisection_test.py b/tools/bisection_search/bisection_test.py
similarity index 100%
rename from tools/bisection-search/bisection_test.py
rename to tools/bisection_search/bisection_test.py
diff --git a/tools/bisection-search/common.py b/tools/bisection_search/common.py
similarity index 80%
rename from tools/bisection-search/common.py
rename to tools/bisection_search/common.py
index 8361fc9..d5029bb 100755
--- a/tools/bisection-search/common.py
+++ b/tools/bisection_search/common.py
@@ -23,6 +23,7 @@
 from subprocess import check_call
 from subprocess import PIPE
 from subprocess import Popen
+from subprocess import STDOUT
 from subprocess import TimeoutExpired
 
 from tempfile import mkdtemp
@@ -81,19 +82,20 @@
   Returns:
    tuple (string, string, int) stdout output, stderr output, return code.
   """
-  proc = Popen(cmd, stderr=PIPE, stdout=PIPE, env=env, universal_newlines=True)
+  proc = Popen(cmd, stderr=STDOUT, stdout=PIPE, env=env,
+               universal_newlines=True)
   timeouted = False
   try:
-    (output, err_output) = proc.communicate(timeout=timeout)
+    (output, _) = proc.communicate(timeout=timeout)
   except TimeoutExpired:
     timeouted = True
     proc.kill()
-    (output, err_output) = proc.communicate()
-  logfile.write('Command:\n{0}\n{1}{2}\nReturn code: {3}\n'.format(
-      _CommandListToCommandString(cmd), err_output, output,
+    (output, _) = proc.communicate()
+  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, err_output, ret_code)
+  return (output, ret_code)
 
 
 def _CommandListToCommandString(cmd):
@@ -148,21 +150,18 @@
     """
 
   @abc.abstractmethod
-  def RunCommand(self, cmd):
-    """Runs command in environment.
+  def RunCommand(self, cmd, env_updates=None):
+    """Runs command in environment with updated environmental variables.
 
     Args:
-      cmd: string, command to run.
-
+      cmd: list of strings, command to run.
+      env_updates: dict, string to string, maps names of variables to their
+        updated values.
     Returns:
       tuple (string, string, int) stdout output, stderr output, return code.
     """
 
   @abc.abstractproperty
-  def classpath(self):
-    """Gets environment specific classpath with test class."""
-
-  @abc.abstractproperty
   def logfile(self):
     """Gets file handle to logfile residing on host."""
 
@@ -176,14 +175,12 @@
   For methods documentation see base class.
   """
 
-  def __init__(self, classpath, x64):
+  def __init__(self, x64):
     """Constructor.
 
     Args:
-      classpath: string, classpath with test class.
       x64: boolean, whether to setup in x64 mode.
     """
-    self._classpath = classpath
     self._env_path = mkdtemp(dir='/tmp/', prefix='bisection_search_')
     self._logfile = open('{0}/log'.format(self._env_path), 'w+')
     os.mkdir('{0}/dalvik-cache'.format(self._env_path))
@@ -197,6 +194,7 @@
     self._shell_env['ANDROID_DATA'] = self._env_path
     self._shell_env['ANDROID_ROOT'] = android_root
     self._shell_env['LD_LIBRARY_PATH'] = library_path
+    self._shell_env['DYLD_LIBRARY_PATH'] = library_path
     self._shell_env['PATH'] = (path + ':' + self._shell_env['PATH'])
     # Using dlopen requires load bias on the host.
     self._shell_env['LD_USE_LOAD_BIAS'] = '1'
@@ -213,13 +211,13 @@
       f.writelines('{0}\n'.format(line) for line in lines)
     return
 
-  def RunCommand(self, cmd):
+  def RunCommand(self, cmd, env_updates=None):
+    if not env_updates:
+      env_updates = {}
     self._EmptyDexCache()
-    return _RunCommandForOutputAndLog(cmd, self._shell_env, self._logfile)
-
-  @property
-  def classpath(self):
-    return self._classpath
+    env = self._shell_env.copy()
+    env.update(env_updates)
+    return _RunCommandForOutputAndLog(cmd, env, self._logfile)
 
   @property
   def logfile(self):
@@ -247,32 +245,18 @@
   For methods documentation see base class.
   """
 
-  def __init__(self, classpath):
-    """Constructor.
-
-    Args:
-      classpath: string, classpath with test 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+')
     self._device_env_path = '{0}/{1}'.format(
         DEVICE_TMP_PATH, os.path.basename(self._host_env_path))
-    self._classpath = os.path.join(
-        self._device_env_path, os.path.basename(classpath))
-    self._shell_env = os.environ
+    self._shell_env = os.environ.copy()
 
     self._AdbMkdir('{0}/dalvik-cache'.format(self._device_env_path))
     for arch_cache_path in _DexArchCachePaths(self._device_env_path):
       self._AdbMkdir(arch_cache_path)
 
-    paths = classpath.split(':')
-    device_paths = []
-    for path in paths:
-      device_paths.append('{0}/{1}'.format(
-          self._device_env_path, os.path.basename(path)))
-      self._AdbPush(path, self._device_env_path)
-    self._classpath = ':'.join(device_paths)
-
   def CreateFile(self, name=None):
     with NamedTemporaryFile(mode='w') as temp_file:
       self._AdbPush(temp_file.name, self._device_env_path)
@@ -283,25 +267,47 @@
   def WriteLines(self, file_path, lines):
     with NamedTemporaryFile(mode='w') as temp_file:
       temp_file.writelines('{0}\n'.format(line) for line in lines)
+      temp_file.flush()
       self._AdbPush(temp_file.name, file_path)
     return
 
-  def RunCommand(self, cmd):
+  def RunCommand(self, cmd, env_updates=None):
+    if not env_updates:
+      env_updates = {}
     self._EmptyDexCache()
+    if 'ANDROID_DATA' not in env_updates:
+      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 && ANDROID_DATA={0} {1} && '
-           'logcat -d dex2oat:* *:S 1>&2"').format(self._device_env_path, cmd)
-    return _RunCommandForOutputAndLog(shlex.split(cmd), self._shell_env,
-                                      self._logfile)
-
-  @property
-  def classpath(self):
-    return self._classpath
+    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)
 
   @property
   def logfile(self):
     return self._logfile
 
+  def PushClasspath(self, classpath):
+    """Push classpath to on-device test directory.
+
+    Classpath can contain multiple colon separated file paths, each file is
+    pushed. Returns analogous classpath with paths valid on device.
+
+    Args:
+      classpath: string, classpath in format 'a/b/c:d/e/f'.
+    Returns:
+      string, classpath valid on device.
+    """
+    paths = classpath.split(':')
+    device_paths = []
+    for path in paths:
+      device_paths.append('{0}/{1}'.format(
+          self._device_env_path, os.path.basename(path)))
+      self._AdbPush(path, self._device_env_path)
+    return ':'.join(device_paths)
+
   def _AdbPush(self, what, where):
     check_call(shlex.split('adb push "{0}" "{1}"'.format(what, where)),
                stdout=self._logfile, stderr=self._logfile)
diff --git a/tools/cpp-define-generator/Android.bp b/tools/cpp-define-generator/Android.bp
new file mode 100644
index 0000000..d792e90
--- /dev/null
+++ b/tools/cpp-define-generator/Android.bp
@@ -0,0 +1,36 @@
+//
+// 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 a "data" binary which will hold all the symbol values that will be parsed by the other scripts.
+//
+// Builds are for host only, target-specific define generation is possibly but is trickier and would need extra tooling.
+//
+// In the future we may wish to parameterize this on (32,64)x(read_barrier,no_read_barrier).
+
+art_cc_binary {
+    name: "cpp-define-generator-data",
+    host_supported: true,
+    device_supported: false,
+    defaults: [
+        "art_debug_defaults",
+        "art_defaults",
+    ],
+    include_dirs: ["art/runtime"],
+    srcs: ["main.cc"],
+    shared_libs: [
+        "libbase",
+    ],
+}
diff --git a/tools/cpp-define-generator/Android.mk b/tools/cpp-define-generator/Android.mk
deleted file mode 100644
index 6ba643c..0000000
--- a/tools/cpp-define-generator/Android.mk
+++ /dev/null
@@ -1,34 +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
-
-CPP_DEFINE_GENERATOR_SRC_FILES := \
-  main.cc
-
-CPP_DEFINE_GENERATOR_EXTRA_SHARED_LIBRARIES :=
-CPP_DEFINE_GENERATOR_EXTRA_INCLUDE :=
-CPP_DEFINE_GENERATOR_MULTILIB :=
-
-# Build a "data" binary which will hold all the symbol values that will be parsed by the other scripts.
-#
-# Builds are for host only, target-specific define generation is possibly but is trickier and would need extra tooling.
-#
-# In the future we may wish to parameterize this on (32,64)x(read_barrier,no_read_barrier).
-$(eval $(call build-art-executable,cpp-define-generator-data,$(CPP_DEFINE_GENERATOR_SRC_FILES),$(CPP_DEFINE_GENERATOR_EXTRA_SHARED_LIBRARIES),$(CPP_DEFINE_GENERATOR_EXTRA_INCLUDE),host,debug,$(CPP_DEFINE_GENERATOR_MULTILIB),shared))
-
diff --git a/tools/dmtracedump/Android.bp b/tools/dmtracedump/Android.bp
new file mode 100644
index 0000000..4f942bd
--- /dev/null
+++ b/tools/dmtracedump/Android.bp
@@ -0,0 +1,44 @@
+// Copyright (C) 2015 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.
+
+// Java method trace dump tool
+
+art_cc_binary {
+    name: "dmtracedump",
+    host_supported: true,
+    device_supported: false,
+    srcs: ["tracedump.cc"],
+    cflags: [
+        "-O0",
+        "-g",
+        "-Wall",
+    ],
+    target: {
+        windows: {
+            enabled: true,
+        },
+    },
+}
+
+art_cc_binary {
+    name: "create_test_dmtrace",
+    host_supported: true,
+    device_supported: false,
+    srcs: ["createtesttrace.cc"],
+    cflags: [
+        "-O0",
+        "-g",
+        "-Wall",
+    ],
+}
diff --git a/tools/dmtracedump/Android.mk b/tools/dmtracedump/Android.mk
deleted file mode 100644
index da0d632..0000000
--- a/tools/dmtracedump/Android.mk
+++ /dev/null
@@ -1,32 +0,0 @@
-# Copyright (C) 2015 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.
-
-# Java method trace dump tool
-
-LOCAL_PATH:= $(call my-dir)
-
-include $(CLEAR_VARS)
-LOCAL_CPP_EXTENSION := cc
-LOCAL_SRC_FILES := tracedump.cc
-LOCAL_CFLAGS += -O0 -g -Wall
-LOCAL_MODULE_HOST_OS := darwin linux windows
-LOCAL_MODULE := dmtracedump
-include $(BUILD_HOST_EXECUTABLE)
-
-include $(CLEAR_VARS)
-LOCAL_CPP_EXTENSION := cc
-LOCAL_SRC_FILES := createtesttrace.cc
-LOCAL_CFLAGS += -O0 -g -Wall
-LOCAL_MODULE := create_test_dmtrace
-include $(BUILD_HOST_EXECUTABLE)
diff --git a/tools/javafuzz/__init__.py b/tools/javafuzz/__init__.py
new file mode 100644
index 0000000..3955c71
--- /dev/null
+++ b/tools/javafuzz/__init__.py
@@ -0,0 +1,17 @@
+#
+# 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.
+#
+
+# This file is intentionally left empty. It indicates that the directory is a Python package.
\ No newline at end of file