Merge "Refactor ClassLinker::FindPrimitiveClass()."
diff --git a/compiler/optimizing/code_generator_arm64.cc b/compiler/optimizing/code_generator_arm64.cc
index a9acf90..48b50ea 100644
--- a/compiler/optimizing/code_generator_arm64.cc
+++ b/compiler/optimizing/code_generator_arm64.cc
@@ -2319,9 +2319,10 @@
       if (offset >= kReferenceLoadMinFarOffset) {
         locations->AddTemp(FixedTempLocation());
       }
-    } else {
+    } else if (!instruction->GetArray()->IsIntermediateAddress()) {
       // We need a non-scratch temporary for the array data pointer in
-      // CodeGeneratorARM64::GenerateArrayLoadWithBakerReadBarrier().
+      // CodeGeneratorARM64::GenerateArrayLoadWithBakerReadBarrier() for the case with no
+      // intermediate address.
       locations->AddTemp(Location::RequiresRegister());
     }
   }
@@ -2351,11 +2352,12 @@
   MacroAssembler* masm = GetVIXLAssembler();
   UseScratchRegisterScope temps(masm);
 
-  // The read barrier instrumentation of object ArrayGet instructions
+  // The non-Baker read barrier instrumentation of object ArrayGet instructions
   // does not support the HIntermediateAddress instruction.
   DCHECK(!((type == DataType::Type::kReference) &&
            instruction->GetArray()->IsIntermediateAddress() &&
-           kEmitCompilerReadBarrier));
+           kEmitCompilerReadBarrier &&
+           !kUseBakerReadBarrier));
 
   if (type == DataType::Type::kReference && kEmitCompilerReadBarrier && kUseBakerReadBarrier) {
     // Object ArrayGet with Baker's read barrier case.
@@ -2363,6 +2365,7 @@
     // CodeGeneratorARM64::GenerateArrayLoadWithBakerReadBarrier call.
     DCHECK(!instruction->CanDoImplicitNullCheckOn(instruction->InputAt(0)));
     if (index.IsConstant()) {
+      DCHECK(!instruction->GetArray()->IsIntermediateAddress());
       // Array load with a constant index can be treated as a field load.
       offset += Int64FromLocation(index) << DataType::SizeShift(type);
       Location maybe_temp =
@@ -2375,9 +2378,8 @@
                                                       /* needs_null_check */ false,
                                                       /* use_load_acquire */ false);
     } else {
-      Register temp = WRegisterFrom(locations->GetTemp(0));
       codegen_->GenerateArrayLoadWithBakerReadBarrier(
-          out, obj.W(), offset, index, temp, /* needs_null_check */ false);
+          instruction, out, obj.W(), offset, index, /* needs_null_check */ false);
     }
   } else {
     // General case.
@@ -2426,8 +2428,8 @@
         // input instruction has done it already. See the comment in
         // `TryExtractArrayAccessAddress()`.
         if (kIsDebugBuild) {
-          HIntermediateAddress* tmp = instruction->GetArray()->AsIntermediateAddress();
-          DCHECK_EQ(tmp->GetOffset()->AsIntConstant()->GetValueAsUint64(), offset);
+          HIntermediateAddress* interm_addr = instruction->GetArray()->AsIntermediateAddress();
+          DCHECK_EQ(interm_addr->GetOffset()->AsIntConstant()->GetValueAsUint64(), offset);
         }
         temp = obj;
       } else {
@@ -2539,8 +2541,8 @@
         // input instruction has done it already. See the comment in
         // `TryExtractArrayAccessAddress()`.
         if (kIsDebugBuild) {
-          HIntermediateAddress* tmp = instruction->GetArray()->AsIntermediateAddress();
-          DCHECK(tmp->GetOffset()->AsIntConstant()->GetValueAsUint64() == offset);
+          HIntermediateAddress* interm_addr = instruction->GetArray()->AsIntermediateAddress();
+          DCHECK(interm_addr->GetOffset()->AsIntConstant()->GetValueAsUint64() == offset);
         }
         temp = array;
       } else {
@@ -5957,11 +5959,11 @@
       instruction, ref, obj, src, needs_null_check, use_load_acquire);
 }
 
-void CodeGeneratorARM64::GenerateArrayLoadWithBakerReadBarrier(Location ref,
+void CodeGeneratorARM64::GenerateArrayLoadWithBakerReadBarrier(HArrayGet* instruction,
+                                                               Location ref,
                                                                Register obj,
                                                                uint32_t data_offset,
                                                                Location index,
-                                                               Register temp,
                                                                bool needs_null_check) {
   DCHECK(kEmitCompilerReadBarrier);
   DCHECK(kUseBakerReadBarrier);
@@ -6000,9 +6002,24 @@
   DCHECK(temps.IsAvailable(ip0));
   DCHECK(temps.IsAvailable(ip1));
   temps.Exclude(ip0, ip1);
+
+  Register temp;
+  if (instruction->GetArray()->IsIntermediateAddress()) {
+    // We do not need to compute the intermediate address from the array: the
+    // input instruction has done it already. See the comment in
+    // `TryExtractArrayAccessAddress()`.
+    if (kIsDebugBuild) {
+      HIntermediateAddress* interm_addr = instruction->GetArray()->AsIntermediateAddress();
+      DCHECK_EQ(interm_addr->GetOffset()->AsIntConstant()->GetValueAsUint64(), data_offset);
+    }
+    temp = obj;
+  } else {
+    temp = WRegisterFrom(instruction->GetLocations()->GetTemp(0));
+    __ Add(temp.X(), obj.X(), Operand(data_offset));
+  }
+
   uint32_t custom_data = EncodeBakerReadBarrierArrayData(temp.GetCode());
 
-  __ Add(temp.X(), obj.X(), Operand(data_offset));
   {
     ExactAssemblyScope guard(GetVIXLAssembler(),
                              (kPoisonHeapReferences ? 4u : 3u) * vixl::aarch64::kInstructionSize);
diff --git a/compiler/optimizing/code_generator_arm64.h b/compiler/optimizing/code_generator_arm64.h
index 1ba58b1..ada5742 100644
--- a/compiler/optimizing/code_generator_arm64.h
+++ b/compiler/optimizing/code_generator_arm64.h
@@ -694,11 +694,11 @@
                                              bool use_load_acquire);
   // Fast path implementation of ReadBarrier::Barrier for a heap
   // reference array load when Baker's read barriers are used.
-  void GenerateArrayLoadWithBakerReadBarrier(Location ref,
+  void GenerateArrayLoadWithBakerReadBarrier(HArrayGet* instruction,
+                                             Location ref,
                                              vixl::aarch64::Register obj,
                                              uint32_t data_offset,
                                              Location index,
-                                             vixl::aarch64::Register temp,
                                              bool needs_null_check);
 
   // Emit code checking the status of the Marking Register, and
diff --git a/compiler/optimizing/instruction_simplifier_arm.cc b/compiler/optimizing/instruction_simplifier_arm.cc
index 24fbb6c..f968c19 100644
--- a/compiler/optimizing/instruction_simplifier_arm.cc
+++ b/compiler/optimizing/instruction_simplifier_arm.cc
@@ -202,6 +202,11 @@
     return;
   }
 
+  // TODO: Support intermediate address for object arrays on arm.
+  if (type == DataType::Type::kReference) {
+    return;
+  }
+
   if (type == DataType::Type::kInt64
       || type == DataType::Type::kFloat32
       || type == DataType::Type::kFloat64) {
diff --git a/compiler/optimizing/instruction_simplifier_shared.cc b/compiler/optimizing/instruction_simplifier_shared.cc
index ccdcb35..0f30f66 100644
--- a/compiler/optimizing/instruction_simplifier_shared.cc
+++ b/compiler/optimizing/instruction_simplifier_shared.cc
@@ -245,11 +245,11 @@
     return false;
   }
   if (kEmitCompilerReadBarrier &&
+      !kUseBakerReadBarrier &&
       access->IsArrayGet() &&
       access->GetType() == DataType::Type::kReference) {
-    // For object arrays, the read barrier instrumentation requires
+    // For object arrays, the non-Baker read barrier instrumentation requires
     // the original array pointer.
-    // TODO: This can be relaxed for Baker CC.
     return false;
   }
 
diff --git a/compiler/optimizing/intrinsics_arm64.cc b/compiler/optimizing/intrinsics_arm64.cc
index 7684dc7..6d04b0e 100644
--- a/compiler/optimizing/intrinsics_arm64.cc
+++ b/compiler/optimizing/intrinsics_arm64.cc
@@ -2916,6 +2916,40 @@
 
 void IntrinsicCodeGeneratorARM64::VisitReachabilityFence(HInvoke* invoke ATTRIBUTE_UNUSED) { }
 
+void IntrinsicLocationsBuilderARM64::VisitCRC32Update(HInvoke* invoke) {
+  if (!codegen_->GetInstructionSetFeatures().HasCRC()) {
+    return;
+  }
+
+  LocationSummary* locations = new (allocator_) LocationSummary(invoke,
+                                                                LocationSummary::kNoCall,
+                                                                kIntrinsified);
+
+  locations->SetInAt(0, Location::RequiresRegister());
+  locations->SetInAt(1, Location::RequiresRegister());
+  locations->SetOut(Location::RequiresRegister());
+}
+
+// Lower the invoke of CRC32.update(int crc, int b).
+void IntrinsicCodeGeneratorARM64::VisitCRC32Update(HInvoke* invoke) {
+  DCHECK(codegen_->GetInstructionSetFeatures().HasCRC());
+
+  MacroAssembler* masm = GetVIXLAssembler();
+
+  Register crc = InputRegisterAt(invoke, 0);
+  Register val = InputRegisterAt(invoke, 1);
+  Register out = OutputRegister(invoke);
+
+  // The general algorithm of the CRC32 calculation is:
+  //   crc = ~crc
+  //   result = crc32_for_byte(crc, b)
+  //   crc = ~result
+  // It is directly lowered to three instructions.
+  __ Mvn(out, crc);
+  __ Crc32b(out, out, val);
+  __ Mvn(out, out);
+}
+
 UNIMPLEMENTED_INTRINSIC(ARM64, ReferenceGetReferent)
 
 UNIMPLEMENTED_INTRINSIC(ARM64, StringStringIndexOf);
diff --git a/compiler/optimizing/intrinsics_arm_vixl.cc b/compiler/optimizing/intrinsics_arm_vixl.cc
index 38e4c89..0c463a2 100644
--- a/compiler/optimizing/intrinsics_arm_vixl.cc
+++ b/compiler/optimizing/intrinsics_arm_vixl.cc
@@ -3059,6 +3059,7 @@
 UNIMPLEMENTED_INTRINSIC(ARMVIXL, UnsafeCASLong)     // High register pressure.
 UNIMPLEMENTED_INTRINSIC(ARMVIXL, SystemArrayCopyChar)
 UNIMPLEMENTED_INTRINSIC(ARMVIXL, ReferenceGetReferent)
+UNIMPLEMENTED_INTRINSIC(ARMVIXL, CRC32Update)
 
 UNIMPLEMENTED_INTRINSIC(ARMVIXL, StringStringIndexOf);
 UNIMPLEMENTED_INTRINSIC(ARMVIXL, StringStringIndexOfAfter);
diff --git a/compiler/optimizing/intrinsics_mips.cc b/compiler/optimizing/intrinsics_mips.cc
index 6f7f5e4..21fb7d7 100644
--- a/compiler/optimizing/intrinsics_mips.cc
+++ b/compiler/optimizing/intrinsics_mips.cc
@@ -2696,6 +2696,8 @@
 UNIMPLEMENTED_INTRINSIC(MIPS, ReferenceGetReferent)
 UNIMPLEMENTED_INTRINSIC(MIPS, SystemArrayCopy)
 
+UNIMPLEMENTED_INTRINSIC(MIPS, CRC32Update)
+
 UNIMPLEMENTED_INTRINSIC(MIPS, StringStringIndexOf);
 UNIMPLEMENTED_INTRINSIC(MIPS, StringStringIndexOfAfter);
 UNIMPLEMENTED_INTRINSIC(MIPS, StringBufferAppend);
diff --git a/compiler/optimizing/intrinsics_mips64.cc b/compiler/optimizing/intrinsics_mips64.cc
index 2eb2529..4b86f5d 100644
--- a/compiler/optimizing/intrinsics_mips64.cc
+++ b/compiler/optimizing/intrinsics_mips64.cc
@@ -2346,6 +2346,7 @@
 
 UNIMPLEMENTED_INTRINSIC(MIPS64, ReferenceGetReferent)
 UNIMPLEMENTED_INTRINSIC(MIPS64, SystemArrayCopy)
+UNIMPLEMENTED_INTRINSIC(MIPS64, CRC32Update)
 
 UNIMPLEMENTED_INTRINSIC(MIPS64, StringStringIndexOf);
 UNIMPLEMENTED_INTRINSIC(MIPS64, StringStringIndexOfAfter);
diff --git a/compiler/optimizing/intrinsics_x86.cc b/compiler/optimizing/intrinsics_x86.cc
index 3504d7a..6dd4681 100644
--- a/compiler/optimizing/intrinsics_x86.cc
+++ b/compiler/optimizing/intrinsics_x86.cc
@@ -2967,6 +2967,7 @@
 UNIMPLEMENTED_INTRINSIC(X86, LongHighestOneBit)
 UNIMPLEMENTED_INTRINSIC(X86, IntegerLowestOneBit)
 UNIMPLEMENTED_INTRINSIC(X86, LongLowestOneBit)
+UNIMPLEMENTED_INTRINSIC(X86, CRC32Update)
 
 UNIMPLEMENTED_INTRINSIC(X86, StringStringIndexOf);
 UNIMPLEMENTED_INTRINSIC(X86, StringStringIndexOfAfter);
diff --git a/compiler/optimizing/intrinsics_x86_64.cc b/compiler/optimizing/intrinsics_x86_64.cc
index 96f6eaa..7db26dc 100644
--- a/compiler/optimizing/intrinsics_x86_64.cc
+++ b/compiler/optimizing/intrinsics_x86_64.cc
@@ -2732,6 +2732,7 @@
 UNIMPLEMENTED_INTRINSIC(X86_64, ReferenceGetReferent)
 UNIMPLEMENTED_INTRINSIC(X86_64, FloatIsInfinite)
 UNIMPLEMENTED_INTRINSIC(X86_64, DoubleIsInfinite)
+UNIMPLEMENTED_INTRINSIC(X86_64, CRC32Update)
 
 UNIMPLEMENTED_INTRINSIC(X86_64, StringStringIndexOf);
 UNIMPLEMENTED_INTRINSIC(X86_64, StringStringIndexOfAfter);
diff --git a/compiler/utils/assembler_thumb_test.cc b/compiler/utils/assembler_thumb_test.cc
index 053e202..3d26296 100644
--- a/compiler/utils/assembler_thumb_test.cc
+++ b/compiler/utils/assembler_thumb_test.cc
@@ -125,7 +125,7 @@
   // Assemble the .S
   snprintf(cmd, sizeof(cmd), "%sas %s -o %s.o", toolsdir.c_str(), filename, filename);
   int cmd_result = system(cmd);
-  ASSERT_EQ(cmd_result, 0) << strerror(errno);
+  ASSERT_EQ(cmd_result, 0) << cmd << strerror(errno);
 
   // Disassemble.
   snprintf(cmd, sizeof(cmd), "%sobjdump -D -M force-thumb --section=.text %s.o  | grep '^  *[0-9a-f][0-9a-f]*:'",
diff --git a/dex2oat/dex2oat_test.cc b/dex2oat/dex2oat_test.cc
index d22b301..baeebd9 100644
--- a/dex2oat/dex2oat_test.cc
+++ b/dex2oat/dex2oat_test.cc
@@ -23,6 +23,7 @@
 #include <unistd.h>
 
 #include <android-base/logging.h>
+#include <android-base/macros.h>
 #include <android-base/stringprintf.h>
 
 #include "common_runtime_test.h"
@@ -90,6 +91,10 @@
     args.push_back("--runtime-arg");
     args.push_back("-Xnorelocate");
 
+    // Unless otherwise stated, use a small amount of threads, so that potential aborts are
+    // shorter. This can be overridden with extra_args.
+    args.push_back("-j4");
+
     args.insert(args.end(), extra_args.begin(), extra_args.end());
 
     int status = Dex2Oat(args, error_msg);
@@ -99,33 +104,33 @@
     return status;
   }
 
-  void GenerateOdexForTest(
+  ::testing::AssertionResult GenerateOdexForTest(
       const std::string& dex_location,
       const std::string& odex_location,
       CompilerFilter::Filter filter,
       const std::vector<std::string>& extra_args = {},
       bool expect_success = true,
-      bool use_fd = false) {
-    GenerateOdexForTest(dex_location,
-                        odex_location,
-                        filter,
-                        extra_args,
-                        expect_success,
-                        use_fd,
-                        [](const OatFile&) {});
+      bool use_fd = false) WARN_UNUSED {
+    return GenerateOdexForTest(dex_location,
+                               odex_location,
+                               filter,
+                               extra_args,
+                               expect_success,
+                               use_fd,
+                               [](const OatFile&) {});
   }
 
   bool test_accepts_odex_file_on_failure = false;
 
   template <typename T>
-  void GenerateOdexForTest(
+  ::testing::AssertionResult GenerateOdexForTest(
       const std::string& dex_location,
       const std::string& odex_location,
       CompilerFilter::Filter filter,
       const std::vector<std::string>& extra_args,
       bool expect_success,
       bool use_fd,
-      T check_oat) {
+      T check_oat) WARN_UNUSED {
     std::string error_msg;
     int status = GenerateOdexForTestWithStatus({dex_location},
                                                odex_location,
@@ -135,7 +140,10 @@
                                                use_fd);
     bool success = (WIFEXITED(status) && WEXITSTATUS(status) == 0);
     if (expect_success) {
-      ASSERT_TRUE(success) << error_msg << std::endl << output_;
+      if (!success) {
+        return ::testing::AssertionFailure()
+            << "Failed to compile odex: " << error_msg << std::endl << output_;
+      }
 
       // Verify the odex file was generated as expected.
       std::unique_ptr<OatFile> odex_file(OatFile::Open(/*zip_fd=*/ -1,
@@ -146,12 +154,16 @@
                                                        dex_location.c_str(),
                                                        /*reservation=*/ nullptr,
                                                        &error_msg));
-      ASSERT_TRUE(odex_file.get() != nullptr) << error_msg;
+      if (odex_file == nullptr) {
+        return ::testing::AssertionFailure() << "Could not open odex file: " << error_msg;
+      }
 
       CheckFilter(filter, odex_file->GetCompilerFilter());
       check_oat(*(odex_file.get()));
     } else {
-      ASSERT_FALSE(success) << output_;
+      if (success) {
+        return ::testing::AssertionFailure() << "Succeeded to compile odex: " << output_;
+      }
 
       error_msg_ = error_msg;
 
@@ -165,9 +177,12 @@
                                                          dex_location.c_str(),
                                                          /*reservation=*/ nullptr,
                                                          &error_msg));
-        ASSERT_TRUE(odex_file.get() == nullptr);
+        if (odex_file != nullptr) {
+          return ::testing::AssertionFailure() << "Could open odex file: " << error_msg;
+        }
       }
     }
+    return ::testing::AssertionSuccess();
   }
 
   // Check the input compiler filter against the generated oat file's filter. May be overridden
@@ -265,7 +280,7 @@
       std::string swap_location = GetOdexDir() + "/Dex2OatSwapTest.odex.swap";
       copy.push_back("--swap-file=" + swap_location);
     }
-    GenerateOdexForTest(dex_location, odex_location, CompilerFilter::kSpeed, copy);
+    ASSERT_TRUE(GenerateOdexForTest(dex_location, odex_location, CompilerFilter::kSpeed, copy));
 
     CheckValidity();
     ASSERT_TRUE(success_);
@@ -490,7 +505,7 @@
 
     std::vector<std::string> new_args(extra_args);
     new_args.push_back("--app-image-file=" + app_image_file);
-    GenerateOdexForTest(dex_location, odex_location, filter, new_args);
+    ASSERT_TRUE(GenerateOdexForTest(dex_location, odex_location, filter, new_args));
 
     CheckValidity();
     ASSERT_TRUE(success_);
@@ -681,12 +696,12 @@
         copy.push_back("--app-image-file=" + app_image_file_name);
       }
     }
-    GenerateOdexForTest(dex_location,
-                        odex_location,
-                        CompilerFilter::kSpeedProfile,
-                        copy,
-                        expect_success,
-                        use_fd);
+    ASSERT_TRUE(GenerateOdexForTest(dex_location,
+                                    odex_location,
+                                    CompilerFilter::kSpeedProfile,
+                                    copy,
+                                    expect_success,
+                                    use_fd));
     if (app_image_file != nullptr) {
       ASSERT_EQ(app_image_file->FlushCloseOrErase(), 0) << "Could not flush and close art file";
     }
@@ -877,24 +892,24 @@
     {
       std::string input_vdex = "--input-vdex-fd=-1";
       std::string output_vdex = StringPrintf("--output-vdex-fd=%d", vdex_file1->Fd());
-      GenerateOdexForTest(dex_location,
-                          odex_location,
-                          CompilerFilter::kQuicken,
-                          { input_vdex, output_vdex },
-                          /*expect_success=*/ true,
-                          /*use_fd=*/ true);
+      ASSERT_TRUE(GenerateOdexForTest(dex_location,
+                                      odex_location,
+                                      CompilerFilter::kQuicken,
+                                      { input_vdex, output_vdex },
+                                      /* expect_success= */ true,
+                                      /* use_fd= */ true));
       EXPECT_GT(vdex_file1->GetLength(), 0u);
     }
     // Unquicken by running the verify compiler filter on the vdex file.
     {
       std::string input_vdex = StringPrintf("--input-vdex-fd=%d", vdex_file1->Fd());
       std::string output_vdex = StringPrintf("--output-vdex-fd=%d", vdex_file1->Fd());
-      GenerateOdexForTest(dex_location,
-                          odex_location,
-                          CompilerFilter::kVerify,
-                          { input_vdex, output_vdex, kDisableCompactDex },
-                          /*expect_success=*/ true,
-                          /*use_fd=*/ true);
+      ASSERT_TRUE(GenerateOdexForTest(dex_location,
+                                      odex_location,
+                                      CompilerFilter::kVerify,
+                                      { input_vdex, output_vdex, kDisableCompactDex },
+                                      /* expect_success= */ true,
+                                      /* use_fd= */ true));
     }
     ASSERT_EQ(vdex_file1->FlushCloseOrErase(), 0) << "Could not flush and close vdex file";
     CheckResult(dex_location, odex_location);
@@ -918,12 +933,12 @@
     {
       std::string input_vdex = "--input-vdex-fd=-1";
       std::string output_vdex = StringPrintf("--output-vdex-fd=%d", vdex_file1->Fd());
-      GenerateOdexForTest(dex_location,
-                          odex_location,
-                          CompilerFilter::kQuicken,
-                          { input_vdex, output_vdex, "--compact-dex-level=fast"},
-                          /*expect_success=*/ true,
-                          /*use_fd=*/ true);
+      ASSERT_TRUE(GenerateOdexForTest(dex_location,
+                                      odex_location,
+                                      CompilerFilter::kQuicken,
+                                      { input_vdex, output_vdex, "--compact-dex-level=fast"},
+                                      /* expect_success= */ true,
+                                      /* use_fd= */ true));
       EXPECT_GT(vdex_file1->GetLength(), 0u);
     }
 
@@ -931,12 +946,12 @@
     {
       std::string input_vdex = StringPrintf("--input-vdex-fd=%d", vdex_file1->Fd());
       std::string output_vdex = StringPrintf("--output-vdex-fd=%d", vdex_file2->Fd());
-      GenerateOdexForTest(dex_location,
-                          odex_location2,
-                          CompilerFilter::kVerify,
-                          { input_vdex, output_vdex, "--compact-dex-level=none"},
-                          /*expect_success=*/ true,
-                          /*use_fd=*/ true);
+      ASSERT_TRUE(GenerateOdexForTest(dex_location,
+                                      odex_location2,
+                                      CompilerFilter::kVerify,
+                                      { input_vdex, output_vdex, "--compact-dex-level=none"},
+                                      /* expect_success= */ true,
+                                      /* use_fd= */ true));
     }
     ASSERT_EQ(vdex_file1->FlushCloseOrErase(), 0) << "Could not flush and close vdex file";
     ASSERT_EQ(vdex_file2->FlushCloseOrErase(), 0) << "Could not flush and close vdex file";
@@ -992,11 +1007,11 @@
     std::string swap_location = GetOdexDir() + "/Dex2OatSwapTest.odex.swap";
     copy.push_back("--swap-file=" + swap_location);
     copy.push_back("-j512");  // Excessive idle threads just slow down dex2oat.
-    GenerateOdexForTest(dex_location,
-                        odex_location,
-                        CompilerFilter::kSpeed,
-                        copy,
-                        expect_success);
+    ASSERT_TRUE(GenerateOdexForTest(dex_location,
+                                    odex_location,
+                                    CompilerFilter::kSpeed,
+                                    copy,
+                                    expect_success));
   }
 
   std::string GetTestDexFileName() {
@@ -1072,13 +1087,13 @@
       ASSERT_STREQ(expected_classpath_key, classpath);
     };
 
-    GenerateOdexForTest(dex_location,
-                        odex_location,
-                        CompilerFilter::kQuicken,
-                        extra_args,
-                        expected_success,
-                        /*use_fd*/ false,
-                        check_oat);
+    ASSERT_TRUE(GenerateOdexForTest(dex_location,
+                                    odex_location,
+                                    CompilerFilter::kQuicken,
+                                    extra_args,
+                                    expected_success,
+                                    /*use_fd*/ false,
+                                    check_oat));
   }
 
   std::string GetUsedDexLocation() {
@@ -1135,11 +1150,11 @@
 
   Copy(GetDexSrc1(), stripped_classpath);
 
-  GenerateOdexForTest(stripped_classpath,
-                      odex_for_classpath,
-                      CompilerFilter::kQuicken,
-                      {},
-                      true);
+  ASSERT_TRUE(GenerateOdexForTest(stripped_classpath,
+                                  odex_for_classpath,
+                                  CompilerFilter::kQuicken,
+                                  {},
+                                  true));
 
   // Strip the dex file
   Copy(GetStrippedDexSrc1(), stripped_classpath);
@@ -1216,7 +1231,7 @@
       CompilerFilter::Filter::kQuicken,
       &error_msg,
       {"--force-determinism", "--avoid-storing-invocation"});
-  EXPECT_EQ(res, 0);
+  ASSERT_EQ(res, 0);
   Copy(base_oat_name, unload_oat_name);
   Copy(base_vdex_name, unload_vdex_name);
   std::unique_ptr<File> unload_oat(OS::OpenFileForReading(unload_oat_name.c_str()));
@@ -1233,7 +1248,7 @@
       CompilerFilter::Filter::kQuicken,
       &error_msg,
       {"--force-determinism", "--avoid-storing-invocation", "--app-image-file=" + app_image_name});
-  EXPECT_EQ(res2, 0);
+  ASSERT_EQ(res2, 0);
   Copy(base_oat_name, no_unload_oat_name);
   Copy(base_vdex_name, no_unload_vdex_name);
   std::unique_ptr<File> no_unload_oat(OS::OpenFileForReading(no_unload_oat_name.c_str()));
@@ -1535,26 +1550,26 @@
   std::string out_dir = GetScratchDir();
   const std::string base_oat_name = out_dir + "/base.oat";
   size_t no_dedupe_size = 0;
-  GenerateOdexForTest(dex->GetLocation(),
-                      base_oat_name,
-                      CompilerFilter::Filter::kSpeed,
-                      { "--deduplicate-code=false" },
-                      true,  // expect_success
-                      false,  // use_fd
-                      [&no_dedupe_size](const OatFile& o) {
-                        no_dedupe_size = o.Size();
-                      });
+  ASSERT_TRUE(GenerateOdexForTest(dex->GetLocation(),
+                                  base_oat_name,
+                                  CompilerFilter::Filter::kSpeed,
+                                  { "--deduplicate-code=false" },
+                                  true,  // expect_success
+                                  false,  // use_fd
+                                  [&no_dedupe_size](const OatFile& o) {
+                                    no_dedupe_size = o.Size();
+                                  }));
 
   size_t dedupe_size = 0;
-  GenerateOdexForTest(dex->GetLocation(),
-                      base_oat_name,
-                      CompilerFilter::Filter::kSpeed,
-                      { "--deduplicate-code=true" },
-                      true,  // expect_success
-                      false,  // use_fd
-                      [&dedupe_size](const OatFile& o) {
-                        dedupe_size = o.Size();
-                      });
+  ASSERT_TRUE(GenerateOdexForTest(dex->GetLocation(),
+                                  base_oat_name,
+                                  CompilerFilter::Filter::kSpeed,
+                                  { "--deduplicate-code=true" },
+                                  true,  // expect_success
+                                  false,  // use_fd
+                                  [&dedupe_size](const OatFile& o) {
+                                    dedupe_size = o.Size();
+                                  }));
 
   EXPECT_LT(dedupe_size, no_dedupe_size);
 }
@@ -1563,15 +1578,15 @@
   std::unique_ptr<const DexFile> dex(OpenTestDexFile("MainUncompressed"));
   std::string out_dir = GetScratchDir();
   const std::string base_oat_name = out_dir + "/base.oat";
-  GenerateOdexForTest(dex->GetLocation(),
-                      base_oat_name,
-                      CompilerFilter::Filter::kQuicken,
-                      { },
-                      true,  // expect_success
-                      false,  // use_fd
-                      [](const OatFile& o) {
-                        CHECK(!o.ContainsDexCode());
-                      });
+  ASSERT_TRUE(GenerateOdexForTest(dex->GetLocation(),
+                                  base_oat_name,
+                                  CompilerFilter::Filter::kQuicken,
+                                  { },
+                                  true,  // expect_success
+                                  false,  // use_fd
+                                  [](const OatFile& o) {
+                                    CHECK(!o.ContainsDexCode());
+                                  }));
 }
 
 TEST_F(Dex2oatTest, EmptyUncompressedDexTest) {
@@ -1667,15 +1682,15 @@
   std::string out_dir = GetScratchDir();
   const std::string oat_filename = out_dir + "/base.oat";
   // The dex won't pass the method verifier, only use the verify filter.
-  GenerateOdexForTest(temp_dex.GetFilename(),
-                      oat_filename,
-                      CompilerFilter::Filter::kVerify,
-                      { },
-                      true,  // expect_success
-                      false,  // use_fd
-                      [](const OatFile& o) {
-                        CHECK(o.ContainsDexCode());
-                      });
+  ASSERT_TRUE(GenerateOdexForTest(temp_dex.GetFilename(),
+                                  oat_filename,
+                                  CompilerFilter::Filter::kVerify,
+                                  { },
+                                  true,  // expect_success
+                                  false,  // use_fd
+                                  [](const OatFile& o) {
+                                    CHECK(o.ContainsDexCode());
+                                  }));
   // Open our generated oat file.
   std::string error_msg;
   std::unique_ptr<OatFile> odex_file(OatFile::Open(/*zip_fd=*/ -1,
@@ -1718,11 +1733,11 @@
   }
   const std::string& dex_location = apk_file.GetFilename();
   const std::string odex_location = GetOdexDir() + "/output.odex";
-  GenerateOdexForTest(dex_location,
-                      odex_location,
-                      CompilerFilter::kQuicken,
-                      { "--compact-dex-level=fast" },
-                      true);
+  ASSERT_TRUE(GenerateOdexForTest(dex_location,
+                                  odex_location,
+                                  CompilerFilter::kQuicken,
+                                  { "--compact-dex-level=fast" },
+                                  true));
 }
 
 TEST_F(Dex2oatTest, StderrLoggerOutput) {
@@ -1732,11 +1747,11 @@
   // Test file doesn't matter.
   Copy(GetDexSrc1(), dex_location);
 
-  GenerateOdexForTest(dex_location,
-                      odex_location,
-                      CompilerFilter::kQuicken,
-                      { "--runtime-arg", "-Xuse-stderr-logger" },
-                      true);
+  ASSERT_TRUE(GenerateOdexForTest(dex_location,
+                                  odex_location,
+                                  CompilerFilter::kQuicken,
+                                  { "--runtime-arg", "-Xuse-stderr-logger" },
+                                  true));
   // Look for some random part of dex2oat logging. With the stderr logger this should be captured,
   // even on device.
   EXPECT_NE(std::string::npos, output_.find("dex2oat took"));
@@ -1749,11 +1764,11 @@
   // Test file doesn't matter.
   Copy(GetDexSrc1(), dex_location);
 
-  GenerateOdexForTest(dex_location,
-                      odex_location,
-                      CompilerFilter::kVerify,
-                      { "--compilation-reason=install" },
-                      true);
+  ASSERT_TRUE(GenerateOdexForTest(dex_location,
+                                  odex_location,
+                                  CompilerFilter::kVerify,
+                                  { "--compilation-reason=install" },
+                                  true));
   std::string error_msg;
   std::unique_ptr<OatFile> odex_file(OatFile::Open(/*zip_fd=*/ -1,
                                                    odex_location.c_str(),
@@ -1774,11 +1789,11 @@
   // Test file doesn't matter.
   Copy(GetDexSrc1(), dex_location);
 
-  GenerateOdexForTest(dex_location,
-                      odex_location,
-                      CompilerFilter::kVerify,
-                      {},
-                      true);
+  ASSERT_TRUE(GenerateOdexForTest(dex_location,
+                                  odex_location,
+                                  CompilerFilter::kVerify,
+                                  {},
+                                  true));
   std::string error_msg;
   std::unique_ptr<OatFile> odex_file(OatFile::Open(/*zip_fd=*/ -1,
                                                    odex_location.c_str(),
@@ -1799,14 +1814,13 @@
   const std::string dex_location = dex->GetLocation();
   const std::string odex_location = out_dir + "/base.oat";
   const std::string vdex_location = out_dir + "/base.vdex";
-  GenerateOdexForTest(dex_location,
-                      odex_location,
-                      CompilerFilter::Filter::kVerify,
-                      { "--copy-dex-files=false" },
-                      true,  // expect_success
-                      false,  // use_fd
-                      [](const OatFile&) {
-                      });
+  ASSERT_TRUE(GenerateOdexForTest(dex_location,
+                                  odex_location,
+                                  CompilerFilter::Filter::kVerify,
+                                  { "--copy-dex-files=false" },
+                                  true,  // expect_success
+                                  false,  // use_fd
+                                  [](const OatFile&) {}));
   {
     // Check the vdex doesn't have dex.
     std::unique_ptr<VdexFile> vdex(VdexFile::Open(vdex_location.c_str(),
@@ -1856,19 +1870,21 @@
   }
 
   auto generate_and_check = [&](CompilerFilter::Filter filter) {
-    GenerateOdexForTest(dex_location,
-                        odex_location,
-                        filter,
-                        { "--dump-timings",
-                          "--dm-file=" + dm_file.GetFilename(),
-                          // Pass -Xuse-stderr-logger have dex2oat output in output_ on target.
-                          "--runtime-arg",
-                          "-Xuse-stderr-logger" },
-                        true,  // expect_success
-                        false,  // use_fd
-                        [](const OatFile& o) {
-                          CHECK(o.ContainsDexCode());
-                        });
+    output_.clear();
+    ASSERT_TRUE(GenerateOdexForTest(dex_location,
+                                    odex_location,
+                                    filter,
+                                    { "--dump-timings",
+                                      "--dm-file=" + dm_file.GetFilename(),
+                                      // Pass -Xuse-stderr-logger have dex2oat output in output_ on
+                                      // target.
+                                      "--runtime-arg",
+                                      "-Xuse-stderr-logger" },
+                                    true,  // expect_success
+                                    false,  // use_fd
+                                    [](const OatFile& o) {
+                                      CHECK(o.ContainsDexCode());
+                                    }));
     // Check the output for "Fast verify", this is printed from --dump-timings.
     std::istringstream iss(output_);
     std::string line;
@@ -1916,14 +1932,14 @@
   {
     std::string input_vdex = "--input-vdex-fd=-1";
     std::string output_vdex = StringPrintf("--output-vdex-fd=%d", vdex_output->Fd());
-    GenerateOdexForTest(dex_location,
-                        odex_location,
-                        CompilerFilter::kQuicken,
-                        // Disable cdex since we want to compare against the original dex file
-                        // after unquickening.
-                        { input_vdex, output_vdex, kDisableCompactDex },
-                        /*expect_success=*/ true,
-                        /*use_fd=*/ true);
+    ASSERT_TRUE(GenerateOdexForTest(dex_location,
+                                    odex_location,
+                                    CompilerFilter::kQuicken,
+                                    // Disable cdex since we want to compare against the original
+                                    // dex file after unquickening.
+                                    { input_vdex, output_vdex, kDisableCompactDex },
+                                    /* expect_success= */ true,
+                                    /* use_fd= */ true));
   }
   // Unquicken by running the verify compiler filter on the vdex file and verify it matches.
   std::string odex_location2 = GetOdexDir() + "/unquickened.odex";
@@ -1932,13 +1948,14 @@
   {
     std::string input_vdex = StringPrintf("--input-vdex-fd=%d", vdex_output->Fd());
     std::string output_vdex = StringPrintf("--output-vdex-fd=%d", vdex_unquickened->Fd());
-    GenerateOdexForTest(dex_location,
-                        odex_location2,
-                        CompilerFilter::kVerify,
-                        // Disable cdex to avoid needing to write out the shared section.
-                        { input_vdex, output_vdex, kDisableCompactDex },
-                        /*expect_success=*/ true,
-                        /*use_fd=*/ true);
+    ASSERT_TRUE(GenerateOdexForTest(dex_location,
+                                    odex_location2,
+                                    CompilerFilter::kVerify,
+                                    // Disable cdex to avoid needing to write out the shared
+                                    // section.
+                                    { input_vdex, output_vdex, kDisableCompactDex },
+                                    /* expect_success= */ true,
+                                    /* use_fd= */ true));
   }
   ASSERT_EQ(vdex_unquickened->Flush(), 0) << "Could not flush and close vdex file";
   ASSERT_TRUE(success_);
@@ -2046,13 +2063,13 @@
   ScratchFile app_image_file;
   const std::string out_dir = GetScratchDir();
   const std::string odex_location = out_dir + "/base.odex";
-  GenerateOdexForTest(GetTestDexFileName("ManyMethods"),
-                      odex_location,
-                      CompilerFilter::Filter::kSpeedProfile,
-                      { "--app-image-fd=" + std::to_string(app_image_file.GetFd()) },
-                      true,  // expect_success
-                      false,  // use_fd
-                      [](const OatFile&) {});
+  ASSERT_TRUE(GenerateOdexForTest(GetTestDexFileName("ManyMethods"),
+                                  odex_location,
+                                  CompilerFilter::Filter::kSpeedProfile,
+                                  { "--app-image-fd=" + std::to_string(app_image_file.GetFd()) },
+                                  true,  // expect_success
+                                  false,  // use_fd
+                                  [](const OatFile&) {}));
   // Open our generated oat file.
   std::string error_msg;
   std::unique_ptr<OatFile> odex_file(OatFile::Open(/*zip_fd=*/ -1,
@@ -2105,15 +2122,15 @@
   const std::string out_dir = GetScratchDir();
   const std::string odex_location = out_dir + "/base.odex";
   const std::string app_image_location = out_dir + "/base.art";
-  GenerateOdexForTest(GetTestDexFileName("StringLiterals"),
-                      odex_location,
-                      CompilerFilter::Filter::kSpeedProfile,
-                      { "--app-image-file=" + app_image_location,
-                        "--resolve-startup-const-strings=true",
-                        "--profile-file=" + profile_file.GetFilename()},
-                      /*expect_success=*/ true,
-                      /*use_fd=*/ false,
-                      [](const OatFile&) {});
+  ASSERT_TRUE(GenerateOdexForTest(GetTestDexFileName("StringLiterals"),
+                                  odex_location,
+                                  CompilerFilter::Filter::kSpeedProfile,
+                                  { "--app-image-file=" + app_image_location,
+                                    "--resolve-startup-const-strings=true",
+                                    "--profile-file=" + profile_file.GetFilename()},
+                                  /* expect_success= */ true,
+                                  /* use_fd= */ false,
+                                  [](const OatFile&) {}));
   // Open our generated oat file.
   std::string error_msg;
   std::unique_ptr<OatFile> odex_file(OatFile::Open(/*zip_fd=*/ -1,
@@ -2220,27 +2237,27 @@
   }
   expected_stored_context +=    + "]";
   // The class path should not be valid and should fail being stored.
-  GenerateOdexForTest(GetTestDexFileName("ManyMethods"),
-                      odex_location,
-                      CompilerFilter::Filter::kQuicken,
-                      { "--class-loader-context=" + stored_context },
-                      true,  // expect_success
-                      false,  // use_fd
-                      [&](const OatFile& oat_file) {
+  EXPECT_TRUE(GenerateOdexForTest(GetTestDexFileName("ManyMethods"),
+                                  odex_location,
+                                  CompilerFilter::Filter::kQuicken,
+                                  { "--class-loader-context=" + stored_context },
+                                  true,  // expect_success
+                                  false,  // use_fd
+                                  [&](const OatFile& oat_file) {
     EXPECT_NE(oat_file.GetClassLoaderContext(), stored_context) << output_;
     EXPECT_NE(oat_file.GetClassLoaderContext(), valid_context) << output_;
-  });
+  }));
   // The stored context should match what we expect even though it's invalid.
-  GenerateOdexForTest(GetTestDexFileName("ManyMethods"),
-                      odex_location,
-                      CompilerFilter::Filter::kQuicken,
-                      { "--class-loader-context=" + valid_context,
-                        "--stored-class-loader-context=" + stored_context },
-                      true,  // expect_success
-                      false,  // use_fd
-                      [&](const OatFile& oat_file) {
+  EXPECT_TRUE(GenerateOdexForTest(GetTestDexFileName("ManyMethods"),
+                                  odex_location,
+                                  CompilerFilter::Filter::kQuicken,
+                                  { "--class-loader-context=" + valid_context,
+                                    "--stored-class-loader-context=" + stored_context },
+                                  true,  // expect_success
+                                  false,  // use_fd
+                                  [&](const OatFile& oat_file) {
     EXPECT_EQ(oat_file.GetClassLoaderContext(), expected_stored_context) << output_;
-  });
+  }));
 }
 
 }  // namespace art
diff --git a/disassembler/Android.bp b/disassembler/Android.bp
index 241b191..a7c1802 100644
--- a/disassembler/Android.bp
+++ b/disassembler/Android.bp
@@ -20,11 +20,39 @@
     host_supported: true,
     srcs: [
         "disassembler.cc",
-        "disassembler_arm.cc",
-        "disassembler_arm64.cc",
         "disassembler_mips.cc",
         "disassembler_x86.cc",
     ],
+    codegen: {
+        arm: {
+            srcs: ["disassembler_arm.cc"]
+        },
+        arm64: {
+            srcs: ["disassembler_arm64.cc"]
+        },
+        // TODO: We should also conditionally include the MIPS32/MIPS64 and the
+        // x86/x86-64 disassembler definitions (b/119090273). However, using the
+        // following syntax here:
+        //
+        //   mips: {
+        //       srcs: ["disassembler_mips.cc"]
+        //   },
+        //   mips64: {
+        //       srcs: ["disassembler_mips.cc"]
+        //   },
+        //   x86: {
+        //       srcs: ["disassembler_x86.cc"]
+        //   },
+        //   x86_64: {
+        //       srcs: ["disassembler_x86.cc"]
+        //   },
+        //
+        // does not work, as it generates a file rejected by ninja with this
+        // error message (e.g. on host, where we include all the back ends by
+        // default):
+        //
+        //   FAILED: ninja: out/soong/build.ninja:320768: multiple rules generate out/soong/.intermediates/art/disassembler/libart-disassembler/linux_glibc_x86_64_static/obj/art/disassembler/disassembler_mips.o [-w dupbuild=err]
+    },
     include_dirs: ["art/runtime"],
 
     shared_libs: [
diff --git a/disassembler/disassembler.cc b/disassembler/disassembler.cc
index 262e815..aee690e 100644
--- a/disassembler/disassembler.cc
+++ b/disassembler/disassembler.cc
@@ -21,10 +21,21 @@
 #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"
+#ifdef ART_ENABLE_CODEGEN_arm
+# include "disassembler_arm.h"
+#endif
+
+#ifdef ART_ENABLE_CODEGEN_arm64
+# include "disassembler_arm64.h"
+#endif
+
+#if defined(ART_ENABLE_CODEGEN_mips) || defined(ART_ENABLE_CODEGEN_mips64)
+# include "disassembler_mips.h"
+#endif
+
+#if defined(ART_ENABLE_CODEGEN_x86) || defined(ART_ENABLE_CODEGEN_x86_64)
+# include "disassembler_x86.h"
+#endif
 
 using android::base::StringPrintf;
 
@@ -36,21 +47,35 @@
 }
 
 Disassembler* Disassembler::Create(InstructionSet instruction_set, DisassemblerOptions* options) {
-  if (instruction_set == InstructionSet::kArm || instruction_set == InstructionSet::kThumb2) {
-    return new arm::DisassemblerArm(options);
-  } else if (instruction_set == InstructionSet::kArm64) {
-    return new arm64::DisassemblerArm64(options);
-  } else if (instruction_set == InstructionSet::kMips) {
-    return new mips::DisassemblerMips(options, /* is_o32_abi= */ true);
-  } else if (instruction_set == InstructionSet::kMips64) {
-    return new mips::DisassemblerMips(options, /* is_o32_abi= */ false);
-  } else if (instruction_set == InstructionSet::kX86) {
-    return new x86::DisassemblerX86(options, false);
-  } else if (instruction_set == InstructionSet::kX86_64) {
-    return new x86::DisassemblerX86(options, true);
-  } else {
-    UNIMPLEMENTED(FATAL) << static_cast<uint32_t>(instruction_set);
-    return nullptr;
+  switch (instruction_set) {
+#ifdef ART_ENABLE_CODEGEN_arm
+    case InstructionSet::kArm:
+    case InstructionSet::kThumb2:
+      return new arm::DisassemblerArm(options);
+#endif
+#ifdef ART_ENABLE_CODEGEN_arm64
+    case InstructionSet::kArm64:
+      return new arm64::DisassemblerArm64(options);
+#endif
+#ifdef ART_ENABLE_CODEGEN_mips
+    case InstructionSet::kMips:
+      return new mips::DisassemblerMips(options, /* is_o32_abi= */ true);
+#endif
+#ifdef ART_ENABLE_CODEGEN_mips64
+    case InstructionSet::kMips64:
+      return new mips::DisassemblerMips(options, /* is_o32_abi= */ false);
+#endif
+#ifdef ART_ENABLE_CODEGEN_x86
+    case InstructionSet::kX86:
+      return new x86::DisassemblerX86(options, /* supports_rex= */ false);
+#endif
+#ifdef ART_ENABLE_CODEGEN_x86_64
+    case InstructionSet::kX86_64:
+      return new x86::DisassemblerX86(options, /* supports_rex= */ true);
+#endif
+    default:
+      UNIMPLEMENTED(FATAL) << static_cast<uint32_t>(instruction_set);
+      return nullptr;
   }
 }
 
diff --git a/libartbase/base/file_utils_test.cc b/libartbase/base/file_utils_test.cc
index f7c9c5e..c917307 100644
--- a/libartbase/base/file_utils_test.cc
+++ b/libartbase/base/file_utils_test.cc
@@ -83,11 +83,15 @@
   ASSERT_EQ(0, unsetenv("ANDROID_ROOT"));
   std::string android_root3 = GetAndroidRootSafe(&error_msg);
   // This should be the same as the other root (modulo realpath), otherwise the test setup is
-  // broken.
-  UniqueCPtr<char> real_root(realpath(android_root.c_str(), nullptr));
+  // broken. On non-bionic. On bionic we can be running with a different libart that lives outside
+  // of ANDROID_ROOT
   UniqueCPtr<char> real_root3(realpath(android_root3.c_str(), nullptr));
+#if !defined(__BIONIC__ ) || defined(__ANDROID__)
+  UniqueCPtr<char> real_root(realpath(android_root.c_str(), nullptr));
   EXPECT_STREQ(real_root.get(), real_root3.get());
-
+#else
+  EXPECT_STRNE(real_root3.get(), "");
+#endif
 
   // Reset ANDROID_ROOT, as other things may depend on it.
   ASSERT_EQ(0, setenv("ANDROID_ROOT", android_root_env.c_str(), /* overwrite */ 1));
diff --git a/runtime/art_method-inl.h b/runtime/art_method-inl.h
index e9c17ee..d8da912 100644
--- a/runtime/art_method-inl.h
+++ b/runtime/art_method-inl.h
@@ -402,6 +402,7 @@
       case Intrinsics::kUnsafeLoadFence:
       case Intrinsics::kUnsafeStoreFence:
       case Intrinsics::kUnsafeFullFence:
+      case Intrinsics::kCRC32Update:
         // These intrinsics are on the light greylist and will fail a DCHECK in
         // SetIntrinsic() if their flags change on the respective dex methods.
         // Note that the DCHECK currently won't fail if the dex methods are
diff --git a/runtime/class_linker.cc b/runtime/class_linker.cc
index 7ccfff1..d1d5bc4 100644
--- a/runtime/class_linker.cc
+++ b/runtime/class_linker.cc
@@ -2034,11 +2034,15 @@
   }
   if (app_image) {
     AppImageLoadingHelper::Update(this, space, class_loader, dex_caches, &temp_set);
-    // Update class loader and resolved strings. If added_class_table is false, the resolved
-    // strings were forwarded UpdateAppImageClassLoadersAndDexCaches.
-    UpdateClassLoaderVisitor visitor(space, class_loader.Get());
-    for (const ClassTable::TableSlot& root : temp_set) {
-      visitor(root.Read());
+
+    {
+      ScopedTrace trace("AppImage:UpdateClassLoaders");
+      // Update class loader and resolved strings. If added_class_table is false, the resolved
+      // strings were forwarded UpdateAppImageClassLoadersAndDexCaches.
+      UpdateClassLoaderVisitor visitor(space, class_loader.Get());
+      for (const ClassTable::TableSlot& root : temp_set) {
+        visitor(root.Read());
+      }
     }
 
     if (kBitstringSubtypeCheckEnabled) {
diff --git a/runtime/gc/collector/concurrent_copying.cc b/runtime/gc/collector/concurrent_copying.cc
index e0bbf43..26a8d13 100644
--- a/runtime/gc/collector/concurrent_copying.cc
+++ b/runtime/gc/collector/concurrent_copying.cc
@@ -1658,7 +1658,9 @@
         << " type=" << to_ref->PrettyTypeOf()
         << " young_gen=" << std::boolalpha << young_gen_ << std::noboolalpha
         << " space=" << heap_->DumpSpaceNameFromAddress(to_ref)
-        << " region_type=" << rtype;
+        << " region_type=" << rtype
+        // TODO: Temporary; remove this when this is no longer needed (b/116087961).
+        << " runtime->sentinel=" << Runtime::Current()->GetSentinel().Read<kWithoutReadBarrier>();
   }
   bool add_to_live_bytes = false;
   // Invariant: There should be no object from a newly-allocated
@@ -1702,7 +1704,9 @@
         << " type=" << to_ref->PrettyTypeOf()
         << " young_gen=" << std::boolalpha << young_gen_ << std::noboolalpha
         << " space=" << heap_->DumpSpaceNameFromAddress(to_ref)
-        << " region_type=" << rtype;
+        << " region_type=" << rtype
+        // TODO: Temporary; remove this when this is no longer needed (b/116087961).
+        << " runtime->sentinel=" << Runtime::Current()->GetSentinel().Read<kWithoutReadBarrier>();
   }
 #ifdef USE_BAKER_OR_BROOKS_READ_BARRIER
   mirror::Object* referent = nullptr;
diff --git a/runtime/image.cc b/runtime/image.cc
index 376742a..59ac283 100644
--- a/runtime/image.cc
+++ b/runtime/image.cc
@@ -26,7 +26,7 @@
 namespace art {
 
 const uint8_t ImageHeader::kImageMagic[] = { 'a', 'r', 't', '\n' };
-const uint8_t ImageHeader::kImageVersion[] = { '0', '6', '6', '\0' };  // Add metadata section.
+const uint8_t ImageHeader::kImageVersion[] = { '0', '6', '7', '\0' };  // Added CRC32 intrinsic
 
 ImageHeader::ImageHeader(uint32_t image_begin,
                          uint32_t image_size,
diff --git a/runtime/interpreter/interpreter_intrinsics.cc b/runtime/interpreter/interpreter_intrinsics.cc
index 17b3cd4..24a026a 100644
--- a/runtime/interpreter/interpreter_intrinsics.cc
+++ b/runtime/interpreter/interpreter_intrinsics.cc
@@ -558,6 +558,7 @@
     UNIMPLEMENTED_CASE(ReferenceGetReferent /* ()Ljava/lang/Object; */)
     UNIMPLEMENTED_CASE(IntegerValueOf /* (I)Ljava/lang/Integer; */)
     UNIMPLEMENTED_CASE(ThreadInterrupted /* ()Z */)
+    UNIMPLEMENTED_CASE(CRC32Update /* (II)I */)
     INTRINSIC_CASE(VarHandleFullFence)
     INTRINSIC_CASE(VarHandleAcquireFence)
     INTRINSIC_CASE(VarHandleReleaseFence)
diff --git a/runtime/interpreter/interpreter_switch_impl-inl.h b/runtime/interpreter/interpreter_switch_impl-inl.h
index 48e1728..71b2336 100644
--- a/runtime/interpreter/interpreter_switch_impl-inl.h
+++ b/runtime/interpreter/interpreter_switch_impl-inl.h
@@ -23,6 +23,7 @@
 #include "base/memory_tool.h"
 #include "base/quasi_atomic.h"
 #include "dex/dex_file_types.h"
+#include "dex/dex_instruction_list.h"
 #include "experimental_flags.h"
 #include "interpreter_common.h"
 #include "jit/jit.h"
@@ -36,6 +37,7 @@
 namespace art {
 namespace interpreter {
 
+// TODO: Replace macros with member functions.
 #define CHECK_FORCE_RETURN()                                                        \
   {                                                                                 \
     if (UNLIKELY(shadow_frame.GetForcePopFrame())) {                                \
@@ -46,12 +48,13 @@
         SendMethodExitEvents(self,                                                  \
                              instrumentation,                                       \
                              shadow_frame,                                          \
-                             shadow_frame.GetThisObject(accessor.InsSize()),        \
+                             shadow_frame.GetThisObject(Accessor().InsSize()),      \
                              shadow_frame.GetMethod(),                              \
-                             inst->GetDexPc(insns),                                 \
+                             inst->GetDexPc(Insns()),                               \
                              JValue());                                             \
       }                                                                             \
       ctx->result = JValue(); /* Handled in caller. */                              \
+      exit_interpreter_loop = true;                                                 \
       return;                                                                       \
     }                                                                               \
   }                                                                                 \
@@ -65,18 +68,19 @@
     if (!MoveToExceptionHandler(self, shadow_frame, instr)) {                                   \
       /* Structured locking is to be enforced for abnormal termination, too. */                 \
       DoMonitorCheckOnExit<do_assignability_check>(self, &shadow_frame);                        \
-      if (interpret_one_instruction) {                                                          \
+      if (ctx->interpret_one_instruction) {                                                     \
         /* Signal mterp to return to caller */                                                  \
         shadow_frame.SetDexPC(dex::kDexNoIndex);                                                \
       }                                                                                         \
       ctx->result = JValue(); /* Handled in caller. */                                          \
+      exit_interpreter_loop = true;                                                             \
       return;                                                                                   \
     } else {                                                                                    \
       CHECK_FORCE_RETURN();                                                                     \
       int32_t displacement =                                                                    \
           static_cast<int32_t>(shadow_frame.GetDexPC()) - static_cast<int32_t>(dex_pc);         \
       inst = inst->RelativeAt(displacement);                                                    \
-      break;  /* Stop executing this opcode and continue in the exception handler. */           \
+      return;  /* Stop executing this opcode and continue in the exception handler. */          \
     }                                                                                           \
   }                                                                                             \
   do {} while (false)
@@ -138,13 +142,12 @@
     CHECK_FORCE_RETURN();                                                                       \
     if (UNLIKELY(instrumentation->HasDexPcListeners())) {                                       \
       if (UNLIKELY(!DoDexPcMoveEvent(self,                                                      \
-                                     accessor,                                                  \
+                                     Accessor(),                                                \
                                      shadow_frame,                                              \
                                      dex_pc,                                                    \
                                      instrumentation,                                           \
                                      save_ref))) {                                              \
         HANDLE_PENDING_EXCEPTION();                                                             \
-        break;                                                                                  \
       }                                                                                         \
       CHECK_FORCE_RETURN();                                                                     \
     }                                                                                           \
@@ -164,11 +167,12 @@
                                             dex_pc,                                            \
                                             offset,                                            \
                                             &result)) {                                        \
-      if (interpret_one_instruction) {                                                         \
+      if (ctx->interpret_one_instruction) {                                                    \
         /* OSR has completed execution of the method.  Signal mterp to return to caller */     \
         shadow_frame.SetDexPC(dex::kDexNoIndex);                                               \
       }                                                                                        \
       ctx->result = result;                                                                    \
+      exit_interpreter_loop = true;                                                            \
       return;                                                                                  \
     }                                                                                          \
   }                                                                                            \
@@ -176,6 +180,7 @@
 
 #define HOTNESS_UPDATE()                                                                       \
   {                                                                                            \
+    jit::Jit* jit = Runtime::Current()->GetJit();                                              \
     if (jit != nullptr) {                                                                      \
       jit->AddSamples(self, shadow_frame.GetMethod(), 1, /*with_backedges=*/ true);            \
     }                                                                                          \
@@ -193,7 +198,7 @@
     if (IsBackwardBranch(offset)) {                                                            \
       HOTNESS_UPDATE();                                                                        \
       /* Record new dex pc early to have consistent suspend point at loop header. */           \
-      shadow_frame.SetDexPC(inst->GetDexPc(insns));                                            \
+      shadow_frame.SetDexPC(inst->GetDexPc(Insns()));                                          \
       self->AllowThreadSuspension();                                                           \
     }                                                                                          \
   }                                                                                            \
@@ -268,6 +273,2460 @@
   }
 }
 
+// Short-lived helper class which executes single DEX bytecode.  It is inlined by compiler.
+//
+// The function names must match the names from dex_instruction_list.h and have no arguments.
+//
+// Any relevant execution information is stored in the fields - it should be kept to minimum.
+//
+template<bool do_access_check, bool transaction_active>
+class InstructionHandler {
+ public:
+  ALWAYS_INLINE void NOP() REQUIRES_SHARED(Locks::mutator_lock_) {
+    PREAMBLE();
+    inst = inst->Next_1xx();
+  }
+
+  ALWAYS_INLINE void MOVE() REQUIRES_SHARED(Locks::mutator_lock_) {
+    PREAMBLE();
+    shadow_frame.SetVReg(inst->VRegA_12x(inst_data),
+                         shadow_frame.GetVReg(inst->VRegB_12x(inst_data)));
+    inst = inst->Next_1xx();
+  }
+
+  ALWAYS_INLINE void MOVE_FROM16() REQUIRES_SHARED(Locks::mutator_lock_) {
+    PREAMBLE();
+    shadow_frame.SetVReg(inst->VRegA_22x(inst_data),
+                         shadow_frame.GetVReg(inst->VRegB_22x()));
+    inst = inst->Next_2xx();
+  }
+
+  ALWAYS_INLINE void MOVE_16() REQUIRES_SHARED(Locks::mutator_lock_) {
+    PREAMBLE();
+    shadow_frame.SetVReg(inst->VRegA_32x(),
+                         shadow_frame.GetVReg(inst->VRegB_32x()));
+    inst = inst->Next_3xx();
+  }
+
+  ALWAYS_INLINE void MOVE_WIDE() REQUIRES_SHARED(Locks::mutator_lock_) {
+    PREAMBLE();
+    shadow_frame.SetVRegLong(inst->VRegA_12x(inst_data),
+                             shadow_frame.GetVRegLong(inst->VRegB_12x(inst_data)));
+    inst = inst->Next_1xx();
+  }
+
+  ALWAYS_INLINE void MOVE_WIDE_FROM16() REQUIRES_SHARED(Locks::mutator_lock_) {
+    PREAMBLE();
+    shadow_frame.SetVRegLong(inst->VRegA_22x(inst_data),
+                             shadow_frame.GetVRegLong(inst->VRegB_22x()));
+    inst = inst->Next_2xx();
+  }
+
+  ALWAYS_INLINE void MOVE_WIDE_16() REQUIRES_SHARED(Locks::mutator_lock_) {
+    PREAMBLE();
+    shadow_frame.SetVRegLong(inst->VRegA_32x(),
+                             shadow_frame.GetVRegLong(inst->VRegB_32x()));
+    inst = inst->Next_3xx();
+  }
+
+  ALWAYS_INLINE void MOVE_OBJECT() REQUIRES_SHARED(Locks::mutator_lock_) {
+    PREAMBLE();
+    shadow_frame.SetVRegReference(inst->VRegA_12x(inst_data),
+                                  shadow_frame.GetVRegReference(inst->VRegB_12x(inst_data)));
+    inst = inst->Next_1xx();
+  }
+
+  ALWAYS_INLINE void MOVE_OBJECT_FROM16() REQUIRES_SHARED(Locks::mutator_lock_) {
+    PREAMBLE();
+    shadow_frame.SetVRegReference(inst->VRegA_22x(inst_data),
+                                  shadow_frame.GetVRegReference(inst->VRegB_22x()));
+    inst = inst->Next_2xx();
+  }
+
+  ALWAYS_INLINE void MOVE_OBJECT_16() REQUIRES_SHARED(Locks::mutator_lock_) {
+    PREAMBLE();
+    shadow_frame.SetVRegReference(inst->VRegA_32x(),
+                                  shadow_frame.GetVRegReference(inst->VRegB_32x()));
+    inst = inst->Next_3xx();
+  }
+
+  ALWAYS_INLINE void MOVE_RESULT() REQUIRES_SHARED(Locks::mutator_lock_) {
+    PREAMBLE();
+    shadow_frame.SetVReg(inst->VRegA_11x(inst_data), ResultRegister()->GetI());
+    inst = inst->Next_1xx();
+  }
+
+  ALWAYS_INLINE void MOVE_RESULT_WIDE() REQUIRES_SHARED(Locks::mutator_lock_) {
+    PREAMBLE();
+    shadow_frame.SetVRegLong(inst->VRegA_11x(inst_data), ResultRegister()->GetJ());
+    inst = inst->Next_1xx();
+  }
+
+  ALWAYS_INLINE void MOVE_RESULT_OBJECT() REQUIRES_SHARED(Locks::mutator_lock_) {
+    PREAMBLE_SAVE(ResultRegister());
+    shadow_frame.SetVRegReference(inst->VRegA_11x(inst_data), ResultRegister()->GetL());
+    inst = inst->Next_1xx();
+  }
+
+  ALWAYS_INLINE void MOVE_EXCEPTION() REQUIRES_SHARED(Locks::mutator_lock_) {
+    PREAMBLE();
+    ObjPtr<mirror::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();
+    inst = inst->Next_1xx();
+  }
+
+  ALWAYS_INLINE void RETURN_VOID_NO_BARRIER() REQUIRES_SHARED(Locks::mutator_lock_) {
+    PREAMBLE();
+    JValue result;
+    self->AllowThreadSuspension();
+    HANDLE_MONITOR_CHECKS();
+    if (UNLIKELY(NeedsMethodExitEvent(instrumentation) &&
+                 !SendMethodExitEvents(self,
+                                       instrumentation,
+                                       shadow_frame,
+                                       shadow_frame.GetThisObject(Accessor().InsSize()),
+                                       shadow_frame.GetMethod(),
+                                       inst->GetDexPc(Insns()),
+                                       result))) {
+      HANDLE_PENDING_EXCEPTION_WITH_INSTRUMENTATION(nullptr);
+    }
+    if (ctx->interpret_one_instruction) {
+      /* Signal mterp to return to caller */
+      shadow_frame.SetDexPC(dex::kDexNoIndex);
+    }
+    ctx->result = result;
+    exit_interpreter_loop = true;
+  }
+
+  ALWAYS_INLINE void RETURN_VOID() REQUIRES_SHARED(Locks::mutator_lock_) {
+    PREAMBLE();
+    QuasiAtomic::ThreadFenceForConstructor();
+    JValue result;
+    self->AllowThreadSuspension();
+    HANDLE_MONITOR_CHECKS();
+    if (UNLIKELY(NeedsMethodExitEvent(instrumentation) &&
+                 !SendMethodExitEvents(self,
+                                       instrumentation,
+                                       shadow_frame,
+                                       shadow_frame.GetThisObject(Accessor().InsSize()),
+                                       shadow_frame.GetMethod(),
+                                       inst->GetDexPc(Insns()),
+                                       result))) {
+      HANDLE_PENDING_EXCEPTION_WITH_INSTRUMENTATION(nullptr);
+    }
+    if (ctx->interpret_one_instruction) {
+      /* Signal mterp to return to caller */
+      shadow_frame.SetDexPC(dex::kDexNoIndex);
+    }
+    ctx->result = result;
+    exit_interpreter_loop = true;
+  }
+
+  ALWAYS_INLINE void RETURN() REQUIRES_SHARED(Locks::mutator_lock_) {
+    PREAMBLE();
+    JValue result;
+    result.SetJ(0);
+    result.SetI(shadow_frame.GetVReg(inst->VRegA_11x(inst_data)));
+    self->AllowThreadSuspension();
+    HANDLE_MONITOR_CHECKS();
+    if (UNLIKELY(NeedsMethodExitEvent(instrumentation) &&
+                 !SendMethodExitEvents(self,
+                                       instrumentation,
+                                       shadow_frame,
+                                       shadow_frame.GetThisObject(Accessor().InsSize()),
+                                       shadow_frame.GetMethod(),
+                                       inst->GetDexPc(Insns()),
+                                       result))) {
+      HANDLE_PENDING_EXCEPTION_WITH_INSTRUMENTATION(nullptr);
+    }
+    if (ctx->interpret_one_instruction) {
+      /* Signal mterp to return to caller */
+      shadow_frame.SetDexPC(dex::kDexNoIndex);
+    }
+    ctx->result = result;
+    exit_interpreter_loop = true;
+  }
+
+  ALWAYS_INLINE void RETURN_WIDE() REQUIRES_SHARED(Locks::mutator_lock_) {
+    PREAMBLE();
+    JValue result;
+    result.SetJ(shadow_frame.GetVRegLong(inst->VRegA_11x(inst_data)));
+    self->AllowThreadSuspension();
+    HANDLE_MONITOR_CHECKS();
+    if (UNLIKELY(NeedsMethodExitEvent(instrumentation) &&
+                 !SendMethodExitEvents(self,
+                                       instrumentation,
+                                       shadow_frame,
+                                       shadow_frame.GetThisObject(Accessor().InsSize()),
+                                       shadow_frame.GetMethod(),
+                                       inst->GetDexPc(Insns()),
+                                       result))) {
+      HANDLE_PENDING_EXCEPTION_WITH_INSTRUMENTATION(nullptr);
+    }
+    if (ctx->interpret_one_instruction) {
+      /* Signal mterp to return to caller */
+      shadow_frame.SetDexPC(dex::kDexNoIndex);
+    }
+    ctx->result = result;
+    exit_interpreter_loop = true;
+  }
+
+  ALWAYS_INLINE void RETURN_OBJECT() REQUIRES_SHARED(Locks::mutator_lock_) {
+    PREAMBLE();
+    JValue result;
+    self->AllowThreadSuspension();
+    HANDLE_MONITOR_CHECKS();
+    const size_t ref_idx = inst->VRegA_11x(inst_data);
+    ObjPtr<mirror::Object> obj_result = shadow_frame.GetVRegReference(ref_idx);
+    if (do_assignability_check && obj_result != nullptr) {
+      ObjPtr<mirror::Class> return_type = shadow_frame.GetMethod()->ResolveReturnType();
+      // Re-load since it might have moved.
+      obj_result = shadow_frame.GetVRegReference(ref_idx);
+      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/InternalError;",
+                                 "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(NeedsMethodExitEvent(instrumentation) &&
+                 !SendMethodExitEvents(self,
+                                       instrumentation,
+                                       shadow_frame,
+                                       shadow_frame.GetThisObject(Accessor().InsSize()),
+                                       shadow_frame.GetMethod(),
+                                       inst->GetDexPc(Insns()),
+                                       result))) {
+      HANDLE_PENDING_EXCEPTION_WITH_INSTRUMENTATION(nullptr);
+    }
+    // Re-load since it might have moved during the MethodExitEvent.
+    result.SetL(shadow_frame.GetVRegReference(ref_idx));
+    if (ctx->interpret_one_instruction) {
+      /* Signal mterp to return to caller */
+      shadow_frame.SetDexPC(dex::kDexNoIndex);
+    }
+    ctx->result = result;
+    exit_interpreter_loop = true;
+  }
+
+  ALWAYS_INLINE void CONST_4() REQUIRES_SHARED(Locks::mutator_lock_) {
+    PREAMBLE();
+    uint4_t dst = inst->VRegA_11n(inst_data);
+    int4_t val = inst->VRegB_11n(inst_data);
+    shadow_frame.SetVReg(dst, val);
+    if (val == 0) {
+      shadow_frame.SetVRegReference(dst, nullptr);
+    }
+    inst = inst->Next_1xx();
+  }
+
+  ALWAYS_INLINE void CONST_16() REQUIRES_SHARED(Locks::mutator_lock_) {
+    PREAMBLE();
+    uint8_t dst = inst->VRegA_21s(inst_data);
+    int16_t val = inst->VRegB_21s();
+    shadow_frame.SetVReg(dst, val);
+    if (val == 0) {
+      shadow_frame.SetVRegReference(dst, nullptr);
+    }
+    inst = inst->Next_2xx();
+  }
+
+  ALWAYS_INLINE void CONST() REQUIRES_SHARED(Locks::mutator_lock_) {
+    PREAMBLE();
+    uint8_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);
+    }
+    inst = inst->Next_3xx();
+  }
+
+  ALWAYS_INLINE void CONST_HIGH16() REQUIRES_SHARED(Locks::mutator_lock_) {
+    PREAMBLE();
+    uint8_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);
+    }
+    inst = inst->Next_2xx();
+  }
+
+  ALWAYS_INLINE void CONST_WIDE_16() REQUIRES_SHARED(Locks::mutator_lock_) {
+    PREAMBLE();
+    shadow_frame.SetVRegLong(inst->VRegA_21s(inst_data), inst->VRegB_21s());
+    inst = inst->Next_2xx();
+  }
+
+  ALWAYS_INLINE void CONST_WIDE_32() REQUIRES_SHARED(Locks::mutator_lock_) {
+    PREAMBLE();
+    shadow_frame.SetVRegLong(inst->VRegA_31i(inst_data), inst->VRegB_31i());
+    inst = inst->Next_3xx();
+  }
+
+  ALWAYS_INLINE void CONST_WIDE() REQUIRES_SHARED(Locks::mutator_lock_) {
+    PREAMBLE();
+    shadow_frame.SetVRegLong(inst->VRegA_51l(inst_data), inst->VRegB_51l());
+    inst = inst->Next_51l();
+  }
+
+  ALWAYS_INLINE void CONST_WIDE_HIGH16() REQUIRES_SHARED(Locks::mutator_lock_) {
+    PREAMBLE();
+    shadow_frame.SetVRegLong(inst->VRegA_21h(inst_data),
+                             static_cast<uint64_t>(inst->VRegB_21h()) << 48);
+    inst = inst->Next_2xx();
+  }
+
+  ALWAYS_INLINE void CONST_STRING() REQUIRES_SHARED(Locks::mutator_lock_) {
+    PREAMBLE();
+    ObjPtr<mirror::String> s = ResolveString(self,
+                                             shadow_frame,
+                                             dex::StringIndex(inst->VRegB_21c()));
+    if (UNLIKELY(s == nullptr)) {
+      HANDLE_PENDING_EXCEPTION();
+    } else {
+      shadow_frame.SetVRegReference(inst->VRegA_21c(inst_data), s);
+      inst = inst->Next_2xx();
+    }
+  }
+
+  ALWAYS_INLINE void CONST_STRING_JUMBO() REQUIRES_SHARED(Locks::mutator_lock_) {
+    PREAMBLE();
+    ObjPtr<mirror::String> s = ResolveString(self,
+                                             shadow_frame,
+                                             dex::StringIndex(inst->VRegB_31c()));
+    if (UNLIKELY(s == nullptr)) {
+      HANDLE_PENDING_EXCEPTION();
+    } else {
+      shadow_frame.SetVRegReference(inst->VRegA_31c(inst_data), s);
+      inst = inst->Next_3xx();
+    }
+  }
+
+  ALWAYS_INLINE void CONST_CLASS() REQUIRES_SHARED(Locks::mutator_lock_) {
+    PREAMBLE();
+    ObjPtr<mirror::Class> c = ResolveVerifyAndClinit(dex::TypeIndex(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);
+      inst = inst->Next_2xx();
+    }
+  }
+
+  ALWAYS_INLINE void CONST_METHOD_HANDLE() REQUIRES_SHARED(Locks::mutator_lock_) {
+    PREAMBLE();
+    ClassLinker* cl = Runtime::Current()->GetClassLinker();
+    ObjPtr<mirror::MethodHandle> mh = cl->ResolveMethodHandle(self,
+                                                              inst->VRegB_21c(),
+                                                              shadow_frame.GetMethod());
+    if (UNLIKELY(mh == nullptr)) {
+      HANDLE_PENDING_EXCEPTION();
+    } else {
+      shadow_frame.SetVRegReference(inst->VRegA_21c(inst_data), mh);
+      inst = inst->Next_2xx();
+    }
+  }
+
+  ALWAYS_INLINE void CONST_METHOD_TYPE() REQUIRES_SHARED(Locks::mutator_lock_) {
+    PREAMBLE();
+    ClassLinker* cl = Runtime::Current()->GetClassLinker();
+    ObjPtr<mirror::MethodType> mt = cl->ResolveMethodType(self,
+                                                          dex::ProtoIndex(inst->VRegB_21c()),
+                                                          shadow_frame.GetMethod());
+    if (UNLIKELY(mt == nullptr)) {
+      HANDLE_PENDING_EXCEPTION();
+    } else {
+      shadow_frame.SetVRegReference(inst->VRegA_21c(inst_data), mt);
+      inst = inst->Next_2xx();
+    }
+  }
+
+  ALWAYS_INLINE void MONITOR_ENTER() REQUIRES_SHARED(Locks::mutator_lock_) {
+    PREAMBLE();
+    HANDLE_ASYNC_EXCEPTION();
+    ObjPtr<mirror::Object> obj = shadow_frame.GetVRegReference(inst->VRegA_11x(inst_data));
+    if (UNLIKELY(obj == nullptr)) {
+      ThrowNullPointerExceptionFromInterpreter();
+      HANDLE_PENDING_EXCEPTION();
+    } else {
+      DoMonitorEnter<do_assignability_check>(self, &shadow_frame, obj);
+      POSSIBLY_HANDLE_PENDING_EXCEPTION(self->IsExceptionPending(), Next_1xx);
+    }
+  }
+
+  ALWAYS_INLINE void MONITOR_EXIT() REQUIRES_SHARED(Locks::mutator_lock_) {
+    PREAMBLE();
+    HANDLE_ASYNC_EXCEPTION();
+    ObjPtr<mirror::Object> obj = shadow_frame.GetVRegReference(inst->VRegA_11x(inst_data));
+    if (UNLIKELY(obj == nullptr)) {
+      ThrowNullPointerExceptionFromInterpreter();
+      HANDLE_PENDING_EXCEPTION();
+    } else {
+      DoMonitorExit<do_assignability_check>(self, &shadow_frame, obj);
+      POSSIBLY_HANDLE_PENDING_EXCEPTION(self->IsExceptionPending(), Next_1xx);
+    }
+  }
+
+  ALWAYS_INLINE void CHECK_CAST() REQUIRES_SHARED(Locks::mutator_lock_) {
+    PREAMBLE();
+    ObjPtr<mirror::Class> c = ResolveVerifyAndClinit(dex::TypeIndex(inst->VRegB_21c()),
+                                                     shadow_frame.GetMethod(),
+                                                     self,
+                                                     false,
+                                                     do_access_check);
+    if (UNLIKELY(c == nullptr)) {
+      HANDLE_PENDING_EXCEPTION();
+    } else {
+      ObjPtr<mirror::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 {
+        inst = inst->Next_2xx();
+      }
+    }
+  }
+
+  ALWAYS_INLINE void INSTANCE_OF() REQUIRES_SHARED(Locks::mutator_lock_) {
+    PREAMBLE();
+    ObjPtr<mirror::Class> c = ResolveVerifyAndClinit(dex::TypeIndex(inst->VRegC_22c()),
+                                                     shadow_frame.GetMethod(),
+                                                     self,
+                                                     false,
+                                                     do_access_check);
+    if (UNLIKELY(c == nullptr)) {
+      HANDLE_PENDING_EXCEPTION();
+    } else {
+      ObjPtr<mirror::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);
+      inst = inst->Next_2xx();
+    }
+  }
+
+  ALWAYS_INLINE void ARRAY_LENGTH() REQUIRES_SHARED(Locks::mutator_lock_) {
+    PREAMBLE();
+    ObjPtr<mirror::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());
+      inst = inst->Next_1xx();
+    }
+  }
+
+  ALWAYS_INLINE void NEW_INSTANCE() REQUIRES_SHARED(Locks::mutator_lock_) {
+    PREAMBLE();
+    ObjPtr<mirror::Object> obj = nullptr;
+    ObjPtr<mirror::Class> c = ResolveVerifyAndClinit(dex::TypeIndex(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<true>(
+            c.Ptr(),
+            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",
+                          obj->PrettyTypeOf().c_str());
+        HANDLE_PENDING_EXCEPTION();
+      }
+      shadow_frame.SetVRegReference(inst->VRegA_21c(inst_data), obj);
+      inst = inst->Next_2xx();
+    }
+  }
+
+  ALWAYS_INLINE void NEW_ARRAY() REQUIRES_SHARED(Locks::mutator_lock_) {
+    PREAMBLE();
+    int32_t length = shadow_frame.GetVReg(inst->VRegB_22c(inst_data));
+    ObjPtr<mirror::Object> obj = AllocArrayFromCode<do_access_check, true>(
+        dex::TypeIndex(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);
+      inst = inst->Next_2xx();
+    }
+  }
+
+  ALWAYS_INLINE void FILLED_NEW_ARRAY() REQUIRES_SHARED(Locks::mutator_lock_) {
+    PREAMBLE();
+    bool success =
+        DoFilledNewArray<false, do_access_check, transaction_active>(inst, shadow_frame, self,
+                                                                     ResultRegister());
+    POSSIBLY_HANDLE_PENDING_EXCEPTION(!success, Next_3xx);
+  }
+
+  ALWAYS_INLINE void FILLED_NEW_ARRAY_RANGE() REQUIRES_SHARED(Locks::mutator_lock_) {
+    PREAMBLE();
+    bool success =
+        DoFilledNewArray<true, do_access_check, transaction_active>(inst, shadow_frame,
+                                                                    self, ResultRegister());
+    POSSIBLY_HANDLE_PENDING_EXCEPTION(!success, Next_3xx);
+  }
+
+  ALWAYS_INLINE void FILL_ARRAY_DATA() REQUIRES_SHARED(Locks::mutator_lock_) {
+    PREAMBLE();
+    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);
+    ObjPtr<mirror::Object> obj = shadow_frame.GetVRegReference(inst->VRegA_31t(inst_data));
+    bool success = FillArrayData(obj, payload);
+    if (!success) {
+      HANDLE_PENDING_EXCEPTION();
+    }
+    if (transaction_active) {
+      RecordArrayElementsInTransaction(obj->AsArray(), payload->element_count);
+    }
+    inst = inst->Next_3xx();
+  }
+
+  ALWAYS_INLINE void THROW() REQUIRES_SHARED(Locks::mutator_lock_) {
+    PREAMBLE();
+    HANDLE_ASYNC_EXCEPTION();
+    ObjPtr<mirror::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/InternalError;",
+                               "Throwing '%s' that is not instance of Throwable",
+                               exception->GetClass()->GetDescriptor(&temp));
+    } else {
+      self->SetException(exception->AsThrowable());
+    }
+    HANDLE_PENDING_EXCEPTION();
+  }
+
+  ALWAYS_INLINE void GOTO() REQUIRES_SHARED(Locks::mutator_lock_) {
+    PREAMBLE();
+    HANDLE_ASYNC_EXCEPTION();
+    int8_t offset = inst->VRegA_10t(inst_data);
+    BRANCH_INSTRUMENTATION(offset);
+    inst = inst->RelativeAt(offset);
+    HANDLE_BACKWARD_BRANCH(offset);
+  }
+
+  ALWAYS_INLINE void GOTO_16() REQUIRES_SHARED(Locks::mutator_lock_) {
+    PREAMBLE();
+    HANDLE_ASYNC_EXCEPTION();
+    int16_t offset = inst->VRegA_20t();
+    BRANCH_INSTRUMENTATION(offset);
+    inst = inst->RelativeAt(offset);
+    HANDLE_BACKWARD_BRANCH(offset);
+  }
+
+  ALWAYS_INLINE void GOTO_32() REQUIRES_SHARED(Locks::mutator_lock_) {
+    PREAMBLE();
+    HANDLE_ASYNC_EXCEPTION();
+    int32_t offset = inst->VRegA_30t();
+    BRANCH_INSTRUMENTATION(offset);
+    inst = inst->RelativeAt(offset);
+    HANDLE_BACKWARD_BRANCH(offset);
+  }
+
+  ALWAYS_INLINE void PACKED_SWITCH() REQUIRES_SHARED(Locks::mutator_lock_) {
+    PREAMBLE();
+    int32_t offset = DoPackedSwitch(inst, shadow_frame, inst_data);
+    BRANCH_INSTRUMENTATION(offset);
+    inst = inst->RelativeAt(offset);
+    HANDLE_BACKWARD_BRANCH(offset);
+  }
+
+  ALWAYS_INLINE void SPARSE_SWITCH() REQUIRES_SHARED(Locks::mutator_lock_) {
+    PREAMBLE();
+    int32_t offset = DoSparseSwitch(inst, shadow_frame, inst_data);
+    BRANCH_INSTRUMENTATION(offset);
+    inst = inst->RelativeAt(offset);
+    HANDLE_BACKWARD_BRANCH(offset);
+  }
+
+#pragma clang diagnostic push
+#pragma clang diagnostic ignored "-Wfloat-equal"
+
+
+  ALWAYS_INLINE void CMPL_FLOAT() REQUIRES_SHARED(Locks::mutator_lock_) {
+    PREAMBLE();
+    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);
+    inst = inst->Next_2xx();
+  }
+
+  ALWAYS_INLINE void CMPG_FLOAT() REQUIRES_SHARED(Locks::mutator_lock_) {
+    PREAMBLE();
+    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);
+    inst = inst->Next_2xx();
+  }
+
+  ALWAYS_INLINE void CMPL_DOUBLE() REQUIRES_SHARED(Locks::mutator_lock_) {
+    PREAMBLE();
+    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);
+    inst = inst->Next_2xx();
+  }
+
+
+  ALWAYS_INLINE void CMPG_DOUBLE() REQUIRES_SHARED(Locks::mutator_lock_) {
+    PREAMBLE();
+    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);
+    inst = inst->Next_2xx();
+  }
+
+#pragma clang diagnostic pop
+
+
+  ALWAYS_INLINE void CMP_LONG() REQUIRES_SHARED(Locks::mutator_lock_) {
+    PREAMBLE();
+    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);
+    inst = inst->Next_2xx();
+  }
+
+  ALWAYS_INLINE void IF_EQ() REQUIRES_SHARED(Locks::mutator_lock_) {
+    PREAMBLE();
+    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);
+      inst = inst->RelativeAt(offset);
+      HANDLE_BACKWARD_BRANCH(offset);
+    } else {
+      BRANCH_INSTRUMENTATION(2);
+      inst = inst->Next_2xx();
+    }
+  }
+
+  ALWAYS_INLINE void IF_NE() REQUIRES_SHARED(Locks::mutator_lock_) {
+    PREAMBLE();
+    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);
+      inst = inst->RelativeAt(offset);
+      HANDLE_BACKWARD_BRANCH(offset);
+    } else {
+      BRANCH_INSTRUMENTATION(2);
+      inst = inst->Next_2xx();
+    }
+  }
+
+  ALWAYS_INLINE void IF_LT() REQUIRES_SHARED(Locks::mutator_lock_) {
+    PREAMBLE();
+    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);
+      inst = inst->RelativeAt(offset);
+      HANDLE_BACKWARD_BRANCH(offset);
+    } else {
+      BRANCH_INSTRUMENTATION(2);
+      inst = inst->Next_2xx();
+    }
+  }
+
+  ALWAYS_INLINE void IF_GE() REQUIRES_SHARED(Locks::mutator_lock_) {
+    PREAMBLE();
+    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);
+      inst = inst->RelativeAt(offset);
+      HANDLE_BACKWARD_BRANCH(offset);
+    } else {
+      BRANCH_INSTRUMENTATION(2);
+      inst = inst->Next_2xx();
+    }
+  }
+
+  ALWAYS_INLINE void IF_GT() REQUIRES_SHARED(Locks::mutator_lock_) {
+    PREAMBLE();
+    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);
+      inst = inst->RelativeAt(offset);
+      HANDLE_BACKWARD_BRANCH(offset);
+    } else {
+      BRANCH_INSTRUMENTATION(2);
+      inst = inst->Next_2xx();
+    }
+  }
+
+  ALWAYS_INLINE void IF_LE() REQUIRES_SHARED(Locks::mutator_lock_) {
+    PREAMBLE();
+    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);
+      inst = inst->RelativeAt(offset);
+      HANDLE_BACKWARD_BRANCH(offset);
+    } else {
+      BRANCH_INSTRUMENTATION(2);
+      inst = inst->Next_2xx();
+    }
+  }
+
+  ALWAYS_INLINE void IF_EQZ() REQUIRES_SHARED(Locks::mutator_lock_) {
+    PREAMBLE();
+    if (shadow_frame.GetVReg(inst->VRegA_21t(inst_data)) == 0) {
+      int16_t offset = inst->VRegB_21t();
+      BRANCH_INSTRUMENTATION(offset);
+      inst = inst->RelativeAt(offset);
+      HANDLE_BACKWARD_BRANCH(offset);
+    } else {
+      BRANCH_INSTRUMENTATION(2);
+      inst = inst->Next_2xx();
+    }
+  }
+
+  ALWAYS_INLINE void IF_NEZ() REQUIRES_SHARED(Locks::mutator_lock_) {
+    PREAMBLE();
+    if (shadow_frame.GetVReg(inst->VRegA_21t(inst_data)) != 0) {
+      int16_t offset = inst->VRegB_21t();
+      BRANCH_INSTRUMENTATION(offset);
+      inst = inst->RelativeAt(offset);
+      HANDLE_BACKWARD_BRANCH(offset);
+    } else {
+      BRANCH_INSTRUMENTATION(2);
+      inst = inst->Next_2xx();
+    }
+  }
+
+  ALWAYS_INLINE void IF_LTZ() REQUIRES_SHARED(Locks::mutator_lock_) {
+    PREAMBLE();
+    if (shadow_frame.GetVReg(inst->VRegA_21t(inst_data)) < 0) {
+      int16_t offset = inst->VRegB_21t();
+      BRANCH_INSTRUMENTATION(offset);
+      inst = inst->RelativeAt(offset);
+      HANDLE_BACKWARD_BRANCH(offset);
+    } else {
+      BRANCH_INSTRUMENTATION(2);
+      inst = inst->Next_2xx();
+    }
+  }
+
+  ALWAYS_INLINE void IF_GEZ() REQUIRES_SHARED(Locks::mutator_lock_) {
+    PREAMBLE();
+    if (shadow_frame.GetVReg(inst->VRegA_21t(inst_data)) >= 0) {
+      int16_t offset = inst->VRegB_21t();
+      BRANCH_INSTRUMENTATION(offset);
+      inst = inst->RelativeAt(offset);
+      HANDLE_BACKWARD_BRANCH(offset);
+    } else {
+      BRANCH_INSTRUMENTATION(2);
+      inst = inst->Next_2xx();
+    }
+  }
+
+  ALWAYS_INLINE void IF_GTZ() REQUIRES_SHARED(Locks::mutator_lock_) {
+    PREAMBLE();
+    if (shadow_frame.GetVReg(inst->VRegA_21t(inst_data)) > 0) {
+      int16_t offset = inst->VRegB_21t();
+      BRANCH_INSTRUMENTATION(offset);
+      inst = inst->RelativeAt(offset);
+      HANDLE_BACKWARD_BRANCH(offset);
+    } else {
+      BRANCH_INSTRUMENTATION(2);
+      inst = inst->Next_2xx();
+    }
+  }
+
+  ALWAYS_INLINE void IF_LEZ() REQUIRES_SHARED(Locks::mutator_lock_) {
+    PREAMBLE();
+    if (shadow_frame.GetVReg(inst->VRegA_21t(inst_data)) <= 0) {
+      int16_t offset = inst->VRegB_21t();
+      BRANCH_INSTRUMENTATION(offset);
+      inst = inst->RelativeAt(offset);
+      HANDLE_BACKWARD_BRANCH(offset);
+    } else {
+      BRANCH_INSTRUMENTATION(2);
+      inst = inst->Next_2xx();
+    }
+  }
+
+  ALWAYS_INLINE void AGET_BOOLEAN() REQUIRES_SHARED(Locks::mutator_lock_) {
+    PREAMBLE();
+    ObjPtr<mirror::Object> a = shadow_frame.GetVRegReference(inst->VRegB_23x());
+    if (UNLIKELY(a == nullptr)) {
+      ThrowNullPointerExceptionFromInterpreter();
+      HANDLE_PENDING_EXCEPTION();
+    }
+    int32_t index = shadow_frame.GetVReg(inst->VRegC_23x());
+    ObjPtr<mirror::BooleanArray> array = a->AsBooleanArray();
+    if (array->CheckIsValidIndex(index)) {
+      shadow_frame.SetVReg(inst->VRegA_23x(inst_data), array->GetWithoutChecks(index));
+      inst = inst->Next_2xx();
+    } else {
+      HANDLE_PENDING_EXCEPTION();
+    }
+  }
+
+  ALWAYS_INLINE void AGET_BYTE() REQUIRES_SHARED(Locks::mutator_lock_) {
+    PREAMBLE();
+    ObjPtr<mirror::Object> a = shadow_frame.GetVRegReference(inst->VRegB_23x());
+    if (UNLIKELY(a == nullptr)) {
+      ThrowNullPointerExceptionFromInterpreter();
+      HANDLE_PENDING_EXCEPTION();
+    }
+    int32_t index = shadow_frame.GetVReg(inst->VRegC_23x());
+    ObjPtr<mirror::ByteArray> array = a->AsByteArray();
+    if (array->CheckIsValidIndex(index)) {
+      shadow_frame.SetVReg(inst->VRegA_23x(inst_data), array->GetWithoutChecks(index));
+      inst = inst->Next_2xx();
+    } else {
+      HANDLE_PENDING_EXCEPTION();
+    }
+  }
+
+  ALWAYS_INLINE void AGET_CHAR() REQUIRES_SHARED(Locks::mutator_lock_) {
+    PREAMBLE();
+    ObjPtr<mirror::Object> a = shadow_frame.GetVRegReference(inst->VRegB_23x());
+    if (UNLIKELY(a == nullptr)) {
+      ThrowNullPointerExceptionFromInterpreter();
+      HANDLE_PENDING_EXCEPTION();
+    }
+    int32_t index = shadow_frame.GetVReg(inst->VRegC_23x());
+    ObjPtr<mirror::CharArray> array = a->AsCharArray();
+    if (array->CheckIsValidIndex(index)) {
+      shadow_frame.SetVReg(inst->VRegA_23x(inst_data), array->GetWithoutChecks(index));
+      inst = inst->Next_2xx();
+    } else {
+      HANDLE_PENDING_EXCEPTION();
+    }
+  }
+
+  ALWAYS_INLINE void AGET_SHORT() REQUIRES_SHARED(Locks::mutator_lock_) {
+    PREAMBLE();
+    ObjPtr<mirror::Object> a = shadow_frame.GetVRegReference(inst->VRegB_23x());
+    if (UNLIKELY(a == nullptr)) {
+      ThrowNullPointerExceptionFromInterpreter();
+      HANDLE_PENDING_EXCEPTION();
+    }
+    int32_t index = shadow_frame.GetVReg(inst->VRegC_23x());
+    ObjPtr<mirror::ShortArray> array = a->AsShortArray();
+    if (array->CheckIsValidIndex(index)) {
+      shadow_frame.SetVReg(inst->VRegA_23x(inst_data), array->GetWithoutChecks(index));
+      inst = inst->Next_2xx();
+    } else {
+      HANDLE_PENDING_EXCEPTION();
+    }
+  }
+
+  ALWAYS_INLINE void AGET() REQUIRES_SHARED(Locks::mutator_lock_) {
+    PREAMBLE();
+    ObjPtr<mirror::Object> a = shadow_frame.GetVRegReference(inst->VRegB_23x());
+    if (UNLIKELY(a == nullptr)) {
+      ThrowNullPointerExceptionFromInterpreter();
+      HANDLE_PENDING_EXCEPTION();
+    }
+    int32_t index = shadow_frame.GetVReg(inst->VRegC_23x());
+    DCHECK(a->IsIntArray() || a->IsFloatArray()) << a->PrettyTypeOf();
+    ObjPtr<mirror::IntArray> array = ObjPtr<mirror::IntArray>::DownCast(a);
+    if (array->CheckIsValidIndex(index)) {
+      shadow_frame.SetVReg(inst->VRegA_23x(inst_data), array->GetWithoutChecks(index));
+      inst = inst->Next_2xx();
+    } else {
+      HANDLE_PENDING_EXCEPTION();
+    }
+  }
+
+  ALWAYS_INLINE void AGET_WIDE() REQUIRES_SHARED(Locks::mutator_lock_) {
+    PREAMBLE();
+    ObjPtr<mirror::Object> a = shadow_frame.GetVRegReference(inst->VRegB_23x());
+    if (UNLIKELY(a == nullptr)) {
+      ThrowNullPointerExceptionFromInterpreter();
+      HANDLE_PENDING_EXCEPTION();
+    }
+    int32_t index = shadow_frame.GetVReg(inst->VRegC_23x());
+    DCHECK(a->IsLongArray() || a->IsDoubleArray()) << a->PrettyTypeOf();
+    ObjPtr<mirror::LongArray> array = ObjPtr<mirror::LongArray>::DownCast(a);
+    if (array->CheckIsValidIndex(index)) {
+      shadow_frame.SetVRegLong(inst->VRegA_23x(inst_data), array->GetWithoutChecks(index));
+      inst = inst->Next_2xx();
+    } else {
+      HANDLE_PENDING_EXCEPTION();
+    }
+  }
+
+  ALWAYS_INLINE void AGET_OBJECT() REQUIRES_SHARED(Locks::mutator_lock_) {
+    PREAMBLE();
+    ObjPtr<mirror::Object> a = shadow_frame.GetVRegReference(inst->VRegB_23x());
+    if (UNLIKELY(a == nullptr)) {
+      ThrowNullPointerExceptionFromInterpreter();
+      HANDLE_PENDING_EXCEPTION();
+    }
+    int32_t index = shadow_frame.GetVReg(inst->VRegC_23x());
+    ObjPtr<mirror::ObjectArray<mirror::Object>> array = a->AsObjectArray<mirror::Object>();
+    if (array->CheckIsValidIndex(index)) {
+      shadow_frame.SetVRegReference(inst->VRegA_23x(inst_data), array->GetWithoutChecks(index));
+      inst = inst->Next_2xx();
+    } else {
+      HANDLE_PENDING_EXCEPTION();
+    }
+  }
+
+  ALWAYS_INLINE void APUT_BOOLEAN() REQUIRES_SHARED(Locks::mutator_lock_) {
+    PREAMBLE();
+    ObjPtr<mirror::Object> a = shadow_frame.GetVRegReference(inst->VRegB_23x());
+    if (UNLIKELY(a == nullptr)) {
+      ThrowNullPointerExceptionFromInterpreter();
+      HANDLE_PENDING_EXCEPTION();
+    }
+    uint8_t val = shadow_frame.GetVReg(inst->VRegA_23x(inst_data));
+    int32_t index = shadow_frame.GetVReg(inst->VRegC_23x());
+    ObjPtr<mirror::BooleanArray> array = a->AsBooleanArray();
+    if (array->CheckIsValidIndex(index)) {
+      array->SetWithoutChecks<transaction_active>(index, val);
+      inst = inst->Next_2xx();
+    } else {
+      HANDLE_PENDING_EXCEPTION();
+    }
+  }
+
+  ALWAYS_INLINE void APUT_BYTE() REQUIRES_SHARED(Locks::mutator_lock_) {
+    PREAMBLE();
+    ObjPtr<mirror::Object> a = shadow_frame.GetVRegReference(inst->VRegB_23x());
+    if (UNLIKELY(a == nullptr)) {
+      ThrowNullPointerExceptionFromInterpreter();
+      HANDLE_PENDING_EXCEPTION();
+    }
+    int8_t val = shadow_frame.GetVReg(inst->VRegA_23x(inst_data));
+    int32_t index = shadow_frame.GetVReg(inst->VRegC_23x());
+    ObjPtr<mirror::ByteArray> array = a->AsByteArray();
+    if (array->CheckIsValidIndex(index)) {
+      array->SetWithoutChecks<transaction_active>(index, val);
+      inst = inst->Next_2xx();
+    } else {
+      HANDLE_PENDING_EXCEPTION();
+    }
+  }
+
+  ALWAYS_INLINE void APUT_CHAR() REQUIRES_SHARED(Locks::mutator_lock_) {
+    PREAMBLE();
+    ObjPtr<mirror::Object> a = shadow_frame.GetVRegReference(inst->VRegB_23x());
+    if (UNLIKELY(a == nullptr)) {
+      ThrowNullPointerExceptionFromInterpreter();
+      HANDLE_PENDING_EXCEPTION();
+    }
+    uint16_t val = shadow_frame.GetVReg(inst->VRegA_23x(inst_data));
+    int32_t index = shadow_frame.GetVReg(inst->VRegC_23x());
+    ObjPtr<mirror::CharArray> array = a->AsCharArray();
+    if (array->CheckIsValidIndex(index)) {
+      array->SetWithoutChecks<transaction_active>(index, val);
+      inst = inst->Next_2xx();
+    } else {
+      HANDLE_PENDING_EXCEPTION();
+    }
+  }
+
+  ALWAYS_INLINE void APUT_SHORT() REQUIRES_SHARED(Locks::mutator_lock_) {
+    PREAMBLE();
+    ObjPtr<mirror::Object> a = shadow_frame.GetVRegReference(inst->VRegB_23x());
+    if (UNLIKELY(a == nullptr)) {
+      ThrowNullPointerExceptionFromInterpreter();
+      HANDLE_PENDING_EXCEPTION();
+    }
+    int16_t val = shadow_frame.GetVReg(inst->VRegA_23x(inst_data));
+    int32_t index = shadow_frame.GetVReg(inst->VRegC_23x());
+    ObjPtr<mirror::ShortArray> array = a->AsShortArray();
+    if (array->CheckIsValidIndex(index)) {
+      array->SetWithoutChecks<transaction_active>(index, val);
+      inst = inst->Next_2xx();
+    } else {
+      HANDLE_PENDING_EXCEPTION();
+    }
+  }
+
+  ALWAYS_INLINE void APUT() REQUIRES_SHARED(Locks::mutator_lock_) {
+    PREAMBLE();
+    ObjPtr<mirror::Object> a = shadow_frame.GetVRegReference(inst->VRegB_23x());
+    if (UNLIKELY(a == nullptr)) {
+      ThrowNullPointerExceptionFromInterpreter();
+      HANDLE_PENDING_EXCEPTION();
+    }
+    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()) << a->PrettyTypeOf();
+    ObjPtr<mirror::IntArray> array = ObjPtr<mirror::IntArray>::DownCast(a);
+    if (array->CheckIsValidIndex(index)) {
+      array->SetWithoutChecks<transaction_active>(index, val);
+      inst = inst->Next_2xx();
+    } else {
+      HANDLE_PENDING_EXCEPTION();
+    }
+  }
+
+  ALWAYS_INLINE void APUT_WIDE() REQUIRES_SHARED(Locks::mutator_lock_) {
+    PREAMBLE();
+    ObjPtr<mirror::Object> a = shadow_frame.GetVRegReference(inst->VRegB_23x());
+    if (UNLIKELY(a == nullptr)) {
+      ThrowNullPointerExceptionFromInterpreter();
+      HANDLE_PENDING_EXCEPTION();
+    }
+    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()) << a->PrettyTypeOf();
+    ObjPtr<mirror::LongArray> array = ObjPtr<mirror::LongArray>::DownCast(a);
+    if (array->CheckIsValidIndex(index)) {
+      array->SetWithoutChecks<transaction_active>(index, val);
+      inst = inst->Next_2xx();
+    } else {
+      HANDLE_PENDING_EXCEPTION();
+    }
+  }
+
+  ALWAYS_INLINE void APUT_OBJECT() REQUIRES_SHARED(Locks::mutator_lock_) {
+    PREAMBLE();
+    ObjPtr<mirror::Object> a = shadow_frame.GetVRegReference(inst->VRegB_23x());
+    if (UNLIKELY(a == nullptr)) {
+      ThrowNullPointerExceptionFromInterpreter();
+      HANDLE_PENDING_EXCEPTION();
+    }
+    int32_t index = shadow_frame.GetVReg(inst->VRegC_23x());
+    ObjPtr<mirror::Object> val = shadow_frame.GetVRegReference(inst->VRegA_23x(inst_data));
+    ObjPtr<mirror::ObjectArray<mirror::Object>> array = a->AsObjectArray<mirror::Object>();
+    if (array->CheckIsValidIndex(index) && array->CheckAssignable(val)) {
+      array->SetWithoutChecks<transaction_active>(index, val);
+      inst = inst->Next_2xx();
+    } else {
+      HANDLE_PENDING_EXCEPTION();
+    }
+  }
+
+  ALWAYS_INLINE void IGET_BOOLEAN() REQUIRES_SHARED(Locks::mutator_lock_) {
+    PREAMBLE();
+    bool success = DoFieldGet<InstancePrimitiveRead, Primitive::kPrimBoolean, do_access_check>(
+        self, shadow_frame, inst, inst_data);
+    POSSIBLY_HANDLE_PENDING_EXCEPTION(!success, Next_2xx);
+  }
+
+  ALWAYS_INLINE void IGET_BYTE() REQUIRES_SHARED(Locks::mutator_lock_) {
+    PREAMBLE();
+    bool success = DoFieldGet<InstancePrimitiveRead, Primitive::kPrimByte, do_access_check>(
+        self, shadow_frame, inst, inst_data);
+    POSSIBLY_HANDLE_PENDING_EXCEPTION(!success, Next_2xx);
+  }
+
+  ALWAYS_INLINE void IGET_CHAR() REQUIRES_SHARED(Locks::mutator_lock_) {
+    PREAMBLE();
+    bool success = DoFieldGet<InstancePrimitiveRead, Primitive::kPrimChar, do_access_check>(
+        self, shadow_frame, inst, inst_data);
+    POSSIBLY_HANDLE_PENDING_EXCEPTION(!success, Next_2xx);
+  }
+
+  ALWAYS_INLINE void IGET_SHORT() REQUIRES_SHARED(Locks::mutator_lock_) {
+    PREAMBLE();
+    bool success = DoFieldGet<InstancePrimitiveRead, Primitive::kPrimShort, do_access_check>(
+        self, shadow_frame, inst, inst_data);
+    POSSIBLY_HANDLE_PENDING_EXCEPTION(!success, Next_2xx);
+  }
+
+  ALWAYS_INLINE void IGET() REQUIRES_SHARED(Locks::mutator_lock_) {
+    PREAMBLE();
+    bool success = DoFieldGet<InstancePrimitiveRead, Primitive::kPrimInt, do_access_check>(
+        self, shadow_frame, inst, inst_data);
+    POSSIBLY_HANDLE_PENDING_EXCEPTION(!success, Next_2xx);
+  }
+
+  ALWAYS_INLINE void IGET_WIDE() REQUIRES_SHARED(Locks::mutator_lock_) {
+    PREAMBLE();
+    bool success = DoFieldGet<InstancePrimitiveRead, Primitive::kPrimLong, do_access_check>(
+        self, shadow_frame, inst, inst_data);
+    POSSIBLY_HANDLE_PENDING_EXCEPTION(!success, Next_2xx);
+  }
+
+  ALWAYS_INLINE void IGET_OBJECT() REQUIRES_SHARED(Locks::mutator_lock_) {
+    PREAMBLE();
+    bool success = DoFieldGet<InstanceObjectRead, Primitive::kPrimNot, do_access_check>(
+        self, shadow_frame, inst, inst_data);
+    POSSIBLY_HANDLE_PENDING_EXCEPTION(!success, Next_2xx);
+  }
+
+  ALWAYS_INLINE void IGET_QUICK() REQUIRES_SHARED(Locks::mutator_lock_) {
+    PREAMBLE();
+    bool success = DoIGetQuick<Primitive::kPrimInt>(shadow_frame, inst, inst_data);
+    POSSIBLY_HANDLE_PENDING_EXCEPTION(!success, Next_2xx);
+  }
+
+  ALWAYS_INLINE void IGET_WIDE_QUICK() REQUIRES_SHARED(Locks::mutator_lock_) {
+    PREAMBLE();
+    bool success = DoIGetQuick<Primitive::kPrimLong>(shadow_frame, inst, inst_data);
+    POSSIBLY_HANDLE_PENDING_EXCEPTION(!success, Next_2xx);
+  }
+
+  ALWAYS_INLINE void IGET_OBJECT_QUICK() REQUIRES_SHARED(Locks::mutator_lock_) {
+    PREAMBLE();
+    bool success = DoIGetQuick<Primitive::kPrimNot>(shadow_frame, inst, inst_data);
+    POSSIBLY_HANDLE_PENDING_EXCEPTION(!success, Next_2xx);
+  }
+
+  ALWAYS_INLINE void IGET_BOOLEAN_QUICK() REQUIRES_SHARED(Locks::mutator_lock_) {
+    PREAMBLE();
+    bool success = DoIGetQuick<Primitive::kPrimBoolean>(shadow_frame, inst, inst_data);
+    POSSIBLY_HANDLE_PENDING_EXCEPTION(!success, Next_2xx);
+  }
+
+  ALWAYS_INLINE void IGET_BYTE_QUICK() REQUIRES_SHARED(Locks::mutator_lock_) {
+    PREAMBLE();
+    bool success = DoIGetQuick<Primitive::kPrimByte>(shadow_frame, inst, inst_data);
+    POSSIBLY_HANDLE_PENDING_EXCEPTION(!success, Next_2xx);
+  }
+
+  ALWAYS_INLINE void IGET_CHAR_QUICK() REQUIRES_SHARED(Locks::mutator_lock_) {
+    PREAMBLE();
+    bool success = DoIGetQuick<Primitive::kPrimChar>(shadow_frame, inst, inst_data);
+    POSSIBLY_HANDLE_PENDING_EXCEPTION(!success, Next_2xx);
+  }
+
+  ALWAYS_INLINE void IGET_SHORT_QUICK() REQUIRES_SHARED(Locks::mutator_lock_) {
+    PREAMBLE();
+    bool success = DoIGetQuick<Primitive::kPrimShort>(shadow_frame, inst, inst_data);
+    POSSIBLY_HANDLE_PENDING_EXCEPTION(!success, Next_2xx);
+  }
+
+  ALWAYS_INLINE void SGET_BOOLEAN() REQUIRES_SHARED(Locks::mutator_lock_) {
+    PREAMBLE();
+    bool success = DoFieldGet<StaticPrimitiveRead, Primitive::kPrimBoolean, do_access_check,
+        transaction_active>(self, shadow_frame, inst, inst_data);
+    POSSIBLY_HANDLE_PENDING_EXCEPTION(!success, Next_2xx);
+  }
+
+  ALWAYS_INLINE void SGET_BYTE() REQUIRES_SHARED(Locks::mutator_lock_) {
+    PREAMBLE();
+    bool success = DoFieldGet<StaticPrimitiveRead, Primitive::kPrimByte, do_access_check,
+        transaction_active>(self, shadow_frame, inst, inst_data);
+    POSSIBLY_HANDLE_PENDING_EXCEPTION(!success, Next_2xx);
+  }
+
+  ALWAYS_INLINE void SGET_CHAR() REQUIRES_SHARED(Locks::mutator_lock_) {
+    PREAMBLE();
+    bool success = DoFieldGet<StaticPrimitiveRead, Primitive::kPrimChar, do_access_check,
+        transaction_active>(self, shadow_frame, inst, inst_data);
+    POSSIBLY_HANDLE_PENDING_EXCEPTION(!success, Next_2xx);
+  }
+
+  ALWAYS_INLINE void SGET_SHORT() REQUIRES_SHARED(Locks::mutator_lock_) {
+    PREAMBLE();
+    bool success = DoFieldGet<StaticPrimitiveRead, Primitive::kPrimShort, do_access_check,
+        transaction_active>(self, shadow_frame, inst, inst_data);
+    POSSIBLY_HANDLE_PENDING_EXCEPTION(!success, Next_2xx);
+  }
+
+  ALWAYS_INLINE void SGET() REQUIRES_SHARED(Locks::mutator_lock_) {
+    PREAMBLE();
+    bool success = DoFieldGet<StaticPrimitiveRead, Primitive::kPrimInt, do_access_check,
+        transaction_active>(self, shadow_frame, inst, inst_data);
+    POSSIBLY_HANDLE_PENDING_EXCEPTION(!success, Next_2xx);
+  }
+
+  ALWAYS_INLINE void SGET_WIDE() REQUIRES_SHARED(Locks::mutator_lock_) {
+    PREAMBLE();
+    bool success = DoFieldGet<StaticPrimitiveRead, Primitive::kPrimLong, do_access_check,
+        transaction_active>(self, shadow_frame, inst, inst_data);
+    POSSIBLY_HANDLE_PENDING_EXCEPTION(!success, Next_2xx);
+  }
+
+  ALWAYS_INLINE void SGET_OBJECT() REQUIRES_SHARED(Locks::mutator_lock_) {
+    PREAMBLE();
+    bool success = DoFieldGet<StaticObjectRead, Primitive::kPrimNot, do_access_check,
+        transaction_active>(self, shadow_frame, inst, inst_data);
+    POSSIBLY_HANDLE_PENDING_EXCEPTION(!success, Next_2xx);
+  }
+
+  ALWAYS_INLINE void IPUT_BOOLEAN() REQUIRES_SHARED(Locks::mutator_lock_) {
+    PREAMBLE();
+    bool success = DoFieldPut<InstancePrimitiveWrite, Primitive::kPrimBoolean, do_access_check,
+        transaction_active>(self, shadow_frame, inst, inst_data);
+    POSSIBLY_HANDLE_PENDING_EXCEPTION(!success, Next_2xx);
+  }
+
+  ALWAYS_INLINE void IPUT_BYTE() REQUIRES_SHARED(Locks::mutator_lock_) {
+    PREAMBLE();
+    bool success = DoFieldPut<InstancePrimitiveWrite, Primitive::kPrimByte, do_access_check,
+        transaction_active>(self, shadow_frame, inst, inst_data);
+    POSSIBLY_HANDLE_PENDING_EXCEPTION(!success, Next_2xx);
+  }
+
+  ALWAYS_INLINE void IPUT_CHAR() REQUIRES_SHARED(Locks::mutator_lock_) {
+    PREAMBLE();
+    bool success = DoFieldPut<InstancePrimitiveWrite, Primitive::kPrimChar, do_access_check,
+        transaction_active>(self, shadow_frame, inst, inst_data);
+    POSSIBLY_HANDLE_PENDING_EXCEPTION(!success, Next_2xx);
+  }
+
+  ALWAYS_INLINE void IPUT_SHORT() REQUIRES_SHARED(Locks::mutator_lock_) {
+    PREAMBLE();
+    bool success = DoFieldPut<InstancePrimitiveWrite, Primitive::kPrimShort, do_access_check,
+        transaction_active>(self, shadow_frame, inst, inst_data);
+    POSSIBLY_HANDLE_PENDING_EXCEPTION(!success, Next_2xx);
+  }
+
+  ALWAYS_INLINE void IPUT() REQUIRES_SHARED(Locks::mutator_lock_) {
+    PREAMBLE();
+    bool success = DoFieldPut<InstancePrimitiveWrite, Primitive::kPrimInt, do_access_check,
+        transaction_active>(self, shadow_frame, inst, inst_data);
+    POSSIBLY_HANDLE_PENDING_EXCEPTION(!success, Next_2xx);
+  }
+
+  ALWAYS_INLINE void IPUT_WIDE() REQUIRES_SHARED(Locks::mutator_lock_) {
+    PREAMBLE();
+    bool success = DoFieldPut<InstancePrimitiveWrite, Primitive::kPrimLong, do_access_check,
+        transaction_active>(self, shadow_frame, inst, inst_data);
+    POSSIBLY_HANDLE_PENDING_EXCEPTION(!success, Next_2xx);
+  }
+
+  ALWAYS_INLINE void IPUT_OBJECT() REQUIRES_SHARED(Locks::mutator_lock_) {
+    PREAMBLE();
+    bool success = DoFieldPut<InstanceObjectWrite, Primitive::kPrimNot, do_access_check,
+        transaction_active>(self, shadow_frame, inst, inst_data);
+    POSSIBLY_HANDLE_PENDING_EXCEPTION(!success, Next_2xx);
+  }
+
+  ALWAYS_INLINE void IPUT_QUICK() REQUIRES_SHARED(Locks::mutator_lock_) {
+    PREAMBLE();
+    bool success = DoIPutQuick<Primitive::kPrimInt, transaction_active>(
+        shadow_frame, inst, inst_data);
+    POSSIBLY_HANDLE_PENDING_EXCEPTION(!success, Next_2xx);
+  }
+
+  ALWAYS_INLINE void IPUT_BOOLEAN_QUICK() REQUIRES_SHARED(Locks::mutator_lock_) {
+    PREAMBLE();
+    bool success = DoIPutQuick<Primitive::kPrimBoolean, transaction_active>(
+        shadow_frame, inst, inst_data);
+    POSSIBLY_HANDLE_PENDING_EXCEPTION(!success, Next_2xx);
+  }
+
+  ALWAYS_INLINE void IPUT_BYTE_QUICK() REQUIRES_SHARED(Locks::mutator_lock_) {
+    PREAMBLE();
+    bool success = DoIPutQuick<Primitive::kPrimByte, transaction_active>(
+        shadow_frame, inst, inst_data);
+    POSSIBLY_HANDLE_PENDING_EXCEPTION(!success, Next_2xx);
+  }
+
+  ALWAYS_INLINE void IPUT_CHAR_QUICK() REQUIRES_SHARED(Locks::mutator_lock_) {
+    PREAMBLE();
+    bool success = DoIPutQuick<Primitive::kPrimChar, transaction_active>(
+        shadow_frame, inst, inst_data);
+    POSSIBLY_HANDLE_PENDING_EXCEPTION(!success, Next_2xx);
+  }
+
+  ALWAYS_INLINE void IPUT_SHORT_QUICK() REQUIRES_SHARED(Locks::mutator_lock_) {
+    PREAMBLE();
+    bool success = DoIPutQuick<Primitive::kPrimShort, transaction_active>(
+        shadow_frame, inst, inst_data);
+    POSSIBLY_HANDLE_PENDING_EXCEPTION(!success, Next_2xx);
+  }
+
+  ALWAYS_INLINE void IPUT_WIDE_QUICK() REQUIRES_SHARED(Locks::mutator_lock_) {
+    PREAMBLE();
+    bool success = DoIPutQuick<Primitive::kPrimLong, transaction_active>(
+        shadow_frame, inst, inst_data);
+    POSSIBLY_HANDLE_PENDING_EXCEPTION(!success, Next_2xx);
+  }
+
+  ALWAYS_INLINE void IPUT_OBJECT_QUICK() REQUIRES_SHARED(Locks::mutator_lock_) {
+    PREAMBLE();
+    bool success = DoIPutQuick<Primitive::kPrimNot, transaction_active>(
+        shadow_frame, inst, inst_data);
+    POSSIBLY_HANDLE_PENDING_EXCEPTION(!success, Next_2xx);
+  }
+
+  ALWAYS_INLINE void SPUT_BOOLEAN() REQUIRES_SHARED(Locks::mutator_lock_) {
+    PREAMBLE();
+    bool success = DoFieldPut<StaticPrimitiveWrite, Primitive::kPrimBoolean, do_access_check,
+        transaction_active>(self, shadow_frame, inst, inst_data);
+    POSSIBLY_HANDLE_PENDING_EXCEPTION(!success, Next_2xx);
+  }
+
+  ALWAYS_INLINE void SPUT_BYTE() REQUIRES_SHARED(Locks::mutator_lock_) {
+    PREAMBLE();
+    bool success = DoFieldPut<StaticPrimitiveWrite, Primitive::kPrimByte, do_access_check,
+        transaction_active>(self, shadow_frame, inst, inst_data);
+    POSSIBLY_HANDLE_PENDING_EXCEPTION(!success, Next_2xx);
+  }
+
+  ALWAYS_INLINE void SPUT_CHAR() REQUIRES_SHARED(Locks::mutator_lock_) {
+    PREAMBLE();
+    bool success = DoFieldPut<StaticPrimitiveWrite, Primitive::kPrimChar, do_access_check,
+        transaction_active>(self, shadow_frame, inst, inst_data);
+    POSSIBLY_HANDLE_PENDING_EXCEPTION(!success, Next_2xx);
+  }
+
+  ALWAYS_INLINE void SPUT_SHORT() REQUIRES_SHARED(Locks::mutator_lock_) {
+    PREAMBLE();
+    bool success = DoFieldPut<StaticPrimitiveWrite, Primitive::kPrimShort, do_access_check,
+        transaction_active>(self, shadow_frame, inst, inst_data);
+    POSSIBLY_HANDLE_PENDING_EXCEPTION(!success, Next_2xx);
+  }
+
+  ALWAYS_INLINE void SPUT() REQUIRES_SHARED(Locks::mutator_lock_) {
+    PREAMBLE();
+    bool success = DoFieldPut<StaticPrimitiveWrite, Primitive::kPrimInt, do_access_check,
+        transaction_active>(self, shadow_frame, inst, inst_data);
+    POSSIBLY_HANDLE_PENDING_EXCEPTION(!success, Next_2xx);
+  }
+
+  ALWAYS_INLINE void SPUT_WIDE() REQUIRES_SHARED(Locks::mutator_lock_) {
+    PREAMBLE();
+    bool success = DoFieldPut<StaticPrimitiveWrite, Primitive::kPrimLong, do_access_check,
+        transaction_active>(self, shadow_frame, inst, inst_data);
+    POSSIBLY_HANDLE_PENDING_EXCEPTION(!success, Next_2xx);
+  }
+
+  ALWAYS_INLINE void SPUT_OBJECT() REQUIRES_SHARED(Locks::mutator_lock_) {
+    PREAMBLE();
+    bool success = DoFieldPut<StaticObjectWrite, Primitive::kPrimNot, do_access_check,
+        transaction_active>(self, shadow_frame, inst, inst_data);
+    POSSIBLY_HANDLE_PENDING_EXCEPTION(!success, Next_2xx);
+  }
+
+  ALWAYS_INLINE void INVOKE_VIRTUAL() REQUIRES_SHARED(Locks::mutator_lock_) {
+    PREAMBLE();
+    bool success = DoInvoke<kVirtual, false, do_access_check, /*is_mterp=*/ false>(
+        self, shadow_frame, inst, inst_data, ResultRegister());
+    POSSIBLY_HANDLE_PENDING_EXCEPTION_ON_INVOKE(!success);
+  }
+
+  ALWAYS_INLINE void INVOKE_VIRTUAL_RANGE() REQUIRES_SHARED(Locks::mutator_lock_) {
+    PREAMBLE();
+    bool success = DoInvoke<kVirtual, true, do_access_check, /*is_mterp=*/ false>(
+        self, shadow_frame, inst, inst_data, ResultRegister());
+    POSSIBLY_HANDLE_PENDING_EXCEPTION_ON_INVOKE(!success);
+  }
+
+  ALWAYS_INLINE void INVOKE_SUPER() REQUIRES_SHARED(Locks::mutator_lock_) {
+    PREAMBLE();
+    bool success = DoInvoke<kSuper, false, do_access_check, /*is_mterp=*/ false>(
+        self, shadow_frame, inst, inst_data, ResultRegister());
+    POSSIBLY_HANDLE_PENDING_EXCEPTION_ON_INVOKE(!success);
+  }
+
+  ALWAYS_INLINE void INVOKE_SUPER_RANGE() REQUIRES_SHARED(Locks::mutator_lock_) {
+    PREAMBLE();
+    bool success = DoInvoke<kSuper, true, do_access_check, /*is_mterp=*/ false>(
+        self, shadow_frame, inst, inst_data, ResultRegister());
+    POSSIBLY_HANDLE_PENDING_EXCEPTION_ON_INVOKE(!success);
+  }
+
+  ALWAYS_INLINE void INVOKE_DIRECT() REQUIRES_SHARED(Locks::mutator_lock_) {
+    PREAMBLE();
+    bool success = DoInvoke<kDirect, false, do_access_check, /*is_mterp=*/ false>(
+        self, shadow_frame, inst, inst_data, ResultRegister());
+    POSSIBLY_HANDLE_PENDING_EXCEPTION_ON_INVOKE(!success);
+  }
+
+  ALWAYS_INLINE void INVOKE_DIRECT_RANGE() REQUIRES_SHARED(Locks::mutator_lock_) {
+    PREAMBLE();
+    bool success = DoInvoke<kDirect, true, do_access_check, /*is_mterp=*/ false>(
+        self, shadow_frame, inst, inst_data, ResultRegister());
+    POSSIBLY_HANDLE_PENDING_EXCEPTION_ON_INVOKE(!success);
+  }
+
+  ALWAYS_INLINE void INVOKE_INTERFACE() REQUIRES_SHARED(Locks::mutator_lock_) {
+    PREAMBLE();
+    bool success = DoInvoke<kInterface, false, do_access_check, /*is_mterp=*/ false>(
+        self, shadow_frame, inst, inst_data, ResultRegister());
+    POSSIBLY_HANDLE_PENDING_EXCEPTION_ON_INVOKE(!success);
+  }
+
+  ALWAYS_INLINE void INVOKE_INTERFACE_RANGE() REQUIRES_SHARED(Locks::mutator_lock_) {
+    PREAMBLE();
+    bool success = DoInvoke<kInterface, true, do_access_check, /*is_mterp=*/ false>(
+        self, shadow_frame, inst, inst_data, ResultRegister());
+    POSSIBLY_HANDLE_PENDING_EXCEPTION_ON_INVOKE(!success);
+  }
+
+  ALWAYS_INLINE void INVOKE_STATIC() REQUIRES_SHARED(Locks::mutator_lock_) {
+    PREAMBLE();
+    bool success = DoInvoke<kStatic, false, do_access_check, /*is_mterp=*/ false>(
+        self, shadow_frame, inst, inst_data, ResultRegister());
+    POSSIBLY_HANDLE_PENDING_EXCEPTION_ON_INVOKE(!success);
+  }
+
+  ALWAYS_INLINE void INVOKE_STATIC_RANGE() REQUIRES_SHARED(Locks::mutator_lock_) {
+    PREAMBLE();
+    bool success = DoInvoke<kStatic, true, do_access_check, /*is_mterp=*/ false>(
+        self, shadow_frame, inst, inst_data, ResultRegister());
+    POSSIBLY_HANDLE_PENDING_EXCEPTION_ON_INVOKE(!success);
+  }
+
+  ALWAYS_INLINE void INVOKE_VIRTUAL_QUICK() REQUIRES_SHARED(Locks::mutator_lock_) {
+    PREAMBLE();
+    bool success = DoInvoke<kVirtual, false, do_access_check, /*is_mterp=*/ false,
+        /*is_quick=*/ true>(self, shadow_frame, inst, inst_data, ResultRegister());
+    POSSIBLY_HANDLE_PENDING_EXCEPTION_ON_INVOKE(!success);
+  }
+
+  ALWAYS_INLINE void INVOKE_VIRTUAL_RANGE_QUICK() REQUIRES_SHARED(Locks::mutator_lock_) {
+    PREAMBLE();
+    bool success = DoInvoke<kVirtual, true, do_access_check, /*is_mterp=*/ false,
+        /*is_quick=*/ true>(self, shadow_frame, inst, inst_data, ResultRegister());
+    POSSIBLY_HANDLE_PENDING_EXCEPTION_ON_INVOKE(!success);
+  }
+
+  ALWAYS_INLINE void INVOKE_POLYMORPHIC() REQUIRES_SHARED(Locks::mutator_lock_) {
+    PREAMBLE();
+    DCHECK(Runtime::Current()->IsMethodHandlesEnabled());
+    bool success = DoInvokePolymorphic</* is_range= */ false>(
+        self, shadow_frame, inst, inst_data, ResultRegister());
+    POSSIBLY_HANDLE_PENDING_EXCEPTION_ON_INVOKE_POLYMORPHIC(!success);
+  }
+
+  ALWAYS_INLINE void INVOKE_POLYMORPHIC_RANGE() REQUIRES_SHARED(Locks::mutator_lock_) {
+    PREAMBLE();
+    DCHECK(Runtime::Current()->IsMethodHandlesEnabled());
+    bool success = DoInvokePolymorphic</* is_range= */ true>(
+        self, shadow_frame, inst, inst_data, ResultRegister());
+    POSSIBLY_HANDLE_PENDING_EXCEPTION_ON_INVOKE_POLYMORPHIC(!success);
+  }
+
+  ALWAYS_INLINE void INVOKE_CUSTOM() REQUIRES_SHARED(Locks::mutator_lock_) {
+    PREAMBLE();
+    DCHECK(Runtime::Current()->IsMethodHandlesEnabled());
+    bool success = DoInvokeCustom</* is_range= */ false>(
+        self, shadow_frame, inst, inst_data, ResultRegister());
+    POSSIBLY_HANDLE_PENDING_EXCEPTION_ON_INVOKE(!success);
+  }
+
+  ALWAYS_INLINE void INVOKE_CUSTOM_RANGE() REQUIRES_SHARED(Locks::mutator_lock_) {
+    PREAMBLE();
+    DCHECK(Runtime::Current()->IsMethodHandlesEnabled());
+    bool success = DoInvokeCustom</* is_range= */ true>(
+        self, shadow_frame, inst, inst_data, ResultRegister());
+    POSSIBLY_HANDLE_PENDING_EXCEPTION_ON_INVOKE(!success);
+  }
+
+  ALWAYS_INLINE void NEG_INT() REQUIRES_SHARED(Locks::mutator_lock_) {
+    PREAMBLE();
+    shadow_frame.SetVReg(
+        inst->VRegA_12x(inst_data), -shadow_frame.GetVReg(inst->VRegB_12x(inst_data)));
+    inst = inst->Next_1xx();
+  }
+
+  ALWAYS_INLINE void NOT_INT() REQUIRES_SHARED(Locks::mutator_lock_) {
+    PREAMBLE();
+    shadow_frame.SetVReg(
+        inst->VRegA_12x(inst_data), ~shadow_frame.GetVReg(inst->VRegB_12x(inst_data)));
+    inst = inst->Next_1xx();
+  }
+
+  ALWAYS_INLINE void NEG_LONG() REQUIRES_SHARED(Locks::mutator_lock_) {
+    PREAMBLE();
+    shadow_frame.SetVRegLong(
+        inst->VRegA_12x(inst_data), -shadow_frame.GetVRegLong(inst->VRegB_12x(inst_data)));
+    inst = inst->Next_1xx();
+  }
+
+  ALWAYS_INLINE void NOT_LONG() REQUIRES_SHARED(Locks::mutator_lock_) {
+    PREAMBLE();
+    shadow_frame.SetVRegLong(
+        inst->VRegA_12x(inst_data), ~shadow_frame.GetVRegLong(inst->VRegB_12x(inst_data)));
+    inst = inst->Next_1xx();
+  }
+
+  ALWAYS_INLINE void NEG_FLOAT() REQUIRES_SHARED(Locks::mutator_lock_) {
+    PREAMBLE();
+    shadow_frame.SetVRegFloat(
+        inst->VRegA_12x(inst_data), -shadow_frame.GetVRegFloat(inst->VRegB_12x(inst_data)));
+    inst = inst->Next_1xx();
+  }
+
+  ALWAYS_INLINE void NEG_DOUBLE() REQUIRES_SHARED(Locks::mutator_lock_) {
+    PREAMBLE();
+    shadow_frame.SetVRegDouble(
+        inst->VRegA_12x(inst_data), -shadow_frame.GetVRegDouble(inst->VRegB_12x(inst_data)));
+    inst = inst->Next_1xx();
+  }
+
+  ALWAYS_INLINE void INT_TO_LONG() REQUIRES_SHARED(Locks::mutator_lock_) {
+    PREAMBLE();
+    shadow_frame.SetVRegLong(inst->VRegA_12x(inst_data),
+                             shadow_frame.GetVReg(inst->VRegB_12x(inst_data)));
+    inst = inst->Next_1xx();
+  }
+
+  ALWAYS_INLINE void INT_TO_FLOAT() REQUIRES_SHARED(Locks::mutator_lock_) {
+    PREAMBLE();
+    shadow_frame.SetVRegFloat(inst->VRegA_12x(inst_data),
+                              shadow_frame.GetVReg(inst->VRegB_12x(inst_data)));
+    inst = inst->Next_1xx();
+  }
+
+  ALWAYS_INLINE void INT_TO_DOUBLE() REQUIRES_SHARED(Locks::mutator_lock_) {
+    PREAMBLE();
+    shadow_frame.SetVRegDouble(inst->VRegA_12x(inst_data),
+                               shadow_frame.GetVReg(inst->VRegB_12x(inst_data)));
+    inst = inst->Next_1xx();
+  }
+
+  ALWAYS_INLINE void LONG_TO_INT() REQUIRES_SHARED(Locks::mutator_lock_) {
+    PREAMBLE();
+    shadow_frame.SetVReg(inst->VRegA_12x(inst_data),
+                         shadow_frame.GetVRegLong(inst->VRegB_12x(inst_data)));
+    inst = inst->Next_1xx();
+  }
+
+  ALWAYS_INLINE void LONG_TO_FLOAT() REQUIRES_SHARED(Locks::mutator_lock_) {
+    PREAMBLE();
+    shadow_frame.SetVRegFloat(inst->VRegA_12x(inst_data),
+                              shadow_frame.GetVRegLong(inst->VRegB_12x(inst_data)));
+    inst = inst->Next_1xx();
+  }
+
+  ALWAYS_INLINE void LONG_TO_DOUBLE() REQUIRES_SHARED(Locks::mutator_lock_) {
+    PREAMBLE();
+    shadow_frame.SetVRegDouble(inst->VRegA_12x(inst_data),
+                               shadow_frame.GetVRegLong(inst->VRegB_12x(inst_data)));
+    inst = inst->Next_1xx();
+  }
+
+  ALWAYS_INLINE void FLOAT_TO_INT() REQUIRES_SHARED(Locks::mutator_lock_) {
+    PREAMBLE();
+    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);
+    inst = inst->Next_1xx();
+  }
+
+  ALWAYS_INLINE void FLOAT_TO_LONG() REQUIRES_SHARED(Locks::mutator_lock_) {
+    PREAMBLE();
+    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);
+    inst = inst->Next_1xx();
+  }
+
+  ALWAYS_INLINE void FLOAT_TO_DOUBLE() REQUIRES_SHARED(Locks::mutator_lock_) {
+    PREAMBLE();
+    shadow_frame.SetVRegDouble(inst->VRegA_12x(inst_data),
+                               shadow_frame.GetVRegFloat(inst->VRegB_12x(inst_data)));
+    inst = inst->Next_1xx();
+  }
+
+  ALWAYS_INLINE void DOUBLE_TO_INT() REQUIRES_SHARED(Locks::mutator_lock_) {
+    PREAMBLE();
+    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);
+    inst = inst->Next_1xx();
+  }
+
+  ALWAYS_INLINE void DOUBLE_TO_LONG() REQUIRES_SHARED(Locks::mutator_lock_) {
+    PREAMBLE();
+    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);
+    inst = inst->Next_1xx();
+  }
+
+  ALWAYS_INLINE void DOUBLE_TO_FLOAT() REQUIRES_SHARED(Locks::mutator_lock_) {
+    PREAMBLE();
+    shadow_frame.SetVRegFloat(inst->VRegA_12x(inst_data),
+                              shadow_frame.GetVRegDouble(inst->VRegB_12x(inst_data)));
+    inst = inst->Next_1xx();
+  }
+
+  ALWAYS_INLINE void INT_TO_BYTE() REQUIRES_SHARED(Locks::mutator_lock_) {
+    PREAMBLE();
+    shadow_frame.SetVReg(inst->VRegA_12x(inst_data), static_cast<int8_t>(
+        shadow_frame.GetVReg(inst->VRegB_12x(inst_data))));
+    inst = inst->Next_1xx();
+  }
+
+  ALWAYS_INLINE void INT_TO_CHAR() REQUIRES_SHARED(Locks::mutator_lock_) {
+    PREAMBLE();
+    shadow_frame.SetVReg(inst->VRegA_12x(inst_data), static_cast<uint16_t>(
+        shadow_frame.GetVReg(inst->VRegB_12x(inst_data))));
+    inst = inst->Next_1xx();
+  }
+
+  ALWAYS_INLINE void INT_TO_SHORT() REQUIRES_SHARED(Locks::mutator_lock_) {
+    PREAMBLE();
+    shadow_frame.SetVReg(inst->VRegA_12x(inst_data), static_cast<int16_t>(
+        shadow_frame.GetVReg(inst->VRegB_12x(inst_data))));
+    inst = inst->Next_1xx();
+  }
+
+  ALWAYS_INLINE void ADD_INT() REQUIRES_SHARED(Locks::mutator_lock_) {
+    PREAMBLE();
+    shadow_frame.SetVReg(inst->VRegA_23x(inst_data),
+                         SafeAdd(shadow_frame.GetVReg(inst->VRegB_23x()),
+                                 shadow_frame.GetVReg(inst->VRegC_23x())));
+    inst = inst->Next_2xx();
+  }
+
+  ALWAYS_INLINE void SUB_INT() REQUIRES_SHARED(Locks::mutator_lock_) {
+    PREAMBLE();
+    shadow_frame.SetVReg(inst->VRegA_23x(inst_data),
+                         SafeSub(shadow_frame.GetVReg(inst->VRegB_23x()),
+                                 shadow_frame.GetVReg(inst->VRegC_23x())));
+    inst = inst->Next_2xx();
+  }
+
+  ALWAYS_INLINE void MUL_INT() REQUIRES_SHARED(Locks::mutator_lock_) {
+    PREAMBLE();
+    shadow_frame.SetVReg(inst->VRegA_23x(inst_data),
+                         SafeMul(shadow_frame.GetVReg(inst->VRegB_23x()),
+                                 shadow_frame.GetVReg(inst->VRegC_23x())));
+    inst = inst->Next_2xx();
+  }
+
+  ALWAYS_INLINE void DIV_INT() REQUIRES_SHARED(Locks::mutator_lock_) {
+    PREAMBLE();
+    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, Next_2xx);
+  }
+
+  ALWAYS_INLINE void REM_INT() REQUIRES_SHARED(Locks::mutator_lock_) {
+    PREAMBLE();
+    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, Next_2xx);
+  }
+
+  ALWAYS_INLINE void SHL_INT() REQUIRES_SHARED(Locks::mutator_lock_) {
+    PREAMBLE();
+    shadow_frame.SetVReg(inst->VRegA_23x(inst_data),
+                         shadow_frame.GetVReg(inst->VRegB_23x()) <<
+                         (shadow_frame.GetVReg(inst->VRegC_23x()) & 0x1f));
+    inst = inst->Next_2xx();
+  }
+
+  ALWAYS_INLINE void SHR_INT() REQUIRES_SHARED(Locks::mutator_lock_) {
+    PREAMBLE();
+    shadow_frame.SetVReg(inst->VRegA_23x(inst_data),
+                         shadow_frame.GetVReg(inst->VRegB_23x()) >>
+                         (shadow_frame.GetVReg(inst->VRegC_23x()) & 0x1f));
+    inst = inst->Next_2xx();
+  }
+
+  ALWAYS_INLINE void USHR_INT() REQUIRES_SHARED(Locks::mutator_lock_) {
+    PREAMBLE();
+    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));
+    inst = inst->Next_2xx();
+  }
+
+  ALWAYS_INLINE void AND_INT() REQUIRES_SHARED(Locks::mutator_lock_) {
+    PREAMBLE();
+    shadow_frame.SetVReg(inst->VRegA_23x(inst_data),
+                         shadow_frame.GetVReg(inst->VRegB_23x()) &
+                         shadow_frame.GetVReg(inst->VRegC_23x()));
+    inst = inst->Next_2xx();
+  }
+
+  ALWAYS_INLINE void OR_INT() REQUIRES_SHARED(Locks::mutator_lock_) {
+    PREAMBLE();
+    shadow_frame.SetVReg(inst->VRegA_23x(inst_data),
+                         shadow_frame.GetVReg(inst->VRegB_23x()) |
+                         shadow_frame.GetVReg(inst->VRegC_23x()));
+    inst = inst->Next_2xx();
+  }
+
+  ALWAYS_INLINE void XOR_INT() REQUIRES_SHARED(Locks::mutator_lock_) {
+    PREAMBLE();
+    shadow_frame.SetVReg(inst->VRegA_23x(inst_data),
+                         shadow_frame.GetVReg(inst->VRegB_23x()) ^
+                         shadow_frame.GetVReg(inst->VRegC_23x()));
+    inst = inst->Next_2xx();
+  }
+
+  ALWAYS_INLINE void ADD_LONG() REQUIRES_SHARED(Locks::mutator_lock_) {
+    PREAMBLE();
+    shadow_frame.SetVRegLong(inst->VRegA_23x(inst_data),
+                             SafeAdd(shadow_frame.GetVRegLong(inst->VRegB_23x()),
+                                     shadow_frame.GetVRegLong(inst->VRegC_23x())));
+    inst = inst->Next_2xx();
+  }
+
+  ALWAYS_INLINE void SUB_LONG() REQUIRES_SHARED(Locks::mutator_lock_) {
+    PREAMBLE();
+    shadow_frame.SetVRegLong(inst->VRegA_23x(inst_data),
+                             SafeSub(shadow_frame.GetVRegLong(inst->VRegB_23x()),
+                                     shadow_frame.GetVRegLong(inst->VRegC_23x())));
+    inst = inst->Next_2xx();
+  }
+
+  ALWAYS_INLINE void MUL_LONG() REQUIRES_SHARED(Locks::mutator_lock_) {
+    PREAMBLE();
+    shadow_frame.SetVRegLong(inst->VRegA_23x(inst_data),
+                             SafeMul(shadow_frame.GetVRegLong(inst->VRegB_23x()),
+                                     shadow_frame.GetVRegLong(inst->VRegC_23x())));
+    inst = inst->Next_2xx();
+  }
+
+  ALWAYS_INLINE void DIV_LONG() REQUIRES_SHARED(Locks::mutator_lock_) {
+    PREAMBLE();
+    DoLongDivide(shadow_frame, inst->VRegA_23x(inst_data),
+                 shadow_frame.GetVRegLong(inst->VRegB_23x()),
+                 shadow_frame.GetVRegLong(inst->VRegC_23x()));
+    POSSIBLY_HANDLE_PENDING_EXCEPTION(self->IsExceptionPending(), Next_2xx);
+  }
+
+  ALWAYS_INLINE void REM_LONG() REQUIRES_SHARED(Locks::mutator_lock_) {
+    PREAMBLE();
+    DoLongRemainder(shadow_frame, inst->VRegA_23x(inst_data),
+                    shadow_frame.GetVRegLong(inst->VRegB_23x()),
+                    shadow_frame.GetVRegLong(inst->VRegC_23x()));
+    POSSIBLY_HANDLE_PENDING_EXCEPTION(self->IsExceptionPending(), Next_2xx);
+  }
+
+  ALWAYS_INLINE void AND_LONG() REQUIRES_SHARED(Locks::mutator_lock_) {
+    PREAMBLE();
+    shadow_frame.SetVRegLong(inst->VRegA_23x(inst_data),
+                             shadow_frame.GetVRegLong(inst->VRegB_23x()) &
+                             shadow_frame.GetVRegLong(inst->VRegC_23x()));
+    inst = inst->Next_2xx();
+  }
+
+  ALWAYS_INLINE void OR_LONG() REQUIRES_SHARED(Locks::mutator_lock_) {
+    PREAMBLE();
+    shadow_frame.SetVRegLong(inst->VRegA_23x(inst_data),
+                             shadow_frame.GetVRegLong(inst->VRegB_23x()) |
+                             shadow_frame.GetVRegLong(inst->VRegC_23x()));
+    inst = inst->Next_2xx();
+  }
+
+  ALWAYS_INLINE void XOR_LONG() REQUIRES_SHARED(Locks::mutator_lock_) {
+    PREAMBLE();
+    shadow_frame.SetVRegLong(inst->VRegA_23x(inst_data),
+                             shadow_frame.GetVRegLong(inst->VRegB_23x()) ^
+                             shadow_frame.GetVRegLong(inst->VRegC_23x()));
+    inst = inst->Next_2xx();
+  }
+
+  ALWAYS_INLINE void SHL_LONG() REQUIRES_SHARED(Locks::mutator_lock_) {
+    PREAMBLE();
+    shadow_frame.SetVRegLong(inst->VRegA_23x(inst_data),
+                             shadow_frame.GetVRegLong(inst->VRegB_23x()) <<
+                             (shadow_frame.GetVReg(inst->VRegC_23x()) & 0x3f));
+    inst = inst->Next_2xx();
+  }
+
+  ALWAYS_INLINE void SHR_LONG() REQUIRES_SHARED(Locks::mutator_lock_) {
+    PREAMBLE();
+    shadow_frame.SetVRegLong(inst->VRegA_23x(inst_data),
+                             shadow_frame.GetVRegLong(inst->VRegB_23x()) >>
+                             (shadow_frame.GetVReg(inst->VRegC_23x()) & 0x3f));
+    inst = inst->Next_2xx();
+  }
+
+  ALWAYS_INLINE void USHR_LONG() REQUIRES_SHARED(Locks::mutator_lock_) {
+    PREAMBLE();
+    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));
+    inst = inst->Next_2xx();
+  }
+
+  ALWAYS_INLINE void ADD_FLOAT() REQUIRES_SHARED(Locks::mutator_lock_) {
+    PREAMBLE();
+    shadow_frame.SetVRegFloat(inst->VRegA_23x(inst_data),
+                              shadow_frame.GetVRegFloat(inst->VRegB_23x()) +
+                              shadow_frame.GetVRegFloat(inst->VRegC_23x()));
+    inst = inst->Next_2xx();
+  }
+
+  ALWAYS_INLINE void SUB_FLOAT() REQUIRES_SHARED(Locks::mutator_lock_) {
+    PREAMBLE();
+    shadow_frame.SetVRegFloat(inst->VRegA_23x(inst_data),
+                              shadow_frame.GetVRegFloat(inst->VRegB_23x()) -
+                              shadow_frame.GetVRegFloat(inst->VRegC_23x()));
+    inst = inst->Next_2xx();
+  }
+
+  ALWAYS_INLINE void MUL_FLOAT() REQUIRES_SHARED(Locks::mutator_lock_) {
+    PREAMBLE();
+    shadow_frame.SetVRegFloat(inst->VRegA_23x(inst_data),
+                              shadow_frame.GetVRegFloat(inst->VRegB_23x()) *
+                              shadow_frame.GetVRegFloat(inst->VRegC_23x()));
+    inst = inst->Next_2xx();
+  }
+
+  ALWAYS_INLINE void DIV_FLOAT() REQUIRES_SHARED(Locks::mutator_lock_) {
+    PREAMBLE();
+    shadow_frame.SetVRegFloat(inst->VRegA_23x(inst_data),
+                              shadow_frame.GetVRegFloat(inst->VRegB_23x()) /
+                              shadow_frame.GetVRegFloat(inst->VRegC_23x()));
+    inst = inst->Next_2xx();
+  }
+
+  ALWAYS_INLINE void REM_FLOAT() REQUIRES_SHARED(Locks::mutator_lock_) {
+    PREAMBLE();
+    shadow_frame.SetVRegFloat(inst->VRegA_23x(inst_data),
+                              fmodf(shadow_frame.GetVRegFloat(inst->VRegB_23x()),
+                                    shadow_frame.GetVRegFloat(inst->VRegC_23x())));
+    inst = inst->Next_2xx();
+  }
+
+  ALWAYS_INLINE void ADD_DOUBLE() REQUIRES_SHARED(Locks::mutator_lock_) {
+    PREAMBLE();
+    shadow_frame.SetVRegDouble(inst->VRegA_23x(inst_data),
+                               shadow_frame.GetVRegDouble(inst->VRegB_23x()) +
+                               shadow_frame.GetVRegDouble(inst->VRegC_23x()));
+    inst = inst->Next_2xx();
+  }
+
+  ALWAYS_INLINE void SUB_DOUBLE() REQUIRES_SHARED(Locks::mutator_lock_) {
+    PREAMBLE();
+    shadow_frame.SetVRegDouble(inst->VRegA_23x(inst_data),
+                               shadow_frame.GetVRegDouble(inst->VRegB_23x()) -
+                               shadow_frame.GetVRegDouble(inst->VRegC_23x()));
+    inst = inst->Next_2xx();
+  }
+
+  ALWAYS_INLINE void MUL_DOUBLE() REQUIRES_SHARED(Locks::mutator_lock_) {
+    PREAMBLE();
+    shadow_frame.SetVRegDouble(inst->VRegA_23x(inst_data),
+                               shadow_frame.GetVRegDouble(inst->VRegB_23x()) *
+                               shadow_frame.GetVRegDouble(inst->VRegC_23x()));
+    inst = inst->Next_2xx();
+  }
+
+  ALWAYS_INLINE void DIV_DOUBLE() REQUIRES_SHARED(Locks::mutator_lock_) {
+    PREAMBLE();
+    shadow_frame.SetVRegDouble(inst->VRegA_23x(inst_data),
+                               shadow_frame.GetVRegDouble(inst->VRegB_23x()) /
+                               shadow_frame.GetVRegDouble(inst->VRegC_23x()));
+    inst = inst->Next_2xx();
+  }
+
+  ALWAYS_INLINE void REM_DOUBLE() REQUIRES_SHARED(Locks::mutator_lock_) {
+    PREAMBLE();
+    shadow_frame.SetVRegDouble(inst->VRegA_23x(inst_data),
+                               fmod(shadow_frame.GetVRegDouble(inst->VRegB_23x()),
+                                    shadow_frame.GetVRegDouble(inst->VRegC_23x())));
+    inst = inst->Next_2xx();
+  }
+
+  ALWAYS_INLINE void ADD_INT_2ADDR() REQUIRES_SHARED(Locks::mutator_lock_) {
+    PREAMBLE();
+    uint4_t vregA = inst->VRegA_12x(inst_data);
+    shadow_frame.SetVReg(vregA, SafeAdd(shadow_frame.GetVReg(vregA),
+                                        shadow_frame.GetVReg(inst->VRegB_12x(inst_data))));
+    inst = inst->Next_1xx();
+  }
+
+  ALWAYS_INLINE void SUB_INT_2ADDR() REQUIRES_SHARED(Locks::mutator_lock_) {
+    PREAMBLE();
+    uint4_t vregA = inst->VRegA_12x(inst_data);
+    shadow_frame.SetVReg(vregA,
+                         SafeSub(shadow_frame.GetVReg(vregA),
+                                 shadow_frame.GetVReg(inst->VRegB_12x(inst_data))));
+    inst = inst->Next_1xx();
+  }
+
+  ALWAYS_INLINE void MUL_INT_2ADDR() REQUIRES_SHARED(Locks::mutator_lock_) {
+    PREAMBLE();
+    uint4_t vregA = inst->VRegA_12x(inst_data);
+    shadow_frame.SetVReg(vregA,
+                         SafeMul(shadow_frame.GetVReg(vregA),
+                                 shadow_frame.GetVReg(inst->VRegB_12x(inst_data))));
+    inst = inst->Next_1xx();
+  }
+
+  ALWAYS_INLINE void DIV_INT_2ADDR() REQUIRES_SHARED(Locks::mutator_lock_) {
+    PREAMBLE();
+    uint4_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, Next_1xx);
+  }
+
+  ALWAYS_INLINE void REM_INT_2ADDR() REQUIRES_SHARED(Locks::mutator_lock_) {
+    PREAMBLE();
+    uint4_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, Next_1xx);
+  }
+
+  ALWAYS_INLINE void SHL_INT_2ADDR() REQUIRES_SHARED(Locks::mutator_lock_) {
+    PREAMBLE();
+    uint4_t vregA = inst->VRegA_12x(inst_data);
+    shadow_frame.SetVReg(vregA,
+                         shadow_frame.GetVReg(vregA) <<
+                         (shadow_frame.GetVReg(inst->VRegB_12x(inst_data)) & 0x1f));
+    inst = inst->Next_1xx();
+  }
+
+  ALWAYS_INLINE void SHR_INT_2ADDR() REQUIRES_SHARED(Locks::mutator_lock_) {
+    PREAMBLE();
+    uint4_t vregA = inst->VRegA_12x(inst_data);
+    shadow_frame.SetVReg(vregA,
+                         shadow_frame.GetVReg(vregA) >>
+                         (shadow_frame.GetVReg(inst->VRegB_12x(inst_data)) & 0x1f));
+    inst = inst->Next_1xx();
+  }
+
+  ALWAYS_INLINE void USHR_INT_2ADDR() REQUIRES_SHARED(Locks::mutator_lock_) {
+    PREAMBLE();
+    uint4_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));
+    inst = inst->Next_1xx();
+  }
+
+  ALWAYS_INLINE void AND_INT_2ADDR() REQUIRES_SHARED(Locks::mutator_lock_) {
+    PREAMBLE();
+    uint4_t vregA = inst->VRegA_12x(inst_data);
+    shadow_frame.SetVReg(vregA,
+                         shadow_frame.GetVReg(vregA) &
+                         shadow_frame.GetVReg(inst->VRegB_12x(inst_data)));
+    inst = inst->Next_1xx();
+  }
+
+  ALWAYS_INLINE void OR_INT_2ADDR() REQUIRES_SHARED(Locks::mutator_lock_) {
+    PREAMBLE();
+    uint4_t vregA = inst->VRegA_12x(inst_data);
+    shadow_frame.SetVReg(vregA,
+                         shadow_frame.GetVReg(vregA) |
+                         shadow_frame.GetVReg(inst->VRegB_12x(inst_data)));
+    inst = inst->Next_1xx();
+  }
+
+  ALWAYS_INLINE void XOR_INT_2ADDR() REQUIRES_SHARED(Locks::mutator_lock_) {
+    PREAMBLE();
+    uint4_t vregA = inst->VRegA_12x(inst_data);
+    shadow_frame.SetVReg(vregA,
+                         shadow_frame.GetVReg(vregA) ^
+                         shadow_frame.GetVReg(inst->VRegB_12x(inst_data)));
+    inst = inst->Next_1xx();
+  }
+
+  ALWAYS_INLINE void ADD_LONG_2ADDR() REQUIRES_SHARED(Locks::mutator_lock_) {
+    PREAMBLE();
+    uint4_t vregA = inst->VRegA_12x(inst_data);
+    shadow_frame.SetVRegLong(vregA,
+                             SafeAdd(shadow_frame.GetVRegLong(vregA),
+                                     shadow_frame.GetVRegLong(inst->VRegB_12x(inst_data))));
+    inst = inst->Next_1xx();
+  }
+
+  ALWAYS_INLINE void SUB_LONG_2ADDR() REQUIRES_SHARED(Locks::mutator_lock_) {
+    PREAMBLE();
+    uint4_t vregA = inst->VRegA_12x(inst_data);
+    shadow_frame.SetVRegLong(vregA,
+                             SafeSub(shadow_frame.GetVRegLong(vregA),
+                                     shadow_frame.GetVRegLong(inst->VRegB_12x(inst_data))));
+    inst = inst->Next_1xx();
+  }
+
+  ALWAYS_INLINE void MUL_LONG_2ADDR() REQUIRES_SHARED(Locks::mutator_lock_) {
+    PREAMBLE();
+    uint4_t vregA = inst->VRegA_12x(inst_data);
+    shadow_frame.SetVRegLong(vregA,
+                             SafeMul(shadow_frame.GetVRegLong(vregA),
+                                     shadow_frame.GetVRegLong(inst->VRegB_12x(inst_data))));
+    inst = inst->Next_1xx();
+  }
+
+  ALWAYS_INLINE void DIV_LONG_2ADDR() REQUIRES_SHARED(Locks::mutator_lock_) {
+    PREAMBLE();
+    uint4_t vregA = inst->VRegA_12x(inst_data);
+    DoLongDivide(shadow_frame, vregA, shadow_frame.GetVRegLong(vregA),
+                shadow_frame.GetVRegLong(inst->VRegB_12x(inst_data)));
+    POSSIBLY_HANDLE_PENDING_EXCEPTION(self->IsExceptionPending(), Next_1xx);
+  }
+
+  ALWAYS_INLINE void REM_LONG_2ADDR() REQUIRES_SHARED(Locks::mutator_lock_) {
+    PREAMBLE();
+    uint4_t vregA = inst->VRegA_12x(inst_data);
+    DoLongRemainder(shadow_frame, vregA, shadow_frame.GetVRegLong(vregA),
+                    shadow_frame.GetVRegLong(inst->VRegB_12x(inst_data)));
+    POSSIBLY_HANDLE_PENDING_EXCEPTION(self->IsExceptionPending(), Next_1xx);
+  }
+
+  ALWAYS_INLINE void AND_LONG_2ADDR() REQUIRES_SHARED(Locks::mutator_lock_) {
+    PREAMBLE();
+    uint4_t vregA = inst->VRegA_12x(inst_data);
+    shadow_frame.SetVRegLong(vregA,
+                             shadow_frame.GetVRegLong(vregA) &
+                             shadow_frame.GetVRegLong(inst->VRegB_12x(inst_data)));
+    inst = inst->Next_1xx();
+  }
+
+  ALWAYS_INLINE void OR_LONG_2ADDR() REQUIRES_SHARED(Locks::mutator_lock_) {
+    PREAMBLE();
+    uint4_t vregA = inst->VRegA_12x(inst_data);
+    shadow_frame.SetVRegLong(vregA,
+                             shadow_frame.GetVRegLong(vregA) |
+                             shadow_frame.GetVRegLong(inst->VRegB_12x(inst_data)));
+    inst = inst->Next_1xx();
+  }
+
+  ALWAYS_INLINE void XOR_LONG_2ADDR() REQUIRES_SHARED(Locks::mutator_lock_) {
+    PREAMBLE();
+    uint4_t vregA = inst->VRegA_12x(inst_data);
+    shadow_frame.SetVRegLong(vregA,
+                             shadow_frame.GetVRegLong(vregA) ^
+                             shadow_frame.GetVRegLong(inst->VRegB_12x(inst_data)));
+    inst = inst->Next_1xx();
+  }
+
+  ALWAYS_INLINE void SHL_LONG_2ADDR() REQUIRES_SHARED(Locks::mutator_lock_) {
+    PREAMBLE();
+    uint4_t vregA = inst->VRegA_12x(inst_data);
+    shadow_frame.SetVRegLong(vregA,
+                             shadow_frame.GetVRegLong(vregA) <<
+                             (shadow_frame.GetVReg(inst->VRegB_12x(inst_data)) & 0x3f));
+    inst = inst->Next_1xx();
+  }
+
+  ALWAYS_INLINE void SHR_LONG_2ADDR() REQUIRES_SHARED(Locks::mutator_lock_) {
+    PREAMBLE();
+    uint4_t vregA = inst->VRegA_12x(inst_data);
+    shadow_frame.SetVRegLong(vregA,
+                             shadow_frame.GetVRegLong(vregA) >>
+                             (shadow_frame.GetVReg(inst->VRegB_12x(inst_data)) & 0x3f));
+    inst = inst->Next_1xx();
+  }
+
+  ALWAYS_INLINE void USHR_LONG_2ADDR() REQUIRES_SHARED(Locks::mutator_lock_) {
+    PREAMBLE();
+    uint4_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));
+    inst = inst->Next_1xx();
+  }
+
+  ALWAYS_INLINE void ADD_FLOAT_2ADDR() REQUIRES_SHARED(Locks::mutator_lock_) {
+    PREAMBLE();
+    uint4_t vregA = inst->VRegA_12x(inst_data);
+    shadow_frame.SetVRegFloat(vregA,
+                              shadow_frame.GetVRegFloat(vregA) +
+                              shadow_frame.GetVRegFloat(inst->VRegB_12x(inst_data)));
+    inst = inst->Next_1xx();
+  }
+
+  ALWAYS_INLINE void SUB_FLOAT_2ADDR() REQUIRES_SHARED(Locks::mutator_lock_) {
+    PREAMBLE();
+    uint4_t vregA = inst->VRegA_12x(inst_data);
+    shadow_frame.SetVRegFloat(vregA,
+                              shadow_frame.GetVRegFloat(vregA) -
+                              shadow_frame.GetVRegFloat(inst->VRegB_12x(inst_data)));
+    inst = inst->Next_1xx();
+  }
+
+  ALWAYS_INLINE void MUL_FLOAT_2ADDR() REQUIRES_SHARED(Locks::mutator_lock_) {
+    PREAMBLE();
+    uint4_t vregA = inst->VRegA_12x(inst_data);
+    shadow_frame.SetVRegFloat(vregA,
+                              shadow_frame.GetVRegFloat(vregA) *
+                              shadow_frame.GetVRegFloat(inst->VRegB_12x(inst_data)));
+    inst = inst->Next_1xx();
+  }
+
+  ALWAYS_INLINE void DIV_FLOAT_2ADDR() REQUIRES_SHARED(Locks::mutator_lock_) {
+    PREAMBLE();
+    uint4_t vregA = inst->VRegA_12x(inst_data);
+    shadow_frame.SetVRegFloat(vregA,
+                              shadow_frame.GetVRegFloat(vregA) /
+                              shadow_frame.GetVRegFloat(inst->VRegB_12x(inst_data)));
+    inst = inst->Next_1xx();
+  }
+
+  ALWAYS_INLINE void REM_FLOAT_2ADDR() REQUIRES_SHARED(Locks::mutator_lock_) {
+    PREAMBLE();
+    uint4_t vregA = inst->VRegA_12x(inst_data);
+    shadow_frame.SetVRegFloat(vregA,
+                              fmodf(shadow_frame.GetVRegFloat(vregA),
+                                    shadow_frame.GetVRegFloat(inst->VRegB_12x(inst_data))));
+    inst = inst->Next_1xx();
+  }
+
+  ALWAYS_INLINE void ADD_DOUBLE_2ADDR() REQUIRES_SHARED(Locks::mutator_lock_) {
+    PREAMBLE();
+    uint4_t vregA = inst->VRegA_12x(inst_data);
+    shadow_frame.SetVRegDouble(vregA,
+                               shadow_frame.GetVRegDouble(vregA) +
+                               shadow_frame.GetVRegDouble(inst->VRegB_12x(inst_data)));
+    inst = inst->Next_1xx();
+  }
+
+  ALWAYS_INLINE void SUB_DOUBLE_2ADDR() REQUIRES_SHARED(Locks::mutator_lock_) {
+    PREAMBLE();
+    uint4_t vregA = inst->VRegA_12x(inst_data);
+    shadow_frame.SetVRegDouble(vregA,
+                               shadow_frame.GetVRegDouble(vregA) -
+                               shadow_frame.GetVRegDouble(inst->VRegB_12x(inst_data)));
+    inst = inst->Next_1xx();
+  }
+
+  ALWAYS_INLINE void MUL_DOUBLE_2ADDR() REQUIRES_SHARED(Locks::mutator_lock_) {
+    PREAMBLE();
+    uint4_t vregA = inst->VRegA_12x(inst_data);
+    shadow_frame.SetVRegDouble(vregA,
+                               shadow_frame.GetVRegDouble(vregA) *
+                               shadow_frame.GetVRegDouble(inst->VRegB_12x(inst_data)));
+    inst = inst->Next_1xx();
+  }
+
+  ALWAYS_INLINE void DIV_DOUBLE_2ADDR() REQUIRES_SHARED(Locks::mutator_lock_) {
+    PREAMBLE();
+    uint4_t vregA = inst->VRegA_12x(inst_data);
+    shadow_frame.SetVRegDouble(vregA,
+                               shadow_frame.GetVRegDouble(vregA) /
+                               shadow_frame.GetVRegDouble(inst->VRegB_12x(inst_data)));
+    inst = inst->Next_1xx();
+  }
+
+  ALWAYS_INLINE void REM_DOUBLE_2ADDR() REQUIRES_SHARED(Locks::mutator_lock_) {
+    PREAMBLE();
+    uint4_t vregA = inst->VRegA_12x(inst_data);
+    shadow_frame.SetVRegDouble(vregA,
+                               fmod(shadow_frame.GetVRegDouble(vregA),
+                                    shadow_frame.GetVRegDouble(inst->VRegB_12x(inst_data))));
+    inst = inst->Next_1xx();
+  }
+
+  ALWAYS_INLINE void ADD_INT_LIT16() REQUIRES_SHARED(Locks::mutator_lock_) {
+    PREAMBLE();
+    shadow_frame.SetVReg(inst->VRegA_22s(inst_data),
+                         SafeAdd(shadow_frame.GetVReg(inst->VRegB_22s(inst_data)),
+                                 inst->VRegC_22s()));
+    inst = inst->Next_2xx();
+  }
+
+  ALWAYS_INLINE void RSUB_INT() REQUIRES_SHARED(Locks::mutator_lock_) {
+    PREAMBLE();
+    shadow_frame.SetVReg(inst->VRegA_22s(inst_data),
+                         SafeSub(inst->VRegC_22s(),
+                                 shadow_frame.GetVReg(inst->VRegB_22s(inst_data))));
+    inst = inst->Next_2xx();
+  }
+
+  ALWAYS_INLINE void MUL_INT_LIT16() REQUIRES_SHARED(Locks::mutator_lock_) {
+    PREAMBLE();
+    shadow_frame.SetVReg(inst->VRegA_22s(inst_data),
+                         SafeMul(shadow_frame.GetVReg(inst->VRegB_22s(inst_data)),
+                                 inst->VRegC_22s()));
+    inst = inst->Next_2xx();
+  }
+
+  ALWAYS_INLINE void DIV_INT_LIT16() REQUIRES_SHARED(Locks::mutator_lock_) {
+    PREAMBLE();
+    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, Next_2xx);
+  }
+
+  ALWAYS_INLINE void REM_INT_LIT16() REQUIRES_SHARED(Locks::mutator_lock_) {
+    PREAMBLE();
+    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, Next_2xx);
+  }
+
+  ALWAYS_INLINE void AND_INT_LIT16() REQUIRES_SHARED(Locks::mutator_lock_) {
+    PREAMBLE();
+    shadow_frame.SetVReg(inst->VRegA_22s(inst_data),
+                         shadow_frame.GetVReg(inst->VRegB_22s(inst_data)) &
+                         inst->VRegC_22s());
+    inst = inst->Next_2xx();
+  }
+
+  ALWAYS_INLINE void OR_INT_LIT16() REQUIRES_SHARED(Locks::mutator_lock_) {
+    PREAMBLE();
+    shadow_frame.SetVReg(inst->VRegA_22s(inst_data),
+                         shadow_frame.GetVReg(inst->VRegB_22s(inst_data)) |
+                         inst->VRegC_22s());
+    inst = inst->Next_2xx();
+  }
+
+  ALWAYS_INLINE void XOR_INT_LIT16() REQUIRES_SHARED(Locks::mutator_lock_) {
+    PREAMBLE();
+    shadow_frame.SetVReg(inst->VRegA_22s(inst_data),
+                         shadow_frame.GetVReg(inst->VRegB_22s(inst_data)) ^
+                         inst->VRegC_22s());
+    inst = inst->Next_2xx();
+  }
+
+  ALWAYS_INLINE void ADD_INT_LIT8() REQUIRES_SHARED(Locks::mutator_lock_) {
+    PREAMBLE();
+    shadow_frame.SetVReg(inst->VRegA_22b(inst_data),
+                         SafeAdd(shadow_frame.GetVReg(inst->VRegB_22b()), inst->VRegC_22b()));
+    inst = inst->Next_2xx();
+  }
+
+  ALWAYS_INLINE void RSUB_INT_LIT8() REQUIRES_SHARED(Locks::mutator_lock_) {
+    PREAMBLE();
+    shadow_frame.SetVReg(inst->VRegA_22b(inst_data),
+                         SafeSub(inst->VRegC_22b(), shadow_frame.GetVReg(inst->VRegB_22b())));
+    inst = inst->Next_2xx();
+  }
+
+  ALWAYS_INLINE void MUL_INT_LIT8() REQUIRES_SHARED(Locks::mutator_lock_) {
+    PREAMBLE();
+    shadow_frame.SetVReg(inst->VRegA_22b(inst_data),
+                         SafeMul(shadow_frame.GetVReg(inst->VRegB_22b()), inst->VRegC_22b()));
+    inst = inst->Next_2xx();
+  }
+
+  ALWAYS_INLINE void DIV_INT_LIT8() REQUIRES_SHARED(Locks::mutator_lock_) {
+    PREAMBLE();
+    bool success = DoIntDivide(shadow_frame, inst->VRegA_22b(inst_data),
+                               shadow_frame.GetVReg(inst->VRegB_22b()), inst->VRegC_22b());
+    POSSIBLY_HANDLE_PENDING_EXCEPTION(!success, Next_2xx);
+  }
+
+  ALWAYS_INLINE void REM_INT_LIT8() REQUIRES_SHARED(Locks::mutator_lock_) {
+    PREAMBLE();
+    bool success = DoIntRemainder(shadow_frame, inst->VRegA_22b(inst_data),
+                                  shadow_frame.GetVReg(inst->VRegB_22b()), inst->VRegC_22b());
+    POSSIBLY_HANDLE_PENDING_EXCEPTION(!success, Next_2xx);
+  }
+
+  ALWAYS_INLINE void AND_INT_LIT8() REQUIRES_SHARED(Locks::mutator_lock_) {
+    PREAMBLE();
+    shadow_frame.SetVReg(inst->VRegA_22b(inst_data),
+                         shadow_frame.GetVReg(inst->VRegB_22b()) &
+                         inst->VRegC_22b());
+    inst = inst->Next_2xx();
+  }
+
+  ALWAYS_INLINE void OR_INT_LIT8() REQUIRES_SHARED(Locks::mutator_lock_) {
+    PREAMBLE();
+    shadow_frame.SetVReg(inst->VRegA_22b(inst_data),
+                         shadow_frame.GetVReg(inst->VRegB_22b()) |
+                         inst->VRegC_22b());
+    inst = inst->Next_2xx();
+  }
+
+  ALWAYS_INLINE void XOR_INT_LIT8() REQUIRES_SHARED(Locks::mutator_lock_) {
+    PREAMBLE();
+    shadow_frame.SetVReg(inst->VRegA_22b(inst_data),
+                         shadow_frame.GetVReg(inst->VRegB_22b()) ^
+                         inst->VRegC_22b());
+    inst = inst->Next_2xx();
+  }
+
+  ALWAYS_INLINE void SHL_INT_LIT8() REQUIRES_SHARED(Locks::mutator_lock_) {
+    PREAMBLE();
+    shadow_frame.SetVReg(inst->VRegA_22b(inst_data),
+                         shadow_frame.GetVReg(inst->VRegB_22b()) <<
+                         (inst->VRegC_22b() & 0x1f));
+    inst = inst->Next_2xx();
+  }
+
+  ALWAYS_INLINE void SHR_INT_LIT8() REQUIRES_SHARED(Locks::mutator_lock_) {
+    PREAMBLE();
+    shadow_frame.SetVReg(inst->VRegA_22b(inst_data),
+                         shadow_frame.GetVReg(inst->VRegB_22b()) >>
+                         (inst->VRegC_22b() & 0x1f));
+    inst = inst->Next_2xx();
+  }
+
+  ALWAYS_INLINE void USHR_INT_LIT8() REQUIRES_SHARED(Locks::mutator_lock_) {
+    PREAMBLE();
+    shadow_frame.SetVReg(inst->VRegA_22b(inst_data),
+                         static_cast<uint32_t>(shadow_frame.GetVReg(inst->VRegB_22b())) >>
+                         (inst->VRegC_22b() & 0x1f));
+    inst = inst->Next_2xx();
+  }
+
+  ALWAYS_INLINE void UNUSED_3E() REQUIRES_SHARED(Locks::mutator_lock_) {
+    UnexpectedOpcode(inst, shadow_frame);
+  }
+
+  ALWAYS_INLINE void UNUSED_3F() REQUIRES_SHARED(Locks::mutator_lock_) {
+    UnexpectedOpcode(inst, shadow_frame);
+  }
+
+  ALWAYS_INLINE void UNUSED_40() REQUIRES_SHARED(Locks::mutator_lock_) {
+    UnexpectedOpcode(inst, shadow_frame);
+  }
+
+  ALWAYS_INLINE void UNUSED_41() REQUIRES_SHARED(Locks::mutator_lock_) {
+    UnexpectedOpcode(inst, shadow_frame);
+  }
+
+  ALWAYS_INLINE void UNUSED_42() REQUIRES_SHARED(Locks::mutator_lock_) {
+    UnexpectedOpcode(inst, shadow_frame);
+  }
+
+  ALWAYS_INLINE void UNUSED_43() REQUIRES_SHARED(Locks::mutator_lock_) {
+    UnexpectedOpcode(inst, shadow_frame);
+  }
+
+  ALWAYS_INLINE void UNUSED_79() REQUIRES_SHARED(Locks::mutator_lock_) {
+    UnexpectedOpcode(inst, shadow_frame);
+  }
+
+  ALWAYS_INLINE void UNUSED_7A() REQUIRES_SHARED(Locks::mutator_lock_) {
+    UnexpectedOpcode(inst, shadow_frame);
+  }
+
+  ALWAYS_INLINE void UNUSED_F3() REQUIRES_SHARED(Locks::mutator_lock_) {
+    UnexpectedOpcode(inst, shadow_frame);
+  }
+
+  ALWAYS_INLINE void UNUSED_F4() REQUIRES_SHARED(Locks::mutator_lock_) {
+    UnexpectedOpcode(inst, shadow_frame);
+  }
+
+  ALWAYS_INLINE void UNUSED_F5() REQUIRES_SHARED(Locks::mutator_lock_) {
+    UnexpectedOpcode(inst, shadow_frame);
+  }
+
+  ALWAYS_INLINE void UNUSED_F6() REQUIRES_SHARED(Locks::mutator_lock_) {
+    UnexpectedOpcode(inst, shadow_frame);
+  }
+
+  ALWAYS_INLINE void UNUSED_F7() REQUIRES_SHARED(Locks::mutator_lock_) {
+    UnexpectedOpcode(inst, shadow_frame);
+  }
+
+  ALWAYS_INLINE void UNUSED_F8() REQUIRES_SHARED(Locks::mutator_lock_) {
+    UnexpectedOpcode(inst, shadow_frame);
+  }
+
+  ALWAYS_INLINE void UNUSED_F9() REQUIRES_SHARED(Locks::mutator_lock_) {
+    UnexpectedOpcode(inst, shadow_frame);
+  }
+
+  ALWAYS_INLINE InstructionHandler(SwitchImplContext* ctx,
+                                   const instrumentation::Instrumentation* instrumentation,
+                                   Thread* self,
+                                   ShadowFrame& shadow_frame,
+                                   uint16_t dex_pc,
+                                   const Instruction*& inst,
+                                   uint16_t inst_data,
+                                   bool& exit_interpreter_loop)
+    : ctx(ctx),
+      instrumentation(instrumentation),
+      self(self),
+      shadow_frame(shadow_frame),
+      dex_pc(dex_pc),
+      inst(inst),
+      inst_data(inst_data),
+      exit_interpreter_loop(exit_interpreter_loop) {
+  }
+
+ private:
+  static constexpr bool do_assignability_check = do_access_check;
+
+  const CodeItemDataAccessor& Accessor() { return ctx->accessor; }
+  const uint16_t* Insns() { return ctx->accessor.Insns(); }
+  JValue* ResultRegister() { return &ctx->result_register; }
+
+  SwitchImplContext* const ctx;
+  const instrumentation::Instrumentation* const instrumentation;
+  Thread* const self;
+  ShadowFrame& shadow_frame;
+  uint32_t const dex_pc;
+  const Instruction*& inst;
+  uint16_t const inst_data;
+  bool& exit_interpreter_loop;
+};
+
+#undef HANDLE_BACKWARD_BRANCH
+#undef HANDLE_ASYNC_EXCEPTION
+#undef HOTNESS_UPDATE
+#undef BRANCH_INSTRUMENTATION
+#undef PREAMBLE
+#undef PREAMBLE_SAVE
+#undef HANDLE_MONITOR_CHECKS
+#undef POSSIBLY_HANDLE_PENDING_EXCEPTION
+#undef POSSIBLY_HANDLE_PENDING_EXCEPTION_ON_INVOKE
+#undef POSSIBLY_HANDLE_PENDING_EXCEPTION_ON_INVOKE_POLYMORPHIC
+#undef POSSIBLY_HANDLE_PENDING_EXCEPTION_ON_INVOKE_IMPL
+#undef HANDLE_PENDING_EXCEPTION
+#undef HANDLE_PENDING_EXCEPTION_WITH_INSTRUMENTATION
+#undef CHECK_FORCE_RETURN
+
 // TODO On ASAN builds this function gets a huge stack frame. Since normally we run in the mterp
 // this shouldn't cause any problems for stack overflow detection. Remove this once b/117341496 is
 // fixed.
@@ -276,9 +2735,6 @@
   Thread* self = ctx->self;
   const CodeItemDataAccessor& accessor = ctx->accessor;
   ShadowFrame& shadow_frame = ctx->shadow_frame;
-  JValue result_register = ctx->result_register;
-  bool interpret_one_instruction = ctx->interpret_one_instruction;
-  constexpr bool do_assignability_check = do_access_check;
   if (UNLIKELY(!shadow_frame.HasReferenceArray())) {
     LOG(FATAL) << "Invalid shadow frame for interpreter use";
     ctx->result = JValue();
@@ -291,2295 +2747,40 @@
   const uint16_t* const insns = accessor.Insns();
   const Instruction* inst = Instruction::At(insns + dex_pc);
   uint16_t inst_data;
-  jit::Jit* jit = Runtime::Current()->GetJit();
 
   DCHECK(!shadow_frame.GetForceRetryInstruction())
       << "Entered interpreter from invoke without retry instruction being handled!";
 
-  do {
+  bool const interpret_one_instruction = ctx->interpret_one_instruction;
+  while (true) {
     dex_pc = inst->GetDexPc(insns);
     shadow_frame.SetDexPC(dex_pc);
     TraceExecution(shadow_frame, inst, dex_pc);
     inst_data = inst->Fetch16(0);
     switch (inst->Opcode(inst_data)) {
-      case Instruction::NOP:
-        PREAMBLE();
-        inst = inst->Next_1xx();
-        break;
-      case Instruction::MOVE:
-        PREAMBLE();
-        shadow_frame.SetVReg(inst->VRegA_12x(inst_data),
-                             shadow_frame.GetVReg(inst->VRegB_12x(inst_data)));
-        inst = inst->Next_1xx();
-        break;
-      case Instruction::MOVE_FROM16:
-        PREAMBLE();
-        shadow_frame.SetVReg(inst->VRegA_22x(inst_data),
-                             shadow_frame.GetVReg(inst->VRegB_22x()));
-        inst = inst->Next_2xx();
-        break;
-      case Instruction::MOVE_16:
-        PREAMBLE();
-        shadow_frame.SetVReg(inst->VRegA_32x(),
-                             shadow_frame.GetVReg(inst->VRegB_32x()));
-        inst = inst->Next_3xx();
-        break;
-      case Instruction::MOVE_WIDE:
-        PREAMBLE();
-        shadow_frame.SetVRegLong(inst->VRegA_12x(inst_data),
-                                 shadow_frame.GetVRegLong(inst->VRegB_12x(inst_data)));
-        inst = inst->Next_1xx();
-        break;
-      case Instruction::MOVE_WIDE_FROM16:
-        PREAMBLE();
-        shadow_frame.SetVRegLong(inst->VRegA_22x(inst_data),
-                                 shadow_frame.GetVRegLong(inst->VRegB_22x()));
-        inst = inst->Next_2xx();
-        break;
-      case Instruction::MOVE_WIDE_16:
-        PREAMBLE();
-        shadow_frame.SetVRegLong(inst->VRegA_32x(),
-                                 shadow_frame.GetVRegLong(inst->VRegB_32x()));
-        inst = inst->Next_3xx();
-        break;
-      case Instruction::MOVE_OBJECT:
-        PREAMBLE();
-        shadow_frame.SetVRegReference(inst->VRegA_12x(inst_data),
-                                      shadow_frame.GetVRegReference(inst->VRegB_12x(inst_data)));
-        inst = inst->Next_1xx();
-        break;
-      case Instruction::MOVE_OBJECT_FROM16:
-        PREAMBLE();
-        shadow_frame.SetVRegReference(inst->VRegA_22x(inst_data),
-                                      shadow_frame.GetVRegReference(inst->VRegB_22x()));
-        inst = inst->Next_2xx();
-        break;
-      case Instruction::MOVE_OBJECT_16:
-        PREAMBLE();
-        shadow_frame.SetVRegReference(inst->VRegA_32x(),
-                                      shadow_frame.GetVRegReference(inst->VRegB_32x()));
-        inst = inst->Next_3xx();
-        break;
-      case Instruction::MOVE_RESULT:
-        PREAMBLE();
-        shadow_frame.SetVReg(inst->VRegA_11x(inst_data), result_register.GetI());
-        inst = inst->Next_1xx();
-        break;
-      case Instruction::MOVE_RESULT_WIDE:
-        PREAMBLE();
-        shadow_frame.SetVRegLong(inst->VRegA_11x(inst_data), result_register.GetJ());
-        inst = inst->Next_1xx();
-        break;
-      case Instruction::MOVE_RESULT_OBJECT:
-        PREAMBLE_SAVE(&result_register);
-        shadow_frame.SetVRegReference(inst->VRegA_11x(inst_data), result_register.GetL());
-        inst = inst->Next_1xx();
-        break;
-      case Instruction::MOVE_EXCEPTION: {
-        PREAMBLE();
-        ObjPtr<mirror::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();
-        inst = inst->Next_1xx();
-        break;
+#define OPCODE_CASE(OPCODE, OPCODE_NAME, pname, f, i, a, e, v)                                    \
+      case OPCODE: {                                                                              \
+        bool exit_loop = false;                                                                   \
+        InstructionHandler<do_access_check, transaction_active> handler(                          \
+            ctx, instrumentation, self, shadow_frame, dex_pc, inst, inst_data, exit_loop);        \
+        /* TODO: Call PREAMBLE here, instead of explicitly in each handler */                     \
+        handler.OPCODE_NAME();                                                                    \
+        /* TODO: Advance 'inst' here, instead of explicitly in each handler */                    \
+        if (UNLIKELY(exit_loop)) {                                                                \
+          return;                                                                                 \
+        }                                                                                         \
+        break;                                                                                    \
       }
-      case Instruction::RETURN_VOID_NO_BARRIER: {
-        PREAMBLE();
-        JValue result;
-        self->AllowThreadSuspension();
-        HANDLE_MONITOR_CHECKS();
-        if (UNLIKELY(NeedsMethodExitEvent(instrumentation) &&
-                     !SendMethodExitEvents(self,
-                                           instrumentation,
-                                           shadow_frame,
-                                           shadow_frame.GetThisObject(accessor.InsSize()),
-                                           shadow_frame.GetMethod(),
-                                           inst->GetDexPc(insns),
-                                           result))) {
-          HANDLE_PENDING_EXCEPTION_WITH_INSTRUMENTATION(nullptr);
-        }
-        if (interpret_one_instruction) {
-          /* Signal mterp to return to caller */
-          shadow_frame.SetDexPC(dex::kDexNoIndex);
-        }
-        ctx->result = result;
-        return;
-      }
-      case Instruction::RETURN_VOID: {
-        PREAMBLE();
-        QuasiAtomic::ThreadFenceForConstructor();
-        JValue result;
-        self->AllowThreadSuspension();
-        HANDLE_MONITOR_CHECKS();
-        if (UNLIKELY(NeedsMethodExitEvent(instrumentation) &&
-                     !SendMethodExitEvents(self,
-                                           instrumentation,
-                                           shadow_frame,
-                                           shadow_frame.GetThisObject(accessor.InsSize()),
-                                           shadow_frame.GetMethod(),
-                                           inst->GetDexPc(insns),
-                                           result))) {
-          HANDLE_PENDING_EXCEPTION_WITH_INSTRUMENTATION(nullptr);
-        }
-        if (interpret_one_instruction) {
-          /* Signal mterp to return to caller */
-          shadow_frame.SetDexPC(dex::kDexNoIndex);
-        }
-        ctx->result = result;
-        return;
-      }
-      case Instruction::RETURN: {
-        PREAMBLE();
-        JValue result;
-        result.SetJ(0);
-        result.SetI(shadow_frame.GetVReg(inst->VRegA_11x(inst_data)));
-        self->AllowThreadSuspension();
-        HANDLE_MONITOR_CHECKS();
-        if (UNLIKELY(NeedsMethodExitEvent(instrumentation) &&
-                     !SendMethodExitEvents(self,
-                                           instrumentation,
-                                           shadow_frame,
-                                           shadow_frame.GetThisObject(accessor.InsSize()),
-                                           shadow_frame.GetMethod(),
-                                           inst->GetDexPc(insns),
-                                           result))) {
-          HANDLE_PENDING_EXCEPTION_WITH_INSTRUMENTATION(nullptr);
-        }
-        if (interpret_one_instruction) {
-          /* Signal mterp to return to caller */
-          shadow_frame.SetDexPC(dex::kDexNoIndex);
-        }
-        ctx->result = result;
-        return;
-      }
-      case Instruction::RETURN_WIDE: {
-        PREAMBLE();
-        JValue result;
-        result.SetJ(shadow_frame.GetVRegLong(inst->VRegA_11x(inst_data)));
-        self->AllowThreadSuspension();
-        HANDLE_MONITOR_CHECKS();
-        if (UNLIKELY(NeedsMethodExitEvent(instrumentation) &&
-                     !SendMethodExitEvents(self,
-                                           instrumentation,
-                                           shadow_frame,
-                                           shadow_frame.GetThisObject(accessor.InsSize()),
-                                           shadow_frame.GetMethod(),
-                                           inst->GetDexPc(insns),
-                                           result))) {
-          HANDLE_PENDING_EXCEPTION_WITH_INSTRUMENTATION(nullptr);
-        }
-        if (interpret_one_instruction) {
-          /* Signal mterp to return to caller */
-          shadow_frame.SetDexPC(dex::kDexNoIndex);
-        }
-        ctx->result = result;
-        return;
-      }
-      case Instruction::RETURN_OBJECT: {
-        PREAMBLE();
-        JValue result;
-        self->AllowThreadSuspension();
-        HANDLE_MONITOR_CHECKS();
-        const size_t ref_idx = inst->VRegA_11x(inst_data);
-        ObjPtr<mirror::Object> obj_result = shadow_frame.GetVRegReference(ref_idx);
-        if (do_assignability_check && obj_result != nullptr) {
-          ObjPtr<mirror::Class> return_type = shadow_frame.GetMethod()->ResolveReturnType();
-          // Re-load since it might have moved.
-          obj_result = shadow_frame.GetVRegReference(ref_idx);
-          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/InternalError;",
-                                     "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(NeedsMethodExitEvent(instrumentation) &&
-                     !SendMethodExitEvents(self,
-                                           instrumentation,
-                                           shadow_frame,
-                                           shadow_frame.GetThisObject(accessor.InsSize()),
-                                           shadow_frame.GetMethod(),
-                                           inst->GetDexPc(insns),
-                                           result))) {
-          HANDLE_PENDING_EXCEPTION_WITH_INSTRUMENTATION(nullptr);
-        }
-        // Re-load since it might have moved during the MethodExitEvent.
-        result.SetL(shadow_frame.GetVRegReference(ref_idx));
-        if (interpret_one_instruction) {
-          /* Signal mterp to return to caller */
-          shadow_frame.SetDexPC(dex::kDexNoIndex);
-        }
-        ctx->result = result;
-        return;
-      }
-      case Instruction::CONST_4: {
-        PREAMBLE();
-        uint4_t dst = inst->VRegA_11n(inst_data);
-        int4_t val = inst->VRegB_11n(inst_data);
-        shadow_frame.SetVReg(dst, val);
-        if (val == 0) {
-          shadow_frame.SetVRegReference(dst, nullptr);
-        }
-        inst = inst->Next_1xx();
-        break;
-      }
-      case Instruction::CONST_16: {
-        PREAMBLE();
-        uint8_t dst = inst->VRegA_21s(inst_data);
-        int16_t val = inst->VRegB_21s();
-        shadow_frame.SetVReg(dst, val);
-        if (val == 0) {
-          shadow_frame.SetVRegReference(dst, nullptr);
-        }
-        inst = inst->Next_2xx();
-        break;
-      }
-      case Instruction::CONST: {
-        PREAMBLE();
-        uint8_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);
-        }
-        inst = inst->Next_3xx();
-        break;
-      }
-      case Instruction::CONST_HIGH16: {
-        PREAMBLE();
-        uint8_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);
-        }
-        inst = inst->Next_2xx();
-        break;
-      }
-      case Instruction::CONST_WIDE_16:
-        PREAMBLE();
-        shadow_frame.SetVRegLong(inst->VRegA_21s(inst_data), inst->VRegB_21s());
-        inst = inst->Next_2xx();
-        break;
-      case Instruction::CONST_WIDE_32:
-        PREAMBLE();
-        shadow_frame.SetVRegLong(inst->VRegA_31i(inst_data), inst->VRegB_31i());
-        inst = inst->Next_3xx();
-        break;
-      case Instruction::CONST_WIDE:
-        PREAMBLE();
-        shadow_frame.SetVRegLong(inst->VRegA_51l(inst_data), inst->VRegB_51l());
-        inst = inst->Next_51l();
-        break;
-      case Instruction::CONST_WIDE_HIGH16:
-        PREAMBLE();
-        shadow_frame.SetVRegLong(inst->VRegA_21h(inst_data),
-                                 static_cast<uint64_t>(inst->VRegB_21h()) << 48);
-        inst = inst->Next_2xx();
-        break;
-      case Instruction::CONST_STRING: {
-        PREAMBLE();
-        ObjPtr<mirror::String> s = ResolveString(self,
-                                                 shadow_frame,
-                                                 dex::StringIndex(inst->VRegB_21c()));
-        if (UNLIKELY(s == nullptr)) {
-          HANDLE_PENDING_EXCEPTION();
-        } else {
-          shadow_frame.SetVRegReference(inst->VRegA_21c(inst_data), s);
-          inst = inst->Next_2xx();
-        }
-        break;
-      }
-      case Instruction::CONST_STRING_JUMBO: {
-        PREAMBLE();
-        ObjPtr<mirror::String> s = ResolveString(self,
-                                                 shadow_frame,
-                                                 dex::StringIndex(inst->VRegB_31c()));
-        if (UNLIKELY(s == nullptr)) {
-          HANDLE_PENDING_EXCEPTION();
-        } else {
-          shadow_frame.SetVRegReference(inst->VRegA_31c(inst_data), s);
-          inst = inst->Next_3xx();
-        }
-        break;
-      }
-      case Instruction::CONST_CLASS: {
-        PREAMBLE();
-        ObjPtr<mirror::Class> c = ResolveVerifyAndClinit(dex::TypeIndex(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);
-          inst = inst->Next_2xx();
-        }
-        break;
-      }
-      case Instruction::CONST_METHOD_HANDLE: {
-        PREAMBLE();
-        ClassLinker* cl = Runtime::Current()->GetClassLinker();
-        ObjPtr<mirror::MethodHandle> mh = cl->ResolveMethodHandle(self,
-                                                                  inst->VRegB_21c(),
-                                                                  shadow_frame.GetMethod());
-        if (UNLIKELY(mh == nullptr)) {
-          HANDLE_PENDING_EXCEPTION();
-        } else {
-          shadow_frame.SetVRegReference(inst->VRegA_21c(inst_data), mh);
-          inst = inst->Next_2xx();
-        }
-        break;
-      }
-      case Instruction::CONST_METHOD_TYPE: {
-        PREAMBLE();
-        ClassLinker* cl = Runtime::Current()->GetClassLinker();
-        ObjPtr<mirror::MethodType> mt = cl->ResolveMethodType(self,
-                                                              dex::ProtoIndex(inst->VRegB_21c()),
-                                                              shadow_frame.GetMethod());
-        if (UNLIKELY(mt == nullptr)) {
-          HANDLE_PENDING_EXCEPTION();
-        } else {
-          shadow_frame.SetVRegReference(inst->VRegA_21c(inst_data), mt);
-          inst = inst->Next_2xx();
-        }
-        break;
-      }
-      case Instruction::MONITOR_ENTER: {
-        PREAMBLE();
-        HANDLE_ASYNC_EXCEPTION();
-        ObjPtr<mirror::Object> obj = shadow_frame.GetVRegReference(inst->VRegA_11x(inst_data));
-        if (UNLIKELY(obj == nullptr)) {
-          ThrowNullPointerExceptionFromInterpreter();
-          HANDLE_PENDING_EXCEPTION();
-        } else {
-          DoMonitorEnter<do_assignability_check>(self, &shadow_frame, obj);
-          POSSIBLY_HANDLE_PENDING_EXCEPTION(self->IsExceptionPending(), Next_1xx);
-        }
-        break;
-      }
-      case Instruction::MONITOR_EXIT: {
-        PREAMBLE();
-        HANDLE_ASYNC_EXCEPTION();
-        ObjPtr<mirror::Object> obj = shadow_frame.GetVRegReference(inst->VRegA_11x(inst_data));
-        if (UNLIKELY(obj == nullptr)) {
-          ThrowNullPointerExceptionFromInterpreter();
-          HANDLE_PENDING_EXCEPTION();
-        } else {
-          DoMonitorExit<do_assignability_check>(self, &shadow_frame, obj);
-          POSSIBLY_HANDLE_PENDING_EXCEPTION(self->IsExceptionPending(), Next_1xx);
-        }
-        break;
-      }
-      case Instruction::CHECK_CAST: {
-        PREAMBLE();
-        ObjPtr<mirror::Class> c = ResolveVerifyAndClinit(dex::TypeIndex(inst->VRegB_21c()),
-                                                         shadow_frame.GetMethod(),
-                                                         self,
-                                                         false,
-                                                         do_access_check);
-        if (UNLIKELY(c == nullptr)) {
-          HANDLE_PENDING_EXCEPTION();
-        } else {
-          ObjPtr<mirror::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 {
-            inst = inst->Next_2xx();
-          }
-        }
-        break;
-      }
-      case Instruction::INSTANCE_OF: {
-        PREAMBLE();
-        ObjPtr<mirror::Class> c = ResolveVerifyAndClinit(dex::TypeIndex(inst->VRegC_22c()),
-                                                         shadow_frame.GetMethod(),
-                                                         self,
-                                                         false,
-                                                         do_access_check);
-        if (UNLIKELY(c == nullptr)) {
-          HANDLE_PENDING_EXCEPTION();
-        } else {
-          ObjPtr<mirror::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);
-          inst = inst->Next_2xx();
-        }
-        break;
-      }
-      case Instruction::ARRAY_LENGTH:  {
-        PREAMBLE();
-        ObjPtr<mirror::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());
-          inst = inst->Next_1xx();
-        }
-        break;
-      }
-      case Instruction::NEW_INSTANCE: {
-        PREAMBLE();
-        ObjPtr<mirror::Object> obj = nullptr;
-        ObjPtr<mirror::Class> c = ResolveVerifyAndClinit(dex::TypeIndex(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<true>(
-                c.Ptr(),
-                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",
-                              obj->PrettyTypeOf().c_str());
-            HANDLE_PENDING_EXCEPTION();
-            break;
-          }
-          shadow_frame.SetVRegReference(inst->VRegA_21c(inst_data), obj);
-          inst = inst->Next_2xx();
-        }
-        break;
-      }
-      case Instruction::NEW_ARRAY: {
-        PREAMBLE();
-        int32_t length = shadow_frame.GetVReg(inst->VRegB_22c(inst_data));
-        ObjPtr<mirror::Object> obj = AllocArrayFromCode<do_access_check, true>(
-            dex::TypeIndex(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);
-          inst = inst->Next_2xx();
-        }
-        break;
-      }
-      case Instruction::FILLED_NEW_ARRAY: {
-        PREAMBLE();
-        bool success =
-            DoFilledNewArray<false, do_access_check, transaction_active>(inst, shadow_frame, self,
-                                                                         &result_register);
-        POSSIBLY_HANDLE_PENDING_EXCEPTION(!success, Next_3xx);
-        break;
-      }
-      case Instruction::FILLED_NEW_ARRAY_RANGE: {
-        PREAMBLE();
-        bool success =
-            DoFilledNewArray<true, do_access_check, transaction_active>(inst, shadow_frame,
-                                                                        self, &result_register);
-        POSSIBLY_HANDLE_PENDING_EXCEPTION(!success, Next_3xx);
-        break;
-      }
-      case Instruction::FILL_ARRAY_DATA: {
-        PREAMBLE();
-        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);
-        ObjPtr<mirror::Object> obj = shadow_frame.GetVRegReference(inst->VRegA_31t(inst_data));
-        bool success = FillArrayData(obj, payload);
-        if (!success) {
-          HANDLE_PENDING_EXCEPTION();
-          break;
-        }
-        if (transaction_active) {
-          RecordArrayElementsInTransaction(obj->AsArray(), payload->element_count);
-        }
-        inst = inst->Next_3xx();
-        break;
-      }
-      case Instruction::THROW: {
-        PREAMBLE();
-        HANDLE_ASYNC_EXCEPTION();
-        ObjPtr<mirror::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/InternalError;",
-                                   "Throwing '%s' that is not instance of Throwable",
-                                   exception->GetClass()->GetDescriptor(&temp));
-        } else {
-          self->SetException(exception->AsThrowable());
-        }
-        HANDLE_PENDING_EXCEPTION();
-        break;
-      }
-      case Instruction::GOTO: {
-        PREAMBLE();
-        HANDLE_ASYNC_EXCEPTION();
-        int8_t offset = inst->VRegA_10t(inst_data);
-        BRANCH_INSTRUMENTATION(offset);
-        inst = inst->RelativeAt(offset);
-        HANDLE_BACKWARD_BRANCH(offset);
-        break;
-      }
-      case Instruction::GOTO_16: {
-        PREAMBLE();
-        HANDLE_ASYNC_EXCEPTION();
-        int16_t offset = inst->VRegA_20t();
-        BRANCH_INSTRUMENTATION(offset);
-        inst = inst->RelativeAt(offset);
-        HANDLE_BACKWARD_BRANCH(offset);
-        break;
-      }
-      case Instruction::GOTO_32: {
-        PREAMBLE();
-        HANDLE_ASYNC_EXCEPTION();
-        int32_t offset = inst->VRegA_30t();
-        BRANCH_INSTRUMENTATION(offset);
-        inst = inst->RelativeAt(offset);
-        HANDLE_BACKWARD_BRANCH(offset);
-        break;
-      }
-      case Instruction::PACKED_SWITCH: {
-        PREAMBLE();
-        int32_t offset = DoPackedSwitch(inst, shadow_frame, inst_data);
-        BRANCH_INSTRUMENTATION(offset);
-        inst = inst->RelativeAt(offset);
-        HANDLE_BACKWARD_BRANCH(offset);
-        break;
-      }
-      case Instruction::SPARSE_SWITCH: {
-        PREAMBLE();
-        int32_t offset = DoSparseSwitch(inst, shadow_frame, inst_data);
-        BRANCH_INSTRUMENTATION(offset);
-        inst = inst->RelativeAt(offset);
-        HANDLE_BACKWARD_BRANCH(offset);
-        break;
-      }
-
-#pragma clang diagnostic push
-#pragma clang diagnostic ignored "-Wfloat-equal"
-
-      case Instruction::CMPL_FLOAT: {
-        PREAMBLE();
-        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);
-        inst = inst->Next_2xx();
-        break;
-      }
-      case Instruction::CMPG_FLOAT: {
-        PREAMBLE();
-        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);
-        inst = inst->Next_2xx();
-        break;
-      }
-      case Instruction::CMPL_DOUBLE: {
-        PREAMBLE();
-        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);
-        inst = inst->Next_2xx();
-        break;
-      }
-
-      case Instruction::CMPG_DOUBLE: {
-        PREAMBLE();
-        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);
-        inst = inst->Next_2xx();
-        break;
-      }
-
-#pragma clang diagnostic pop
-
-      case Instruction::CMP_LONG: {
-        PREAMBLE();
-        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);
-        inst = inst->Next_2xx();
-        break;
-      }
-      case Instruction::IF_EQ: {
-        PREAMBLE();
-        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);
-          inst = inst->RelativeAt(offset);
-          HANDLE_BACKWARD_BRANCH(offset);
-        } else {
-          BRANCH_INSTRUMENTATION(2);
-          inst = inst->Next_2xx();
-        }
-        break;
-      }
-      case Instruction::IF_NE: {
-        PREAMBLE();
-        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);
-          inst = inst->RelativeAt(offset);
-          HANDLE_BACKWARD_BRANCH(offset);
-        } else {
-          BRANCH_INSTRUMENTATION(2);
-          inst = inst->Next_2xx();
-        }
-        break;
-      }
-      case Instruction::IF_LT: {
-        PREAMBLE();
-        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);
-          inst = inst->RelativeAt(offset);
-          HANDLE_BACKWARD_BRANCH(offset);
-        } else {
-          BRANCH_INSTRUMENTATION(2);
-          inst = inst->Next_2xx();
-        }
-        break;
-      }
-      case Instruction::IF_GE: {
-        PREAMBLE();
-        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);
-          inst = inst->RelativeAt(offset);
-          HANDLE_BACKWARD_BRANCH(offset);
-        } else {
-          BRANCH_INSTRUMENTATION(2);
-          inst = inst->Next_2xx();
-        }
-        break;
-      }
-      case Instruction::IF_GT: {
-        PREAMBLE();
-        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);
-          inst = inst->RelativeAt(offset);
-          HANDLE_BACKWARD_BRANCH(offset);
-        } else {
-          BRANCH_INSTRUMENTATION(2);
-          inst = inst->Next_2xx();
-        }
-        break;
-      }
-      case Instruction::IF_LE: {
-        PREAMBLE();
-        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);
-          inst = inst->RelativeAt(offset);
-          HANDLE_BACKWARD_BRANCH(offset);
-        } else {
-          BRANCH_INSTRUMENTATION(2);
-          inst = inst->Next_2xx();
-        }
-        break;
-      }
-      case Instruction::IF_EQZ: {
-        PREAMBLE();
-        if (shadow_frame.GetVReg(inst->VRegA_21t(inst_data)) == 0) {
-          int16_t offset = inst->VRegB_21t();
-          BRANCH_INSTRUMENTATION(offset);
-          inst = inst->RelativeAt(offset);
-          HANDLE_BACKWARD_BRANCH(offset);
-        } else {
-          BRANCH_INSTRUMENTATION(2);
-          inst = inst->Next_2xx();
-        }
-        break;
-      }
-      case Instruction::IF_NEZ: {
-        PREAMBLE();
-        if (shadow_frame.GetVReg(inst->VRegA_21t(inst_data)) != 0) {
-          int16_t offset = inst->VRegB_21t();
-          BRANCH_INSTRUMENTATION(offset);
-          inst = inst->RelativeAt(offset);
-          HANDLE_BACKWARD_BRANCH(offset);
-        } else {
-          BRANCH_INSTRUMENTATION(2);
-          inst = inst->Next_2xx();
-        }
-        break;
-      }
-      case Instruction::IF_LTZ: {
-        PREAMBLE();
-        if (shadow_frame.GetVReg(inst->VRegA_21t(inst_data)) < 0) {
-          int16_t offset = inst->VRegB_21t();
-          BRANCH_INSTRUMENTATION(offset);
-          inst = inst->RelativeAt(offset);
-          HANDLE_BACKWARD_BRANCH(offset);
-        } else {
-          BRANCH_INSTRUMENTATION(2);
-          inst = inst->Next_2xx();
-        }
-        break;
-      }
-      case Instruction::IF_GEZ: {
-        PREAMBLE();
-        if (shadow_frame.GetVReg(inst->VRegA_21t(inst_data)) >= 0) {
-          int16_t offset = inst->VRegB_21t();
-          BRANCH_INSTRUMENTATION(offset);
-          inst = inst->RelativeAt(offset);
-          HANDLE_BACKWARD_BRANCH(offset);
-        } else {
-          BRANCH_INSTRUMENTATION(2);
-          inst = inst->Next_2xx();
-        }
-        break;
-      }
-      case Instruction::IF_GTZ: {
-        PREAMBLE();
-        if (shadow_frame.GetVReg(inst->VRegA_21t(inst_data)) > 0) {
-          int16_t offset = inst->VRegB_21t();
-          BRANCH_INSTRUMENTATION(offset);
-          inst = inst->RelativeAt(offset);
-          HANDLE_BACKWARD_BRANCH(offset);
-        } else {
-          BRANCH_INSTRUMENTATION(2);
-          inst = inst->Next_2xx();
-        }
-        break;
-      }
-      case Instruction::IF_LEZ:  {
-        PREAMBLE();
-        if (shadow_frame.GetVReg(inst->VRegA_21t(inst_data)) <= 0) {
-          int16_t offset = inst->VRegB_21t();
-          BRANCH_INSTRUMENTATION(offset);
-          inst = inst->RelativeAt(offset);
-          HANDLE_BACKWARD_BRANCH(offset);
-        } else {
-          BRANCH_INSTRUMENTATION(2);
-          inst = inst->Next_2xx();
-        }
-        break;
-      }
-      case Instruction::AGET_BOOLEAN: {
-        PREAMBLE();
-        ObjPtr<mirror::Object> a = shadow_frame.GetVRegReference(inst->VRegB_23x());
-        if (UNLIKELY(a == nullptr)) {
-          ThrowNullPointerExceptionFromInterpreter();
-          HANDLE_PENDING_EXCEPTION();
-          break;
-        }
-        int32_t index = shadow_frame.GetVReg(inst->VRegC_23x());
-        ObjPtr<mirror::BooleanArray> array = a->AsBooleanArray();
-        if (array->CheckIsValidIndex(index)) {
-          shadow_frame.SetVReg(inst->VRegA_23x(inst_data), array->GetWithoutChecks(index));
-          inst = inst->Next_2xx();
-        } else {
-          HANDLE_PENDING_EXCEPTION();
-        }
-        break;
-      }
-      case Instruction::AGET_BYTE: {
-        PREAMBLE();
-        ObjPtr<mirror::Object> a = shadow_frame.GetVRegReference(inst->VRegB_23x());
-        if (UNLIKELY(a == nullptr)) {
-          ThrowNullPointerExceptionFromInterpreter();
-          HANDLE_PENDING_EXCEPTION();
-          break;
-        }
-        int32_t index = shadow_frame.GetVReg(inst->VRegC_23x());
-        ObjPtr<mirror::ByteArray> array = a->AsByteArray();
-        if (array->CheckIsValidIndex(index)) {
-          shadow_frame.SetVReg(inst->VRegA_23x(inst_data), array->GetWithoutChecks(index));
-          inst = inst->Next_2xx();
-        } else {
-          HANDLE_PENDING_EXCEPTION();
-        }
-        break;
-      }
-      case Instruction::AGET_CHAR: {
-        PREAMBLE();
-        ObjPtr<mirror::Object> a = shadow_frame.GetVRegReference(inst->VRegB_23x());
-        if (UNLIKELY(a == nullptr)) {
-          ThrowNullPointerExceptionFromInterpreter();
-          HANDLE_PENDING_EXCEPTION();
-          break;
-        }
-        int32_t index = shadow_frame.GetVReg(inst->VRegC_23x());
-        ObjPtr<mirror::CharArray> array = a->AsCharArray();
-        if (array->CheckIsValidIndex(index)) {
-          shadow_frame.SetVReg(inst->VRegA_23x(inst_data), array->GetWithoutChecks(index));
-          inst = inst->Next_2xx();
-        } else {
-          HANDLE_PENDING_EXCEPTION();
-        }
-        break;
-      }
-      case Instruction::AGET_SHORT: {
-        PREAMBLE();
-        ObjPtr<mirror::Object> a = shadow_frame.GetVRegReference(inst->VRegB_23x());
-        if (UNLIKELY(a == nullptr)) {
-          ThrowNullPointerExceptionFromInterpreter();
-          HANDLE_PENDING_EXCEPTION();
-          break;
-        }
-        int32_t index = shadow_frame.GetVReg(inst->VRegC_23x());
-        ObjPtr<mirror::ShortArray> array = a->AsShortArray();
-        if (array->CheckIsValidIndex(index)) {
-          shadow_frame.SetVReg(inst->VRegA_23x(inst_data), array->GetWithoutChecks(index));
-          inst = inst->Next_2xx();
-        } else {
-          HANDLE_PENDING_EXCEPTION();
-        }
-        break;
-      }
-      case Instruction::AGET: {
-        PREAMBLE();
-        ObjPtr<mirror::Object> a = shadow_frame.GetVRegReference(inst->VRegB_23x());
-        if (UNLIKELY(a == nullptr)) {
-          ThrowNullPointerExceptionFromInterpreter();
-          HANDLE_PENDING_EXCEPTION();
-          break;
-        }
-        int32_t index = shadow_frame.GetVReg(inst->VRegC_23x());
-        DCHECK(a->IsIntArray() || a->IsFloatArray()) << a->PrettyTypeOf();
-        ObjPtr<mirror::IntArray> array = ObjPtr<mirror::IntArray>::DownCast(a);
-        if (array->CheckIsValidIndex(index)) {
-          shadow_frame.SetVReg(inst->VRegA_23x(inst_data), array->GetWithoutChecks(index));
-          inst = inst->Next_2xx();
-        } else {
-          HANDLE_PENDING_EXCEPTION();
-        }
-        break;
-      }
-      case Instruction::AGET_WIDE:  {
-        PREAMBLE();
-        ObjPtr<mirror::Object> a = shadow_frame.GetVRegReference(inst->VRegB_23x());
-        if (UNLIKELY(a == nullptr)) {
-          ThrowNullPointerExceptionFromInterpreter();
-          HANDLE_PENDING_EXCEPTION();
-          break;
-        }
-        int32_t index = shadow_frame.GetVReg(inst->VRegC_23x());
-        DCHECK(a->IsLongArray() || a->IsDoubleArray()) << a->PrettyTypeOf();
-        ObjPtr<mirror::LongArray> array = ObjPtr<mirror::LongArray>::DownCast(a);
-        if (array->CheckIsValidIndex(index)) {
-          shadow_frame.SetVRegLong(inst->VRegA_23x(inst_data), array->GetWithoutChecks(index));
-          inst = inst->Next_2xx();
-        } else {
-          HANDLE_PENDING_EXCEPTION();
-        }
-        break;
-      }
-      case Instruction::AGET_OBJECT: {
-        PREAMBLE();
-        ObjPtr<mirror::Object> a = shadow_frame.GetVRegReference(inst->VRegB_23x());
-        if (UNLIKELY(a == nullptr)) {
-          ThrowNullPointerExceptionFromInterpreter();
-          HANDLE_PENDING_EXCEPTION();
-          break;
-        }
-        int32_t index = shadow_frame.GetVReg(inst->VRegC_23x());
-        ObjPtr<mirror::ObjectArray<mirror::Object>> array = a->AsObjectArray<mirror::Object>();
-        if (array->CheckIsValidIndex(index)) {
-          shadow_frame.SetVRegReference(inst->VRegA_23x(inst_data), array->GetWithoutChecks(index));
-          inst = inst->Next_2xx();
-        } else {
-          HANDLE_PENDING_EXCEPTION();
-        }
-        break;
-      }
-      case Instruction::APUT_BOOLEAN: {
-        PREAMBLE();
-        ObjPtr<mirror::Object> a = shadow_frame.GetVRegReference(inst->VRegB_23x());
-        if (UNLIKELY(a == nullptr)) {
-          ThrowNullPointerExceptionFromInterpreter();
-          HANDLE_PENDING_EXCEPTION();
-          break;
-        }
-        uint8_t val = shadow_frame.GetVReg(inst->VRegA_23x(inst_data));
-        int32_t index = shadow_frame.GetVReg(inst->VRegC_23x());
-        ObjPtr<mirror::BooleanArray> array = a->AsBooleanArray();
-        if (array->CheckIsValidIndex(index)) {
-          array->SetWithoutChecks<transaction_active>(index, val);
-          inst = inst->Next_2xx();
-        } else {
-          HANDLE_PENDING_EXCEPTION();
-        }
-        break;
-      }
-      case Instruction::APUT_BYTE: {
-        PREAMBLE();
-        ObjPtr<mirror::Object> a = shadow_frame.GetVRegReference(inst->VRegB_23x());
-        if (UNLIKELY(a == nullptr)) {
-          ThrowNullPointerExceptionFromInterpreter();
-          HANDLE_PENDING_EXCEPTION();
-          break;
-        }
-        int8_t val = shadow_frame.GetVReg(inst->VRegA_23x(inst_data));
-        int32_t index = shadow_frame.GetVReg(inst->VRegC_23x());
-        ObjPtr<mirror::ByteArray> array = a->AsByteArray();
-        if (array->CheckIsValidIndex(index)) {
-          array->SetWithoutChecks<transaction_active>(index, val);
-          inst = inst->Next_2xx();
-        } else {
-          HANDLE_PENDING_EXCEPTION();
-        }
-        break;
-      }
-      case Instruction::APUT_CHAR: {
-        PREAMBLE();
-        ObjPtr<mirror::Object> a = shadow_frame.GetVRegReference(inst->VRegB_23x());
-        if (UNLIKELY(a == nullptr)) {
-          ThrowNullPointerExceptionFromInterpreter();
-          HANDLE_PENDING_EXCEPTION();
-          break;
-        }
-        uint16_t val = shadow_frame.GetVReg(inst->VRegA_23x(inst_data));
-        int32_t index = shadow_frame.GetVReg(inst->VRegC_23x());
-        ObjPtr<mirror::CharArray> array = a->AsCharArray();
-        if (array->CheckIsValidIndex(index)) {
-          array->SetWithoutChecks<transaction_active>(index, val);
-          inst = inst->Next_2xx();
-        } else {
-          HANDLE_PENDING_EXCEPTION();
-        }
-        break;
-      }
-      case Instruction::APUT_SHORT: {
-        PREAMBLE();
-        ObjPtr<mirror::Object> a = shadow_frame.GetVRegReference(inst->VRegB_23x());
-        if (UNLIKELY(a == nullptr)) {
-          ThrowNullPointerExceptionFromInterpreter();
-          HANDLE_PENDING_EXCEPTION();
-          break;
-        }
-        int16_t val = shadow_frame.GetVReg(inst->VRegA_23x(inst_data));
-        int32_t index = shadow_frame.GetVReg(inst->VRegC_23x());
-        ObjPtr<mirror::ShortArray> array = a->AsShortArray();
-        if (array->CheckIsValidIndex(index)) {
-          array->SetWithoutChecks<transaction_active>(index, val);
-          inst = inst->Next_2xx();
-        } else {
-          HANDLE_PENDING_EXCEPTION();
-        }
-        break;
-      }
-      case Instruction::APUT: {
-        PREAMBLE();
-        ObjPtr<mirror::Object> a = shadow_frame.GetVRegReference(inst->VRegB_23x());
-        if (UNLIKELY(a == nullptr)) {
-          ThrowNullPointerExceptionFromInterpreter();
-          HANDLE_PENDING_EXCEPTION();
-          break;
-        }
-        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()) << a->PrettyTypeOf();
-        ObjPtr<mirror::IntArray> array = ObjPtr<mirror::IntArray>::DownCast(a);
-        if (array->CheckIsValidIndex(index)) {
-          array->SetWithoutChecks<transaction_active>(index, val);
-          inst = inst->Next_2xx();
-        } else {
-          HANDLE_PENDING_EXCEPTION();
-        }
-        break;
-      }
-      case Instruction::APUT_WIDE: {
-        PREAMBLE();
-        ObjPtr<mirror::Object> a = shadow_frame.GetVRegReference(inst->VRegB_23x());
-        if (UNLIKELY(a == nullptr)) {
-          ThrowNullPointerExceptionFromInterpreter();
-          HANDLE_PENDING_EXCEPTION();
-          break;
-        }
-        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()) << a->PrettyTypeOf();
-        ObjPtr<mirror::LongArray> array = ObjPtr<mirror::LongArray>::DownCast(a);
-        if (array->CheckIsValidIndex(index)) {
-          array->SetWithoutChecks<transaction_active>(index, val);
-          inst = inst->Next_2xx();
-        } else {
-          HANDLE_PENDING_EXCEPTION();
-        }
-        break;
-      }
-      case Instruction::APUT_OBJECT: {
-        PREAMBLE();
-        ObjPtr<mirror::Object> a = shadow_frame.GetVRegReference(inst->VRegB_23x());
-        if (UNLIKELY(a == nullptr)) {
-          ThrowNullPointerExceptionFromInterpreter();
-          HANDLE_PENDING_EXCEPTION();
-          break;
-        }
-        int32_t index = shadow_frame.GetVReg(inst->VRegC_23x());
-        ObjPtr<mirror::Object> val = shadow_frame.GetVRegReference(inst->VRegA_23x(inst_data));
-        ObjPtr<mirror::ObjectArray<mirror::Object>> array = a->AsObjectArray<mirror::Object>();
-        if (array->CheckIsValidIndex(index) && array->CheckAssignable(val)) {
-          array->SetWithoutChecks<transaction_active>(index, val);
-          inst = inst->Next_2xx();
-        } else {
-          HANDLE_PENDING_EXCEPTION();
-        }
-        break;
-      }
-      case Instruction::IGET_BOOLEAN: {
-        PREAMBLE();
-        bool success = DoFieldGet<InstancePrimitiveRead, Primitive::kPrimBoolean, do_access_check>(
-            self, shadow_frame, inst, inst_data);
-        POSSIBLY_HANDLE_PENDING_EXCEPTION(!success, Next_2xx);
-        break;
-      }
-      case Instruction::IGET_BYTE: {
-        PREAMBLE();
-        bool success = DoFieldGet<InstancePrimitiveRead, Primitive::kPrimByte, do_access_check>(
-            self, shadow_frame, inst, inst_data);
-        POSSIBLY_HANDLE_PENDING_EXCEPTION(!success, Next_2xx);
-        break;
-      }
-      case Instruction::IGET_CHAR: {
-        PREAMBLE();
-        bool success = DoFieldGet<InstancePrimitiveRead, Primitive::kPrimChar, do_access_check>(
-            self, shadow_frame, inst, inst_data);
-        POSSIBLY_HANDLE_PENDING_EXCEPTION(!success, Next_2xx);
-        break;
-      }
-      case Instruction::IGET_SHORT: {
-        PREAMBLE();
-        bool success = DoFieldGet<InstancePrimitiveRead, Primitive::kPrimShort, do_access_check>(
-            self, shadow_frame, inst, inst_data);
-        POSSIBLY_HANDLE_PENDING_EXCEPTION(!success, Next_2xx);
-        break;
-      }
-      case Instruction::IGET: {
-        PREAMBLE();
-        bool success = DoFieldGet<InstancePrimitiveRead, Primitive::kPrimInt, do_access_check>(
-            self, shadow_frame, inst, inst_data);
-        POSSIBLY_HANDLE_PENDING_EXCEPTION(!success, Next_2xx);
-        break;
-      }
-      case Instruction::IGET_WIDE: {
-        PREAMBLE();
-        bool success = DoFieldGet<InstancePrimitiveRead, Primitive::kPrimLong, do_access_check>(
-            self, shadow_frame, inst, inst_data);
-        POSSIBLY_HANDLE_PENDING_EXCEPTION(!success, Next_2xx);
-        break;
-      }
-      case Instruction::IGET_OBJECT: {
-        PREAMBLE();
-        bool success = DoFieldGet<InstanceObjectRead, Primitive::kPrimNot, do_access_check>(
-            self, shadow_frame, inst, inst_data);
-        POSSIBLY_HANDLE_PENDING_EXCEPTION(!success, Next_2xx);
-        break;
-      }
-      case Instruction::IGET_QUICK: {
-        PREAMBLE();
-        bool success = DoIGetQuick<Primitive::kPrimInt>(shadow_frame, inst, inst_data);
-        POSSIBLY_HANDLE_PENDING_EXCEPTION(!success, Next_2xx);
-        break;
-      }
-      case Instruction::IGET_WIDE_QUICK: {
-        PREAMBLE();
-        bool success = DoIGetQuick<Primitive::kPrimLong>(shadow_frame, inst, inst_data);
-        POSSIBLY_HANDLE_PENDING_EXCEPTION(!success, Next_2xx);
-        break;
-      }
-      case Instruction::IGET_OBJECT_QUICK: {
-        PREAMBLE();
-        bool success = DoIGetQuick<Primitive::kPrimNot>(shadow_frame, inst, inst_data);
-        POSSIBLY_HANDLE_PENDING_EXCEPTION(!success, Next_2xx);
-        break;
-      }
-      case Instruction::IGET_BOOLEAN_QUICK: {
-        PREAMBLE();
-        bool success = DoIGetQuick<Primitive::kPrimBoolean>(shadow_frame, inst, inst_data);
-        POSSIBLY_HANDLE_PENDING_EXCEPTION(!success, Next_2xx);
-        break;
-      }
-      case Instruction::IGET_BYTE_QUICK: {
-        PREAMBLE();
-        bool success = DoIGetQuick<Primitive::kPrimByte>(shadow_frame, inst, inst_data);
-        POSSIBLY_HANDLE_PENDING_EXCEPTION(!success, Next_2xx);
-        break;
-      }
-      case Instruction::IGET_CHAR_QUICK: {
-        PREAMBLE();
-        bool success = DoIGetQuick<Primitive::kPrimChar>(shadow_frame, inst, inst_data);
-        POSSIBLY_HANDLE_PENDING_EXCEPTION(!success, Next_2xx);
-        break;
-      }
-      case Instruction::IGET_SHORT_QUICK: {
-        PREAMBLE();
-        bool success = DoIGetQuick<Primitive::kPrimShort>(shadow_frame, inst, inst_data);
-        POSSIBLY_HANDLE_PENDING_EXCEPTION(!success, Next_2xx);
-        break;
-      }
-      case Instruction::SGET_BOOLEAN: {
-        PREAMBLE();
-        bool success = DoFieldGet<StaticPrimitiveRead, Primitive::kPrimBoolean, do_access_check,
-            transaction_active>(self, shadow_frame, inst, inst_data);
-        POSSIBLY_HANDLE_PENDING_EXCEPTION(!success, Next_2xx);
-        break;
-      }
-      case Instruction::SGET_BYTE: {
-        PREAMBLE();
-        bool success = DoFieldGet<StaticPrimitiveRead, Primitive::kPrimByte, do_access_check,
-            transaction_active>(self, shadow_frame, inst, inst_data);
-        POSSIBLY_HANDLE_PENDING_EXCEPTION(!success, Next_2xx);
-        break;
-      }
-      case Instruction::SGET_CHAR: {
-        PREAMBLE();
-        bool success = DoFieldGet<StaticPrimitiveRead, Primitive::kPrimChar, do_access_check,
-            transaction_active>(self, shadow_frame, inst, inst_data);
-        POSSIBLY_HANDLE_PENDING_EXCEPTION(!success, Next_2xx);
-        break;
-      }
-      case Instruction::SGET_SHORT: {
-        PREAMBLE();
-        bool success = DoFieldGet<StaticPrimitiveRead, Primitive::kPrimShort, do_access_check,
-            transaction_active>(self, shadow_frame, inst, inst_data);
-        POSSIBLY_HANDLE_PENDING_EXCEPTION(!success, Next_2xx);
-        break;
-      }
-      case Instruction::SGET: {
-        PREAMBLE();
-        bool success = DoFieldGet<StaticPrimitiveRead, Primitive::kPrimInt, do_access_check,
-            transaction_active>(self, shadow_frame, inst, inst_data);
-        POSSIBLY_HANDLE_PENDING_EXCEPTION(!success, Next_2xx);
-        break;
-      }
-      case Instruction::SGET_WIDE: {
-        PREAMBLE();
-        bool success = DoFieldGet<StaticPrimitiveRead, Primitive::kPrimLong, do_access_check,
-            transaction_active>(self, shadow_frame, inst, inst_data);
-        POSSIBLY_HANDLE_PENDING_EXCEPTION(!success, Next_2xx);
-        break;
-      }
-      case Instruction::SGET_OBJECT: {
-        PREAMBLE();
-        bool success = DoFieldGet<StaticObjectRead, Primitive::kPrimNot, do_access_check,
-            transaction_active>(self, shadow_frame, inst, inst_data);
-        POSSIBLY_HANDLE_PENDING_EXCEPTION(!success, Next_2xx);
-        break;
-      }
-      case Instruction::IPUT_BOOLEAN: {
-        PREAMBLE();
-        bool success = DoFieldPut<InstancePrimitiveWrite, Primitive::kPrimBoolean, do_access_check,
-            transaction_active>(self, shadow_frame, inst, inst_data);
-        POSSIBLY_HANDLE_PENDING_EXCEPTION(!success, Next_2xx);
-        break;
-      }
-      case Instruction::IPUT_BYTE: {
-        PREAMBLE();
-        bool success = DoFieldPut<InstancePrimitiveWrite, Primitive::kPrimByte, do_access_check,
-            transaction_active>(self, shadow_frame, inst, inst_data);
-        POSSIBLY_HANDLE_PENDING_EXCEPTION(!success, Next_2xx);
-        break;
-      }
-      case Instruction::IPUT_CHAR: {
-        PREAMBLE();
-        bool success = DoFieldPut<InstancePrimitiveWrite, Primitive::kPrimChar, do_access_check,
-            transaction_active>(self, shadow_frame, inst, inst_data);
-        POSSIBLY_HANDLE_PENDING_EXCEPTION(!success, Next_2xx);
-        break;
-      }
-      case Instruction::IPUT_SHORT: {
-        PREAMBLE();
-        bool success = DoFieldPut<InstancePrimitiveWrite, Primitive::kPrimShort, do_access_check,
-            transaction_active>(self, shadow_frame, inst, inst_data);
-        POSSIBLY_HANDLE_PENDING_EXCEPTION(!success, Next_2xx);
-        break;
-      }
-      case Instruction::IPUT: {
-        PREAMBLE();
-        bool success = DoFieldPut<InstancePrimitiveWrite, Primitive::kPrimInt, do_access_check,
-            transaction_active>(self, shadow_frame, inst, inst_data);
-        POSSIBLY_HANDLE_PENDING_EXCEPTION(!success, Next_2xx);
-        break;
-      }
-      case Instruction::IPUT_WIDE: {
-        PREAMBLE();
-        bool success = DoFieldPut<InstancePrimitiveWrite, Primitive::kPrimLong, do_access_check,
-            transaction_active>(self, shadow_frame, inst, inst_data);
-        POSSIBLY_HANDLE_PENDING_EXCEPTION(!success, Next_2xx);
-        break;
-      }
-      case Instruction::IPUT_OBJECT: {
-        PREAMBLE();
-        bool success = DoFieldPut<InstanceObjectWrite, Primitive::kPrimNot, do_access_check,
-            transaction_active>(self, shadow_frame, inst, inst_data);
-        POSSIBLY_HANDLE_PENDING_EXCEPTION(!success, Next_2xx);
-        break;
-      }
-      case Instruction::IPUT_QUICK: {
-        PREAMBLE();
-        bool success = DoIPutQuick<Primitive::kPrimInt, transaction_active>(
-            shadow_frame, inst, inst_data);
-        POSSIBLY_HANDLE_PENDING_EXCEPTION(!success, Next_2xx);
-        break;
-      }
-      case Instruction::IPUT_BOOLEAN_QUICK: {
-        PREAMBLE();
-        bool success = DoIPutQuick<Primitive::kPrimBoolean, transaction_active>(
-            shadow_frame, inst, inst_data);
-        POSSIBLY_HANDLE_PENDING_EXCEPTION(!success, Next_2xx);
-        break;
-      }
-      case Instruction::IPUT_BYTE_QUICK: {
-        PREAMBLE();
-        bool success = DoIPutQuick<Primitive::kPrimByte, transaction_active>(
-            shadow_frame, inst, inst_data);
-        POSSIBLY_HANDLE_PENDING_EXCEPTION(!success, Next_2xx);
-        break;
-      }
-      case Instruction::IPUT_CHAR_QUICK: {
-        PREAMBLE();
-        bool success = DoIPutQuick<Primitive::kPrimChar, transaction_active>(
-            shadow_frame, inst, inst_data);
-        POSSIBLY_HANDLE_PENDING_EXCEPTION(!success, Next_2xx);
-        break;
-      }
-      case Instruction::IPUT_SHORT_QUICK: {
-        PREAMBLE();
-        bool success = DoIPutQuick<Primitive::kPrimShort, transaction_active>(
-            shadow_frame, inst, inst_data);
-        POSSIBLY_HANDLE_PENDING_EXCEPTION(!success, Next_2xx);
-        break;
-      }
-      case Instruction::IPUT_WIDE_QUICK: {
-        PREAMBLE();
-        bool success = DoIPutQuick<Primitive::kPrimLong, transaction_active>(
-            shadow_frame, inst, inst_data);
-        POSSIBLY_HANDLE_PENDING_EXCEPTION(!success, Next_2xx);
-        break;
-      }
-      case Instruction::IPUT_OBJECT_QUICK: {
-        PREAMBLE();
-        bool success = DoIPutQuick<Primitive::kPrimNot, transaction_active>(
-            shadow_frame, inst, inst_data);
-        POSSIBLY_HANDLE_PENDING_EXCEPTION(!success, Next_2xx);
-        break;
-      }
-      case Instruction::SPUT_BOOLEAN: {
-        PREAMBLE();
-        bool success = DoFieldPut<StaticPrimitiveWrite, Primitive::kPrimBoolean, do_access_check,
-            transaction_active>(self, shadow_frame, inst, inst_data);
-        POSSIBLY_HANDLE_PENDING_EXCEPTION(!success, Next_2xx);
-        break;
-      }
-      case Instruction::SPUT_BYTE: {
-        PREAMBLE();
-        bool success = DoFieldPut<StaticPrimitiveWrite, Primitive::kPrimByte, do_access_check,
-            transaction_active>(self, shadow_frame, inst, inst_data);
-        POSSIBLY_HANDLE_PENDING_EXCEPTION(!success, Next_2xx);
-        break;
-      }
-      case Instruction::SPUT_CHAR: {
-        PREAMBLE();
-        bool success = DoFieldPut<StaticPrimitiveWrite, Primitive::kPrimChar, do_access_check,
-            transaction_active>(self, shadow_frame, inst, inst_data);
-        POSSIBLY_HANDLE_PENDING_EXCEPTION(!success, Next_2xx);
-        break;
-      }
-      case Instruction::SPUT_SHORT: {
-        PREAMBLE();
-        bool success = DoFieldPut<StaticPrimitiveWrite, Primitive::kPrimShort, do_access_check,
-            transaction_active>(self, shadow_frame, inst, inst_data);
-        POSSIBLY_HANDLE_PENDING_EXCEPTION(!success, Next_2xx);
-        break;
-      }
-      case Instruction::SPUT: {
-        PREAMBLE();
-        bool success = DoFieldPut<StaticPrimitiveWrite, Primitive::kPrimInt, do_access_check,
-            transaction_active>(self, shadow_frame, inst, inst_data);
-        POSSIBLY_HANDLE_PENDING_EXCEPTION(!success, Next_2xx);
-        break;
-      }
-      case Instruction::SPUT_WIDE: {
-        PREAMBLE();
-        bool success = DoFieldPut<StaticPrimitiveWrite, Primitive::kPrimLong, do_access_check,
-            transaction_active>(self, shadow_frame, inst, inst_data);
-        POSSIBLY_HANDLE_PENDING_EXCEPTION(!success, Next_2xx);
-        break;
-      }
-      case Instruction::SPUT_OBJECT: {
-        PREAMBLE();
-        bool success = DoFieldPut<StaticObjectWrite, Primitive::kPrimNot, do_access_check,
-            transaction_active>(self, shadow_frame, inst, inst_data);
-        POSSIBLY_HANDLE_PENDING_EXCEPTION(!success, Next_2xx);
-        break;
-      }
-      case Instruction::INVOKE_VIRTUAL: {
-        PREAMBLE();
-        bool success = DoInvoke<kVirtual, false, do_access_check, /*is_mterp=*/ false>(
-            self, shadow_frame, inst, inst_data, &result_register);
-        POSSIBLY_HANDLE_PENDING_EXCEPTION_ON_INVOKE(!success);
-        break;
-      }
-      case Instruction::INVOKE_VIRTUAL_RANGE: {
-        PREAMBLE();
-        bool success = DoInvoke<kVirtual, true, do_access_check, /*is_mterp=*/ false>(
-            self, shadow_frame, inst, inst_data, &result_register);
-        POSSIBLY_HANDLE_PENDING_EXCEPTION_ON_INVOKE(!success);
-        break;
-      }
-      case Instruction::INVOKE_SUPER: {
-        PREAMBLE();
-        bool success = DoInvoke<kSuper, false, do_access_check, /*is_mterp=*/ false>(
-            self, shadow_frame, inst, inst_data, &result_register);
-        POSSIBLY_HANDLE_PENDING_EXCEPTION_ON_INVOKE(!success);
-        break;
-      }
-      case Instruction::INVOKE_SUPER_RANGE: {
-        PREAMBLE();
-        bool success = DoInvoke<kSuper, true, do_access_check, /*is_mterp=*/ false>(
-            self, shadow_frame, inst, inst_data, &result_register);
-        POSSIBLY_HANDLE_PENDING_EXCEPTION_ON_INVOKE(!success);
-        break;
-      }
-      case Instruction::INVOKE_DIRECT: {
-        PREAMBLE();
-        bool success = DoInvoke<kDirect, false, do_access_check, /*is_mterp=*/ false>(
-            self, shadow_frame, inst, inst_data, &result_register);
-        POSSIBLY_HANDLE_PENDING_EXCEPTION_ON_INVOKE(!success);
-        break;
-      }
-      case Instruction::INVOKE_DIRECT_RANGE: {
-        PREAMBLE();
-        bool success = DoInvoke<kDirect, true, do_access_check, /*is_mterp=*/ false>(
-            self, shadow_frame, inst, inst_data, &result_register);
-        POSSIBLY_HANDLE_PENDING_EXCEPTION_ON_INVOKE(!success);
-        break;
-      }
-      case Instruction::INVOKE_INTERFACE: {
-        PREAMBLE();
-        bool success = DoInvoke<kInterface, false, do_access_check, /*is_mterp=*/ false>(
-            self, shadow_frame, inst, inst_data, &result_register);
-        POSSIBLY_HANDLE_PENDING_EXCEPTION_ON_INVOKE(!success);
-        break;
-      }
-      case Instruction::INVOKE_INTERFACE_RANGE: {
-        PREAMBLE();
-        bool success = DoInvoke<kInterface, true, do_access_check, /*is_mterp=*/ false>(
-            self, shadow_frame, inst, inst_data, &result_register);
-        POSSIBLY_HANDLE_PENDING_EXCEPTION_ON_INVOKE(!success);
-        break;
-      }
-      case Instruction::INVOKE_STATIC: {
-        PREAMBLE();
-        bool success = DoInvoke<kStatic, false, do_access_check, /*is_mterp=*/ false>(
-            self, shadow_frame, inst, inst_data, &result_register);
-        POSSIBLY_HANDLE_PENDING_EXCEPTION_ON_INVOKE(!success);
-        break;
-      }
-      case Instruction::INVOKE_STATIC_RANGE: {
-        PREAMBLE();
-        bool success = DoInvoke<kStatic, true, do_access_check, /*is_mterp=*/ false>(
-            self, shadow_frame, inst, inst_data, &result_register);
-        POSSIBLY_HANDLE_PENDING_EXCEPTION_ON_INVOKE(!success);
-        break;
-      }
-      case Instruction::INVOKE_VIRTUAL_QUICK: {
-        PREAMBLE();
-        bool success = DoInvoke<kVirtual, false, do_access_check, /*is_mterp=*/ false,
-            /*is_quick=*/ true>(self, shadow_frame, inst, inst_data, &result_register);
-        POSSIBLY_HANDLE_PENDING_EXCEPTION_ON_INVOKE(!success);
-        break;
-      }
-      case Instruction::INVOKE_VIRTUAL_RANGE_QUICK: {
-        PREAMBLE();
-        bool success = DoInvoke<kVirtual, true, do_access_check, /*is_mterp=*/ false,
-            /*is_quick=*/ true>(self, shadow_frame, inst, inst_data, &result_register);
-        POSSIBLY_HANDLE_PENDING_EXCEPTION_ON_INVOKE(!success);
-        break;
-      }
-      case Instruction::INVOKE_POLYMORPHIC: {
-        PREAMBLE();
-        DCHECK(Runtime::Current()->IsMethodHandlesEnabled());
-        bool success = DoInvokePolymorphic</* is_range= */ false>(
-            self, shadow_frame, inst, inst_data, &result_register);
-        POSSIBLY_HANDLE_PENDING_EXCEPTION_ON_INVOKE_POLYMORPHIC(!success);
-        break;
-      }
-      case Instruction::INVOKE_POLYMORPHIC_RANGE: {
-        PREAMBLE();
-        DCHECK(Runtime::Current()->IsMethodHandlesEnabled());
-        bool success = DoInvokePolymorphic</* is_range= */ true>(
-            self, shadow_frame, inst, inst_data, &result_register);
-        POSSIBLY_HANDLE_PENDING_EXCEPTION_ON_INVOKE_POLYMORPHIC(!success);
-        break;
-      }
-      case Instruction::INVOKE_CUSTOM: {
-        PREAMBLE();
-        DCHECK(Runtime::Current()->IsMethodHandlesEnabled());
-        bool success = DoInvokeCustom</* is_range= */ false>(
-            self, shadow_frame, inst, inst_data, &result_register);
-        POSSIBLY_HANDLE_PENDING_EXCEPTION_ON_INVOKE(!success);
-        break;
-      }
-      case Instruction::INVOKE_CUSTOM_RANGE: {
-        PREAMBLE();
-        DCHECK(Runtime::Current()->IsMethodHandlesEnabled());
-        bool success = DoInvokeCustom</* is_range= */ true>(
-            self, shadow_frame, inst, inst_data, &result_register);
-        POSSIBLY_HANDLE_PENDING_EXCEPTION_ON_INVOKE(!success);
-        break;
-      }
-      case Instruction::NEG_INT:
-        PREAMBLE();
-        shadow_frame.SetVReg(
-            inst->VRegA_12x(inst_data), -shadow_frame.GetVReg(inst->VRegB_12x(inst_data)));
-        inst = inst->Next_1xx();
-        break;
-      case Instruction::NOT_INT:
-        PREAMBLE();
-        shadow_frame.SetVReg(
-            inst->VRegA_12x(inst_data), ~shadow_frame.GetVReg(inst->VRegB_12x(inst_data)));
-        inst = inst->Next_1xx();
-        break;
-      case Instruction::NEG_LONG:
-        PREAMBLE();
-        shadow_frame.SetVRegLong(
-            inst->VRegA_12x(inst_data), -shadow_frame.GetVRegLong(inst->VRegB_12x(inst_data)));
-        inst = inst->Next_1xx();
-        break;
-      case Instruction::NOT_LONG:
-        PREAMBLE();
-        shadow_frame.SetVRegLong(
-            inst->VRegA_12x(inst_data), ~shadow_frame.GetVRegLong(inst->VRegB_12x(inst_data)));
-        inst = inst->Next_1xx();
-        break;
-      case Instruction::NEG_FLOAT:
-        PREAMBLE();
-        shadow_frame.SetVRegFloat(
-            inst->VRegA_12x(inst_data), -shadow_frame.GetVRegFloat(inst->VRegB_12x(inst_data)));
-        inst = inst->Next_1xx();
-        break;
-      case Instruction::NEG_DOUBLE:
-        PREAMBLE();
-        shadow_frame.SetVRegDouble(
-            inst->VRegA_12x(inst_data), -shadow_frame.GetVRegDouble(inst->VRegB_12x(inst_data)));
-        inst = inst->Next_1xx();
-        break;
-      case Instruction::INT_TO_LONG:
-        PREAMBLE();
-        shadow_frame.SetVRegLong(inst->VRegA_12x(inst_data),
-                                 shadow_frame.GetVReg(inst->VRegB_12x(inst_data)));
-        inst = inst->Next_1xx();
-        break;
-      case Instruction::INT_TO_FLOAT:
-        PREAMBLE();
-        shadow_frame.SetVRegFloat(inst->VRegA_12x(inst_data),
-                                  shadow_frame.GetVReg(inst->VRegB_12x(inst_data)));
-        inst = inst->Next_1xx();
-        break;
-      case Instruction::INT_TO_DOUBLE:
-        PREAMBLE();
-        shadow_frame.SetVRegDouble(inst->VRegA_12x(inst_data),
-                                   shadow_frame.GetVReg(inst->VRegB_12x(inst_data)));
-        inst = inst->Next_1xx();
-        break;
-      case Instruction::LONG_TO_INT:
-        PREAMBLE();
-        shadow_frame.SetVReg(inst->VRegA_12x(inst_data),
-                             shadow_frame.GetVRegLong(inst->VRegB_12x(inst_data)));
-        inst = inst->Next_1xx();
-        break;
-      case Instruction::LONG_TO_FLOAT:
-        PREAMBLE();
-        shadow_frame.SetVRegFloat(inst->VRegA_12x(inst_data),
-                                  shadow_frame.GetVRegLong(inst->VRegB_12x(inst_data)));
-        inst = inst->Next_1xx();
-        break;
-      case Instruction::LONG_TO_DOUBLE:
-        PREAMBLE();
-        shadow_frame.SetVRegDouble(inst->VRegA_12x(inst_data),
-                                   shadow_frame.GetVRegLong(inst->VRegB_12x(inst_data)));
-        inst = inst->Next_1xx();
-        break;
-      case Instruction::FLOAT_TO_INT: {
-        PREAMBLE();
-        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);
-        inst = inst->Next_1xx();
-        break;
-      }
-      case Instruction::FLOAT_TO_LONG: {
-        PREAMBLE();
-        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);
-        inst = inst->Next_1xx();
-        break;
-      }
-      case Instruction::FLOAT_TO_DOUBLE:
-        PREAMBLE();
-        shadow_frame.SetVRegDouble(inst->VRegA_12x(inst_data),
-                                   shadow_frame.GetVRegFloat(inst->VRegB_12x(inst_data)));
-        inst = inst->Next_1xx();
-        break;
-      case Instruction::DOUBLE_TO_INT: {
-        PREAMBLE();
-        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);
-        inst = inst->Next_1xx();
-        break;
-      }
-      case Instruction::DOUBLE_TO_LONG: {
-        PREAMBLE();
-        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);
-        inst = inst->Next_1xx();
-        break;
-      }
-      case Instruction::DOUBLE_TO_FLOAT:
-        PREAMBLE();
-        shadow_frame.SetVRegFloat(inst->VRegA_12x(inst_data),
-                                  shadow_frame.GetVRegDouble(inst->VRegB_12x(inst_data)));
-        inst = inst->Next_1xx();
-        break;
-      case Instruction::INT_TO_BYTE:
-        PREAMBLE();
-        shadow_frame.SetVReg(inst->VRegA_12x(inst_data), static_cast<int8_t>(
-            shadow_frame.GetVReg(inst->VRegB_12x(inst_data))));
-        inst = inst->Next_1xx();
-        break;
-      case Instruction::INT_TO_CHAR:
-        PREAMBLE();
-        shadow_frame.SetVReg(inst->VRegA_12x(inst_data), static_cast<uint16_t>(
-            shadow_frame.GetVReg(inst->VRegB_12x(inst_data))));
-        inst = inst->Next_1xx();
-        break;
-      case Instruction::INT_TO_SHORT:
-        PREAMBLE();
-        shadow_frame.SetVReg(inst->VRegA_12x(inst_data), static_cast<int16_t>(
-            shadow_frame.GetVReg(inst->VRegB_12x(inst_data))));
-        inst = inst->Next_1xx();
-        break;
-      case Instruction::ADD_INT: {
-        PREAMBLE();
-        shadow_frame.SetVReg(inst->VRegA_23x(inst_data),
-                             SafeAdd(shadow_frame.GetVReg(inst->VRegB_23x()),
-                                     shadow_frame.GetVReg(inst->VRegC_23x())));
-        inst = inst->Next_2xx();
-        break;
-      }
-      case Instruction::SUB_INT:
-        PREAMBLE();
-        shadow_frame.SetVReg(inst->VRegA_23x(inst_data),
-                             SafeSub(shadow_frame.GetVReg(inst->VRegB_23x()),
-                                     shadow_frame.GetVReg(inst->VRegC_23x())));
-        inst = inst->Next_2xx();
-        break;
-      case Instruction::MUL_INT:
-        PREAMBLE();
-        shadow_frame.SetVReg(inst->VRegA_23x(inst_data),
-                             SafeMul(shadow_frame.GetVReg(inst->VRegB_23x()),
-                                     shadow_frame.GetVReg(inst->VRegC_23x())));
-        inst = inst->Next_2xx();
-        break;
-      case Instruction::DIV_INT: {
-        PREAMBLE();
-        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, Next_2xx);
-        break;
-      }
-      case Instruction::REM_INT: {
-        PREAMBLE();
-        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, Next_2xx);
-        break;
-      }
-      case Instruction::SHL_INT:
-        PREAMBLE();
-        shadow_frame.SetVReg(inst->VRegA_23x(inst_data),
-                             shadow_frame.GetVReg(inst->VRegB_23x()) <<
-                             (shadow_frame.GetVReg(inst->VRegC_23x()) & 0x1f));
-        inst = inst->Next_2xx();
-        break;
-      case Instruction::SHR_INT:
-        PREAMBLE();
-        shadow_frame.SetVReg(inst->VRegA_23x(inst_data),
-                             shadow_frame.GetVReg(inst->VRegB_23x()) >>
-                             (shadow_frame.GetVReg(inst->VRegC_23x()) & 0x1f));
-        inst = inst->Next_2xx();
-        break;
-      case Instruction::USHR_INT:
-        PREAMBLE();
-        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));
-        inst = inst->Next_2xx();
-        break;
-      case Instruction::AND_INT:
-        PREAMBLE();
-        shadow_frame.SetVReg(inst->VRegA_23x(inst_data),
-                             shadow_frame.GetVReg(inst->VRegB_23x()) &
-                             shadow_frame.GetVReg(inst->VRegC_23x()));
-        inst = inst->Next_2xx();
-        break;
-      case Instruction::OR_INT:
-        PREAMBLE();
-        shadow_frame.SetVReg(inst->VRegA_23x(inst_data),
-                             shadow_frame.GetVReg(inst->VRegB_23x()) |
-                             shadow_frame.GetVReg(inst->VRegC_23x()));
-        inst = inst->Next_2xx();
-        break;
-      case Instruction::XOR_INT:
-        PREAMBLE();
-        shadow_frame.SetVReg(inst->VRegA_23x(inst_data),
-                             shadow_frame.GetVReg(inst->VRegB_23x()) ^
-                             shadow_frame.GetVReg(inst->VRegC_23x()));
-        inst = inst->Next_2xx();
-        break;
-      case Instruction::ADD_LONG:
-        PREAMBLE();
-        shadow_frame.SetVRegLong(inst->VRegA_23x(inst_data),
-                                 SafeAdd(shadow_frame.GetVRegLong(inst->VRegB_23x()),
-                                         shadow_frame.GetVRegLong(inst->VRegC_23x())));
-        inst = inst->Next_2xx();
-        break;
-      case Instruction::SUB_LONG:
-        PREAMBLE();
-        shadow_frame.SetVRegLong(inst->VRegA_23x(inst_data),
-                                 SafeSub(shadow_frame.GetVRegLong(inst->VRegB_23x()),
-                                         shadow_frame.GetVRegLong(inst->VRegC_23x())));
-        inst = inst->Next_2xx();
-        break;
-      case Instruction::MUL_LONG:
-        PREAMBLE();
-        shadow_frame.SetVRegLong(inst->VRegA_23x(inst_data),
-                                 SafeMul(shadow_frame.GetVRegLong(inst->VRegB_23x()),
-                                         shadow_frame.GetVRegLong(inst->VRegC_23x())));
-        inst = inst->Next_2xx();
-        break;
-      case Instruction::DIV_LONG:
-        PREAMBLE();
-        DoLongDivide(shadow_frame, inst->VRegA_23x(inst_data),
-                     shadow_frame.GetVRegLong(inst->VRegB_23x()),
-                     shadow_frame.GetVRegLong(inst->VRegC_23x()));
-        POSSIBLY_HANDLE_PENDING_EXCEPTION(self->IsExceptionPending(), Next_2xx);
-        break;
-      case Instruction::REM_LONG:
-        PREAMBLE();
-        DoLongRemainder(shadow_frame, inst->VRegA_23x(inst_data),
-                        shadow_frame.GetVRegLong(inst->VRegB_23x()),
-                        shadow_frame.GetVRegLong(inst->VRegC_23x()));
-        POSSIBLY_HANDLE_PENDING_EXCEPTION(self->IsExceptionPending(), Next_2xx);
-        break;
-      case Instruction::AND_LONG:
-        PREAMBLE();
-        shadow_frame.SetVRegLong(inst->VRegA_23x(inst_data),
-                                 shadow_frame.GetVRegLong(inst->VRegB_23x()) &
-                                 shadow_frame.GetVRegLong(inst->VRegC_23x()));
-        inst = inst->Next_2xx();
-        break;
-      case Instruction::OR_LONG:
-        PREAMBLE();
-        shadow_frame.SetVRegLong(inst->VRegA_23x(inst_data),
-                                 shadow_frame.GetVRegLong(inst->VRegB_23x()) |
-                                 shadow_frame.GetVRegLong(inst->VRegC_23x()));
-        inst = inst->Next_2xx();
-        break;
-      case Instruction::XOR_LONG:
-        PREAMBLE();
-        shadow_frame.SetVRegLong(inst->VRegA_23x(inst_data),
-                                 shadow_frame.GetVRegLong(inst->VRegB_23x()) ^
-                                 shadow_frame.GetVRegLong(inst->VRegC_23x()));
-        inst = inst->Next_2xx();
-        break;
-      case Instruction::SHL_LONG:
-        PREAMBLE();
-        shadow_frame.SetVRegLong(inst->VRegA_23x(inst_data),
-                                 shadow_frame.GetVRegLong(inst->VRegB_23x()) <<
-                                 (shadow_frame.GetVReg(inst->VRegC_23x()) & 0x3f));
-        inst = inst->Next_2xx();
-        break;
-      case Instruction::SHR_LONG:
-        PREAMBLE();
-        shadow_frame.SetVRegLong(inst->VRegA_23x(inst_data),
-                                 shadow_frame.GetVRegLong(inst->VRegB_23x()) >>
-                                 (shadow_frame.GetVReg(inst->VRegC_23x()) & 0x3f));
-        inst = inst->Next_2xx();
-        break;
-      case Instruction::USHR_LONG:
-        PREAMBLE();
-        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));
-        inst = inst->Next_2xx();
-        break;
-      case Instruction::ADD_FLOAT:
-        PREAMBLE();
-        shadow_frame.SetVRegFloat(inst->VRegA_23x(inst_data),
-                                  shadow_frame.GetVRegFloat(inst->VRegB_23x()) +
-                                  shadow_frame.GetVRegFloat(inst->VRegC_23x()));
-        inst = inst->Next_2xx();
-        break;
-      case Instruction::SUB_FLOAT:
-        PREAMBLE();
-        shadow_frame.SetVRegFloat(inst->VRegA_23x(inst_data),
-                                  shadow_frame.GetVRegFloat(inst->VRegB_23x()) -
-                                  shadow_frame.GetVRegFloat(inst->VRegC_23x()));
-        inst = inst->Next_2xx();
-        break;
-      case Instruction::MUL_FLOAT:
-        PREAMBLE();
-        shadow_frame.SetVRegFloat(inst->VRegA_23x(inst_data),
-                                  shadow_frame.GetVRegFloat(inst->VRegB_23x()) *
-                                  shadow_frame.GetVRegFloat(inst->VRegC_23x()));
-        inst = inst->Next_2xx();
-        break;
-      case Instruction::DIV_FLOAT:
-        PREAMBLE();
-        shadow_frame.SetVRegFloat(inst->VRegA_23x(inst_data),
-                                  shadow_frame.GetVRegFloat(inst->VRegB_23x()) /
-                                  shadow_frame.GetVRegFloat(inst->VRegC_23x()));
-        inst = inst->Next_2xx();
-        break;
-      case Instruction::REM_FLOAT:
-        PREAMBLE();
-        shadow_frame.SetVRegFloat(inst->VRegA_23x(inst_data),
-                                  fmodf(shadow_frame.GetVRegFloat(inst->VRegB_23x()),
-                                        shadow_frame.GetVRegFloat(inst->VRegC_23x())));
-        inst = inst->Next_2xx();
-        break;
-      case Instruction::ADD_DOUBLE:
-        PREAMBLE();
-        shadow_frame.SetVRegDouble(inst->VRegA_23x(inst_data),
-                                   shadow_frame.GetVRegDouble(inst->VRegB_23x()) +
-                                   shadow_frame.GetVRegDouble(inst->VRegC_23x()));
-        inst = inst->Next_2xx();
-        break;
-      case Instruction::SUB_DOUBLE:
-        PREAMBLE();
-        shadow_frame.SetVRegDouble(inst->VRegA_23x(inst_data),
-                                   shadow_frame.GetVRegDouble(inst->VRegB_23x()) -
-                                   shadow_frame.GetVRegDouble(inst->VRegC_23x()));
-        inst = inst->Next_2xx();
-        break;
-      case Instruction::MUL_DOUBLE:
-        PREAMBLE();
-        shadow_frame.SetVRegDouble(inst->VRegA_23x(inst_data),
-                                   shadow_frame.GetVRegDouble(inst->VRegB_23x()) *
-                                   shadow_frame.GetVRegDouble(inst->VRegC_23x()));
-        inst = inst->Next_2xx();
-        break;
-      case Instruction::DIV_DOUBLE:
-        PREAMBLE();
-        shadow_frame.SetVRegDouble(inst->VRegA_23x(inst_data),
-                                   shadow_frame.GetVRegDouble(inst->VRegB_23x()) /
-                                   shadow_frame.GetVRegDouble(inst->VRegC_23x()));
-        inst = inst->Next_2xx();
-        break;
-      case Instruction::REM_DOUBLE:
-        PREAMBLE();
-        shadow_frame.SetVRegDouble(inst->VRegA_23x(inst_data),
-                                   fmod(shadow_frame.GetVRegDouble(inst->VRegB_23x()),
-                                        shadow_frame.GetVRegDouble(inst->VRegC_23x())));
-        inst = inst->Next_2xx();
-        break;
-      case Instruction::ADD_INT_2ADDR: {
-        PREAMBLE();
-        uint4_t vregA = inst->VRegA_12x(inst_data);
-        shadow_frame.SetVReg(vregA, SafeAdd(shadow_frame.GetVReg(vregA),
-                                            shadow_frame.GetVReg(inst->VRegB_12x(inst_data))));
-        inst = inst->Next_1xx();
-        break;
-      }
-      case Instruction::SUB_INT_2ADDR: {
-        PREAMBLE();
-        uint4_t vregA = inst->VRegA_12x(inst_data);
-        shadow_frame.SetVReg(vregA,
-                             SafeSub(shadow_frame.GetVReg(vregA),
-                                     shadow_frame.GetVReg(inst->VRegB_12x(inst_data))));
-        inst = inst->Next_1xx();
-        break;
-      }
-      case Instruction::MUL_INT_2ADDR: {
-        PREAMBLE();
-        uint4_t vregA = inst->VRegA_12x(inst_data);
-        shadow_frame.SetVReg(vregA,
-                             SafeMul(shadow_frame.GetVReg(vregA),
-                                     shadow_frame.GetVReg(inst->VRegB_12x(inst_data))));
-        inst = inst->Next_1xx();
-        break;
-      }
-      case Instruction::DIV_INT_2ADDR: {
-        PREAMBLE();
-        uint4_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, Next_1xx);
-        break;
-      }
-      case Instruction::REM_INT_2ADDR: {
-        PREAMBLE();
-        uint4_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, Next_1xx);
-        break;
-      }
-      case Instruction::SHL_INT_2ADDR: {
-        PREAMBLE();
-        uint4_t vregA = inst->VRegA_12x(inst_data);
-        shadow_frame.SetVReg(vregA,
-                             shadow_frame.GetVReg(vregA) <<
-                             (shadow_frame.GetVReg(inst->VRegB_12x(inst_data)) & 0x1f));
-        inst = inst->Next_1xx();
-        break;
-      }
-      case Instruction::SHR_INT_2ADDR: {
-        PREAMBLE();
-        uint4_t vregA = inst->VRegA_12x(inst_data);
-        shadow_frame.SetVReg(vregA,
-                             shadow_frame.GetVReg(vregA) >>
-                             (shadow_frame.GetVReg(inst->VRegB_12x(inst_data)) & 0x1f));
-        inst = inst->Next_1xx();
-        break;
-      }
-      case Instruction::USHR_INT_2ADDR: {
-        PREAMBLE();
-        uint4_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));
-        inst = inst->Next_1xx();
-        break;
-      }
-      case Instruction::AND_INT_2ADDR: {
-        PREAMBLE();
-        uint4_t vregA = inst->VRegA_12x(inst_data);
-        shadow_frame.SetVReg(vregA,
-                             shadow_frame.GetVReg(vregA) &
-                             shadow_frame.GetVReg(inst->VRegB_12x(inst_data)));
-        inst = inst->Next_1xx();
-        break;
-      }
-      case Instruction::OR_INT_2ADDR: {
-        PREAMBLE();
-        uint4_t vregA = inst->VRegA_12x(inst_data);
-        shadow_frame.SetVReg(vregA,
-                             shadow_frame.GetVReg(vregA) |
-                             shadow_frame.GetVReg(inst->VRegB_12x(inst_data)));
-        inst = inst->Next_1xx();
-        break;
-      }
-      case Instruction::XOR_INT_2ADDR: {
-        PREAMBLE();
-        uint4_t vregA = inst->VRegA_12x(inst_data);
-        shadow_frame.SetVReg(vregA,
-                             shadow_frame.GetVReg(vregA) ^
-                             shadow_frame.GetVReg(inst->VRegB_12x(inst_data)));
-        inst = inst->Next_1xx();
-        break;
-      }
-      case Instruction::ADD_LONG_2ADDR: {
-        PREAMBLE();
-        uint4_t vregA = inst->VRegA_12x(inst_data);
-        shadow_frame.SetVRegLong(vregA,
-                                 SafeAdd(shadow_frame.GetVRegLong(vregA),
-                                         shadow_frame.GetVRegLong(inst->VRegB_12x(inst_data))));
-        inst = inst->Next_1xx();
-        break;
-      }
-      case Instruction::SUB_LONG_2ADDR: {
-        PREAMBLE();
-        uint4_t vregA = inst->VRegA_12x(inst_data);
-        shadow_frame.SetVRegLong(vregA,
-                                 SafeSub(shadow_frame.GetVRegLong(vregA),
-                                         shadow_frame.GetVRegLong(inst->VRegB_12x(inst_data))));
-        inst = inst->Next_1xx();
-        break;
-      }
-      case Instruction::MUL_LONG_2ADDR: {
-        PREAMBLE();
-        uint4_t vregA = inst->VRegA_12x(inst_data);
-        shadow_frame.SetVRegLong(vregA,
-                                 SafeMul(shadow_frame.GetVRegLong(vregA),
-                                         shadow_frame.GetVRegLong(inst->VRegB_12x(inst_data))));
-        inst = inst->Next_1xx();
-        break;
-      }
-      case Instruction::DIV_LONG_2ADDR: {
-        PREAMBLE();
-        uint4_t vregA = inst->VRegA_12x(inst_data);
-        DoLongDivide(shadow_frame, vregA, shadow_frame.GetVRegLong(vregA),
-                    shadow_frame.GetVRegLong(inst->VRegB_12x(inst_data)));
-        POSSIBLY_HANDLE_PENDING_EXCEPTION(self->IsExceptionPending(), Next_1xx);
-        break;
-      }
-      case Instruction::REM_LONG_2ADDR: {
-        PREAMBLE();
-        uint4_t vregA = inst->VRegA_12x(inst_data);
-        DoLongRemainder(shadow_frame, vregA, shadow_frame.GetVRegLong(vregA),
-                        shadow_frame.GetVRegLong(inst->VRegB_12x(inst_data)));
-        POSSIBLY_HANDLE_PENDING_EXCEPTION(self->IsExceptionPending(), Next_1xx);
-        break;
-      }
-      case Instruction::AND_LONG_2ADDR: {
-        PREAMBLE();
-        uint4_t vregA = inst->VRegA_12x(inst_data);
-        shadow_frame.SetVRegLong(vregA,
-                                 shadow_frame.GetVRegLong(vregA) &
-                                 shadow_frame.GetVRegLong(inst->VRegB_12x(inst_data)));
-        inst = inst->Next_1xx();
-        break;
-      }
-      case Instruction::OR_LONG_2ADDR: {
-        PREAMBLE();
-        uint4_t vregA = inst->VRegA_12x(inst_data);
-        shadow_frame.SetVRegLong(vregA,
-                                 shadow_frame.GetVRegLong(vregA) |
-                                 shadow_frame.GetVRegLong(inst->VRegB_12x(inst_data)));
-        inst = inst->Next_1xx();
-        break;
-      }
-      case Instruction::XOR_LONG_2ADDR: {
-        PREAMBLE();
-        uint4_t vregA = inst->VRegA_12x(inst_data);
-        shadow_frame.SetVRegLong(vregA,
-                                 shadow_frame.GetVRegLong(vregA) ^
-                                 shadow_frame.GetVRegLong(inst->VRegB_12x(inst_data)));
-        inst = inst->Next_1xx();
-        break;
-      }
-      case Instruction::SHL_LONG_2ADDR: {
-        PREAMBLE();
-        uint4_t vregA = inst->VRegA_12x(inst_data);
-        shadow_frame.SetVRegLong(vregA,
-                                 shadow_frame.GetVRegLong(vregA) <<
-                                 (shadow_frame.GetVReg(inst->VRegB_12x(inst_data)) & 0x3f));
-        inst = inst->Next_1xx();
-        break;
-      }
-      case Instruction::SHR_LONG_2ADDR: {
-        PREAMBLE();
-        uint4_t vregA = inst->VRegA_12x(inst_data);
-        shadow_frame.SetVRegLong(vregA,
-                                 shadow_frame.GetVRegLong(vregA) >>
-                                 (shadow_frame.GetVReg(inst->VRegB_12x(inst_data)) & 0x3f));
-        inst = inst->Next_1xx();
-        break;
-      }
-      case Instruction::USHR_LONG_2ADDR: {
-        PREAMBLE();
-        uint4_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));
-        inst = inst->Next_1xx();
-        break;
-      }
-      case Instruction::ADD_FLOAT_2ADDR: {
-        PREAMBLE();
-        uint4_t vregA = inst->VRegA_12x(inst_data);
-        shadow_frame.SetVRegFloat(vregA,
-                                  shadow_frame.GetVRegFloat(vregA) +
-                                  shadow_frame.GetVRegFloat(inst->VRegB_12x(inst_data)));
-        inst = inst->Next_1xx();
-        break;
-      }
-      case Instruction::SUB_FLOAT_2ADDR: {
-        PREAMBLE();
-        uint4_t vregA = inst->VRegA_12x(inst_data);
-        shadow_frame.SetVRegFloat(vregA,
-                                  shadow_frame.GetVRegFloat(vregA) -
-                                  shadow_frame.GetVRegFloat(inst->VRegB_12x(inst_data)));
-        inst = inst->Next_1xx();
-        break;
-      }
-      case Instruction::MUL_FLOAT_2ADDR: {
-        PREAMBLE();
-        uint4_t vregA = inst->VRegA_12x(inst_data);
-        shadow_frame.SetVRegFloat(vregA,
-                                  shadow_frame.GetVRegFloat(vregA) *
-                                  shadow_frame.GetVRegFloat(inst->VRegB_12x(inst_data)));
-        inst = inst->Next_1xx();
-        break;
-      }
-      case Instruction::DIV_FLOAT_2ADDR: {
-        PREAMBLE();
-        uint4_t vregA = inst->VRegA_12x(inst_data);
-        shadow_frame.SetVRegFloat(vregA,
-                                  shadow_frame.GetVRegFloat(vregA) /
-                                  shadow_frame.GetVRegFloat(inst->VRegB_12x(inst_data)));
-        inst = inst->Next_1xx();
-        break;
-      }
-      case Instruction::REM_FLOAT_2ADDR: {
-        PREAMBLE();
-        uint4_t vregA = inst->VRegA_12x(inst_data);
-        shadow_frame.SetVRegFloat(vregA,
-                                  fmodf(shadow_frame.GetVRegFloat(vregA),
-                                        shadow_frame.GetVRegFloat(inst->VRegB_12x(inst_data))));
-        inst = inst->Next_1xx();
-        break;
-      }
-      case Instruction::ADD_DOUBLE_2ADDR: {
-        PREAMBLE();
-        uint4_t vregA = inst->VRegA_12x(inst_data);
-        shadow_frame.SetVRegDouble(vregA,
-                                   shadow_frame.GetVRegDouble(vregA) +
-                                   shadow_frame.GetVRegDouble(inst->VRegB_12x(inst_data)));
-        inst = inst->Next_1xx();
-        break;
-      }
-      case Instruction::SUB_DOUBLE_2ADDR: {
-        PREAMBLE();
-        uint4_t vregA = inst->VRegA_12x(inst_data);
-        shadow_frame.SetVRegDouble(vregA,
-                                   shadow_frame.GetVRegDouble(vregA) -
-                                   shadow_frame.GetVRegDouble(inst->VRegB_12x(inst_data)));
-        inst = inst->Next_1xx();
-        break;
-      }
-      case Instruction::MUL_DOUBLE_2ADDR: {
-        PREAMBLE();
-        uint4_t vregA = inst->VRegA_12x(inst_data);
-        shadow_frame.SetVRegDouble(vregA,
-                                   shadow_frame.GetVRegDouble(vregA) *
-                                   shadow_frame.GetVRegDouble(inst->VRegB_12x(inst_data)));
-        inst = inst->Next_1xx();
-        break;
-      }
-      case Instruction::DIV_DOUBLE_2ADDR: {
-        PREAMBLE();
-        uint4_t vregA = inst->VRegA_12x(inst_data);
-        shadow_frame.SetVRegDouble(vregA,
-                                   shadow_frame.GetVRegDouble(vregA) /
-                                   shadow_frame.GetVRegDouble(inst->VRegB_12x(inst_data)));
-        inst = inst->Next_1xx();
-        break;
-      }
-      case Instruction::REM_DOUBLE_2ADDR: {
-        PREAMBLE();
-        uint4_t vregA = inst->VRegA_12x(inst_data);
-        shadow_frame.SetVRegDouble(vregA,
-                                   fmod(shadow_frame.GetVRegDouble(vregA),
-                                        shadow_frame.GetVRegDouble(inst->VRegB_12x(inst_data))));
-        inst = inst->Next_1xx();
-        break;
-      }
-      case Instruction::ADD_INT_LIT16:
-        PREAMBLE();
-        shadow_frame.SetVReg(inst->VRegA_22s(inst_data),
-                             SafeAdd(shadow_frame.GetVReg(inst->VRegB_22s(inst_data)),
-                                     inst->VRegC_22s()));
-        inst = inst->Next_2xx();
-        break;
-      case Instruction::RSUB_INT_LIT16:
-        PREAMBLE();
-        shadow_frame.SetVReg(inst->VRegA_22s(inst_data),
-                             SafeSub(inst->VRegC_22s(),
-                                     shadow_frame.GetVReg(inst->VRegB_22s(inst_data))));
-        inst = inst->Next_2xx();
-        break;
-      case Instruction::MUL_INT_LIT16:
-        PREAMBLE();
-        shadow_frame.SetVReg(inst->VRegA_22s(inst_data),
-                             SafeMul(shadow_frame.GetVReg(inst->VRegB_22s(inst_data)),
-                                     inst->VRegC_22s()));
-        inst = inst->Next_2xx();
-        break;
-      case Instruction::DIV_INT_LIT16: {
-        PREAMBLE();
-        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, Next_2xx);
-        break;
-      }
-      case Instruction::REM_INT_LIT16: {
-        PREAMBLE();
-        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, Next_2xx);
-        break;
-      }
-      case Instruction::AND_INT_LIT16:
-        PREAMBLE();
-        shadow_frame.SetVReg(inst->VRegA_22s(inst_data),
-                             shadow_frame.GetVReg(inst->VRegB_22s(inst_data)) &
-                             inst->VRegC_22s());
-        inst = inst->Next_2xx();
-        break;
-      case Instruction::OR_INT_LIT16:
-        PREAMBLE();
-        shadow_frame.SetVReg(inst->VRegA_22s(inst_data),
-                             shadow_frame.GetVReg(inst->VRegB_22s(inst_data)) |
-                             inst->VRegC_22s());
-        inst = inst->Next_2xx();
-        break;
-      case Instruction::XOR_INT_LIT16:
-        PREAMBLE();
-        shadow_frame.SetVReg(inst->VRegA_22s(inst_data),
-                             shadow_frame.GetVReg(inst->VRegB_22s(inst_data)) ^
-                             inst->VRegC_22s());
-        inst = inst->Next_2xx();
-        break;
-      case Instruction::ADD_INT_LIT8:
-        PREAMBLE();
-        shadow_frame.SetVReg(inst->VRegA_22b(inst_data),
-                             SafeAdd(shadow_frame.GetVReg(inst->VRegB_22b()), inst->VRegC_22b()));
-        inst = inst->Next_2xx();
-        break;
-      case Instruction::RSUB_INT_LIT8:
-        PREAMBLE();
-        shadow_frame.SetVReg(inst->VRegA_22b(inst_data),
-                             SafeSub(inst->VRegC_22b(), shadow_frame.GetVReg(inst->VRegB_22b())));
-        inst = inst->Next_2xx();
-        break;
-      case Instruction::MUL_INT_LIT8:
-        PREAMBLE();
-        shadow_frame.SetVReg(inst->VRegA_22b(inst_data),
-                             SafeMul(shadow_frame.GetVReg(inst->VRegB_22b()), inst->VRegC_22b()));
-        inst = inst->Next_2xx();
-        break;
-      case Instruction::DIV_INT_LIT8: {
-        PREAMBLE();
-        bool success = DoIntDivide(shadow_frame, inst->VRegA_22b(inst_data),
-                                   shadow_frame.GetVReg(inst->VRegB_22b()), inst->VRegC_22b());
-        POSSIBLY_HANDLE_PENDING_EXCEPTION(!success, Next_2xx);
-        break;
-      }
-      case Instruction::REM_INT_LIT8: {
-        PREAMBLE();
-        bool success = DoIntRemainder(shadow_frame, inst->VRegA_22b(inst_data),
-                                      shadow_frame.GetVReg(inst->VRegB_22b()), inst->VRegC_22b());
-        POSSIBLY_HANDLE_PENDING_EXCEPTION(!success, Next_2xx);
-        break;
-      }
-      case Instruction::AND_INT_LIT8:
-        PREAMBLE();
-        shadow_frame.SetVReg(inst->VRegA_22b(inst_data),
-                             shadow_frame.GetVReg(inst->VRegB_22b()) &
-                             inst->VRegC_22b());
-        inst = inst->Next_2xx();
-        break;
-      case Instruction::OR_INT_LIT8:
-        PREAMBLE();
-        shadow_frame.SetVReg(inst->VRegA_22b(inst_data),
-                             shadow_frame.GetVReg(inst->VRegB_22b()) |
-                             inst->VRegC_22b());
-        inst = inst->Next_2xx();
-        break;
-      case Instruction::XOR_INT_LIT8:
-        PREAMBLE();
-        shadow_frame.SetVReg(inst->VRegA_22b(inst_data),
-                             shadow_frame.GetVReg(inst->VRegB_22b()) ^
-                             inst->VRegC_22b());
-        inst = inst->Next_2xx();
-        break;
-      case Instruction::SHL_INT_LIT8:
-        PREAMBLE();
-        shadow_frame.SetVReg(inst->VRegA_22b(inst_data),
-                             shadow_frame.GetVReg(inst->VRegB_22b()) <<
-                             (inst->VRegC_22b() & 0x1f));
-        inst = inst->Next_2xx();
-        break;
-      case Instruction::SHR_INT_LIT8:
-        PREAMBLE();
-        shadow_frame.SetVReg(inst->VRegA_22b(inst_data),
-                             shadow_frame.GetVReg(inst->VRegB_22b()) >>
-                             (inst->VRegC_22b() & 0x1f));
-        inst = inst->Next_2xx();
-        break;
-      case Instruction::USHR_INT_LIT8:
-        PREAMBLE();
-        shadow_frame.SetVReg(inst->VRegA_22b(inst_data),
-                             static_cast<uint32_t>(shadow_frame.GetVReg(inst->VRegB_22b())) >>
-                             (inst->VRegC_22b() & 0x1f));
-        inst = inst->Next_2xx();
-        break;
-      case Instruction::UNUSED_3E ... Instruction::UNUSED_43:
-      case Instruction::UNUSED_79 ... Instruction::UNUSED_7A:
-      case Instruction::UNUSED_F3 ... Instruction::UNUSED_F9:
-        UnexpectedOpcode(inst, shadow_frame);
+DEX_INSTRUCTION_LIST(OPCODE_CASE)
+#undef OPCODE_CASE
     }
-  } while (!interpret_one_instruction);
-  // Record where we stopped.
-  shadow_frame.SetDexPC(inst->GetDexPc(insns));
-  ctx->result = result_register;
-  return;
+    if (UNLIKELY(interpret_one_instruction)) {
+      // Record where we stopped.
+      shadow_frame.SetDexPC(inst->GetDexPc(insns));
+      ctx->result = ctx->result_register;
+      return;
+    }
+  }
 }  // NOLINT(readability/fn_size)
 
 }  // namespace interpreter
diff --git a/runtime/intrinsics_list.h b/runtime/intrinsics_list.h
index 2f91f5d..093dd7f 100644
--- a/runtime/intrinsics_list.h
+++ b/runtime/intrinsics_list.h
@@ -219,6 +219,7 @@
   V(VarHandleLoadLoadFence, kStatic, kNeedsEnvironmentOrCache, kWriteSideEffects, kNoThrow, "Ljava/lang/invoke/VarHandle;", "loadLoadFence", "()V") \
   V(VarHandleStoreStoreFence, kStatic, kNeedsEnvironmentOrCache, kReadSideEffects, kNoThrow, "Ljava/lang/invoke/VarHandle;", "storeStoreFence", "()V") \
   V(ReachabilityFence, kStatic, kNeedsEnvironmentOrCache, kWriteSideEffects, kNoThrow, "Ljava/lang/ref/Reference;", "reachabilityFence", "(Ljava/lang/Object;)V") \
+  V(CRC32Update, kStatic, kNeedsEnvironmentOrCache, kReadSideEffects, kCanThrow, "Ljava/util/zip/CRC32;", "update", "(II)I") \
   SIGNATURE_POLYMORPHIC_INTRINSICS_LIST(V)
 
 #endif  // ART_RUNTIME_INTRINSICS_LIST_H_
diff --git a/runtime/native/sun_misc_Unsafe.cc b/runtime/native/sun_misc_Unsafe.cc
index e021b77..a739c2d 100644
--- a/runtime/native/sun_misc_Unsafe.cc
+++ b/runtime/native/sun_misc_Unsafe.cc
@@ -31,8 +31,10 @@
 #include "mirror/array.h"
 #include "mirror/class-inl.h"
 #include "mirror/object-inl.h"
+#include "art_field-inl.h"
 #include "native_util.h"
 #include "scoped_fast_native_object_access-inl.h"
+#include "well_known_classes.h"
 
 namespace art {
 
@@ -504,6 +506,33 @@
   std::atomic_thread_fence(std::memory_order_seq_cst);
 }
 
+static void Unsafe_park(JNIEnv* env, jobject, jboolean isAbsolute, jlong time) {
+  ScopedObjectAccess soa(env);
+  Thread::Current()->Park(isAbsolute, time);
+}
+
+static void Unsafe_unpark(JNIEnv* env, jobject, jobject jthread) {
+  art::ScopedFastNativeObjectAccess soa(env);
+  if (jthread == nullptr || !env->IsInstanceOf(jthread, WellKnownClasses::java_lang_Thread)) {
+    ThrowIllegalArgumentException("Argument to unpark() was not a Thread");
+    return;
+  }
+  art::MutexLock mu(soa.Self(), *art::Locks::thread_list_lock_);
+  art::Thread* thread = art::Thread::FromManagedThread(soa, jthread);
+  if (thread != nullptr) {
+    thread->Unpark();
+  } else {
+    // If thread is null, that means that either the thread is not started yet,
+    // or the thread has already terminated. Setting the field to true will be
+    // respected when the thread does start, and is harmless if the thread has
+    // already terminated.
+    ArtField* unparked =
+        jni::DecodeArtField(WellKnownClasses::java_lang_Thread_unparkedBeforeStart);
+    // JNI must use non transactional mode.
+    unparked->SetBoolean<false>(soa.Decode<mirror::Object>(jthread), JNI_TRUE);
+  }
+}
+
 static JNINativeMethod gMethods[] = {
   FAST_NATIVE_METHOD(Unsafe, compareAndSwapInt, "(Ljava/lang/Object;JII)Z"),
   FAST_NATIVE_METHOD(Unsafe, compareAndSwapLong, "(Ljava/lang/Object;JJJ)Z"),
@@ -546,6 +575,8 @@
   FAST_NATIVE_METHOD(Unsafe, putShort, "(Ljava/lang/Object;JS)V"),
   FAST_NATIVE_METHOD(Unsafe, putFloat, "(Ljava/lang/Object;JF)V"),
   FAST_NATIVE_METHOD(Unsafe, putDouble, "(Ljava/lang/Object;JD)V"),
+  FAST_NATIVE_METHOD(Unsafe, unpark, "(Ljava/lang/Object;)V"),
+  NATIVE_METHOD(Unsafe, park, "(ZJ)V"),
 
   // Each of the getFoo variants are overloaded with a call that operates
   // directively on a native pointer.
diff --git a/runtime/runtime.cc b/runtime/runtime.cc
index 34b84f5..3c0125b 100644
--- a/runtime/runtime.cc
+++ b/runtime/runtime.cc
@@ -791,10 +791,6 @@
     std::string error_msg;
     if (!jit::Jit::LoadCompiler(&error_msg)) {
       LOG(WARNING) << "Failed to load JIT compiler with error " << error_msg;
-    } else if (!IsZygote()) {
-      // If we are the zygote then we need to wait until after forking to create the code cache
-      // due to SELinux restrictions on r/w/x memory regions.
-      CreateJitCodeCache(/*rwx_memory_allowed=*/true);
     }
   }
 
@@ -900,6 +896,11 @@
   }
 
   if (jit_ == nullptr) {
+    // The system server's code cache was initialized specially. For other zygote forks or
+    // processes create it now.
+    if (!is_system_server) {
+      CreateJitCodeCache(/*rwx_memory_allowed=*/true);
+    }
     // Note that when running ART standalone (not zygote, nor zygote fork),
     // the jit may have already been created.
     CreateJit();
@@ -1101,6 +1102,10 @@
   sentinel_ = GcRoot<mirror::Object>(sentinel);
 }
 
+GcRoot<mirror::Object> Runtime::GetSentinel() {
+  return sentinel_;
+}
+
 static inline void CreatePreAllocatedException(Thread* self,
                                                Runtime* runtime,
                                                GcRoot<mirror::Throwable>* exception,
diff --git a/runtime/runtime.h b/runtime/runtime.h
index 4fb0d2e..be5b3c1 100644
--- a/runtime/runtime.h
+++ b/runtime/runtime.h
@@ -691,6 +691,9 @@
 
   // Called from class linker.
   void SetSentinel(mirror::Object* sentinel) REQUIRES_SHARED(Locks::mutator_lock_);
+  // For testing purpose only.
+  // TODO: Remove this when this is no longer needed (b/116087961).
+  GcRoot<mirror::Object> GetSentinel() REQUIRES_SHARED(Locks::mutator_lock_);
 
   // Create a normal LinearAlloc or low 4gb version if we are 64 bit AOT compiler.
   LinearAlloc* CreateLinearAlloc();
diff --git a/runtime/thread.cc b/runtime/thread.cc
index dda3b82..66e852a 100644
--- a/runtime/thread.cc
+++ b/runtime/thread.cc
@@ -44,6 +44,7 @@
 #include "arch/context.h"
 #include "art_field-inl.h"
 #include "art_method-inl.h"
+#include "base/atomic.h"
 #include "base/bit_utils.h"
 #include "base/casts.h"
 #include "base/file_utils.h"
@@ -285,6 +286,116 @@
       << "No deoptimization context for thread " << *this;
 }
 
+enum {
+  kPermitAvailable = 0,  // Incrementing consumes the permit
+  kNoPermit = 1,  // Incrementing marks as waiter waiting
+  kNoPermitWaiterWaiting = 2
+};
+
+void Thread::Park(bool is_absolute, int64_t time) {
+  DCHECK(this == Thread::Current());
+#if ART_USE_FUTEXES
+  // Consume the permit, or mark as waiting. This cannot cause park_state to go
+  // outside of its valid range (0, 1, 2), because in all cases where 2 is
+  // assigned it is set back to 1 before returning, and this method cannot run
+  // concurrently with itself since it operates on the current thread.
+  int old_state = tls32_.park_state_.fetch_add(1, std::memory_order_relaxed);
+  if (old_state == kNoPermit) {
+    // no permit was available. block thread until later.
+    // TODO: Call to signal jvmti here
+    int result = 0;
+    if (!is_absolute && time == 0) {
+      // Thread.getState() is documented to return waiting for untimed parks.
+      ScopedThreadSuspension sts(this, ThreadState::kWaiting);
+      DCHECK_EQ(NumberOfHeldMutexes(), 0u);
+      result = futex(tls32_.park_state_.Address(),
+                     FUTEX_WAIT_PRIVATE,
+                     /* sleep if val = */ kNoPermitWaiterWaiting,
+                     /* timeout */ nullptr,
+                     nullptr,
+                     0);
+    } else if (time > 0) {
+      // Only actually suspend and futex_wait if we're going to wait for some
+      // positive amount of time - the kernel will reject negative times with
+      // EINVAL, and a zero time will just noop.
+
+      // Thread.getState() is documented to return timed wait for timed parks.
+      ScopedThreadSuspension sts(this, ThreadState::kTimedWaiting);
+      DCHECK_EQ(NumberOfHeldMutexes(), 0u);
+      timespec timespec;
+      if (is_absolute) {
+        // Time is millis when scheduled for an absolute time
+        timespec.tv_nsec = (time % 1000) * 1000000;
+        timespec.tv_sec = time / 1000;
+        // This odd looking pattern is recommended by futex documentation to
+        // wait until an absolute deadline, with otherwise identical behavior to
+        // FUTEX_WAIT_PRIVATE. This also allows parkUntil() to return at the
+        // correct time when the system clock changes.
+        result = futex(tls32_.park_state_.Address(),
+                       FUTEX_WAIT_BITSET_PRIVATE | FUTEX_CLOCK_REALTIME,
+                       /* sleep if val = */ kNoPermitWaiterWaiting,
+                       &timespec,
+                       nullptr,
+                       FUTEX_BITSET_MATCH_ANY);
+      } else {
+        // Time is nanos when scheduled for a relative time
+        timespec.tv_sec = time / 1000000000;
+        timespec.tv_nsec = time % 1000000000;
+        result = futex(tls32_.park_state_.Address(),
+                       FUTEX_WAIT_PRIVATE,
+                       /* sleep if val = */ kNoPermitWaiterWaiting,
+                       &timespec,
+                       nullptr,
+                       0);
+      }
+    }
+    if (result == -1) {
+      switch (errno) {
+        case EAGAIN:
+        case ETIMEDOUT:
+        case EINTR: break;  // park() is allowed to spuriously return
+        default: PLOG(FATAL) << "Failed to park";
+      }
+    }
+    // Mark as no longer waiting, and consume permit if there is one.
+    tls32_.park_state_.store(kNoPermit, std::memory_order_relaxed);
+    // TODO: Call to signal jvmti here
+  } else {
+    // the fetch_add has consumed the permit. immediately return.
+    DCHECK_EQ(old_state, kPermitAvailable);
+  }
+#else
+  #pragma clang diagnostic push
+  #pragma clang diagnostic warning "-W#warnings"
+  #warning "LockSupport.park/unpark implemented as noops without FUTEX support."
+  #pragma clang diagnostic pop
+  UNUSED(is_absolute, time);
+  UNIMPLEMENTED(WARNING);
+  sched_yield();
+#endif
+}
+
+void Thread::Unpark() {
+#if ART_USE_FUTEXES
+  // Set permit available; will be consumed either by fetch_add (when the thread
+  // tries to park) or store (when the parked thread is woken up)
+  if (tls32_.park_state_.exchange(kPermitAvailable, std::memory_order_relaxed)
+      == kNoPermitWaiterWaiting) {
+    int result = futex(tls32_.park_state_.Address(),
+                       FUTEX_WAKE_PRIVATE,
+                       /* number of waiters = */ 1,
+                       nullptr,
+                       nullptr,
+                       0);
+    if (result == -1) {
+      PLOG(FATAL) << "Failed to unpark";
+    }
+  }
+#else
+  UNIMPLEMENTED(WARNING);
+#endif
+}
+
 void Thread::PushStackedShadowFrame(ShadowFrame* sf, StackedShadowFrameType type) {
   StackedShadowFrameRecord* record = new StackedShadowFrameRecord(
       sf, type, tlsPtr_.stacked_shadow_frame_record);
@@ -489,6 +600,22 @@
 
     runtime->GetRuntimeCallbacks()->ThreadStart(self);
 
+    // Unpark ourselves if the java peer was unparked before it started (see
+    // b/28845097#comment49 for more information)
+
+    ArtField* unparkedField = jni::DecodeArtField(
+        WellKnownClasses::java_lang_Thread_unparkedBeforeStart);
+    bool should_unpark = false;
+    {
+      // Hold the lock here, so that if another thread calls unpark before the thread starts
+      // we don't observe the unparkedBeforeStart field before the unparker writes to it,
+      // which could cause a lost unpark.
+      art::MutexLock mu(soa.Self(), *art::Locks::thread_list_lock_);
+      should_unpark = unparkedField->GetBoolean(self->tlsPtr_.opeer) == JNI_TRUE;
+    }
+    if (should_unpark) {
+      self->Unpark();
+    }
     // Invoke the 'run' method of our java.lang.Thread.
     ObjPtr<mirror::Object> receiver = self->tlsPtr_.opeer;
     jmethodID mid = WellKnownClasses::java_lang_Thread_run;
@@ -2133,6 +2260,9 @@
   tls32_.state_and_flags.as_struct.flags = 0;
   tls32_.state_and_flags.as_struct.state = kNative;
   tls32_.interrupted.store(false, std::memory_order_relaxed);
+  // Initialize with no permit; if the java Thread was unparked before being
+  // started, it will unpark itself before calling into java code.
+  tls32_.park_state_.store(kNoPermit, std::memory_order_relaxed);
   memset(&tlsPtr_.held_mutexes[0], 0, sizeof(tlsPtr_.held_mutexes));
   std::fill(tlsPtr_.rosalloc_runs,
             tlsPtr_.rosalloc_runs + kNumRosAllocThreadLocalSizeBracketsInThread,
@@ -2449,12 +2579,15 @@
 }
 
 void Thread::Interrupt(Thread* self) {
-  MutexLock mu(self, *wait_mutex_);
-  if (tls32_.interrupted.load(std::memory_order_seq_cst)) {
-    return;
+  {
+    MutexLock mu(self, *wait_mutex_);
+    if (tls32_.interrupted.load(std::memory_order_seq_cst)) {
+      return;
+    }
+    tls32_.interrupted.store(true, std::memory_order_seq_cst);
+    NotifyLocked(self);
   }
-  tls32_.interrupted.store(true, std::memory_order_seq_cst);
-  NotifyLocked(self);
+  Unpark();
 }
 
 void Thread::Notify() {
diff --git a/runtime/thread.h b/runtime/thread.h
index 941867c..b304cef 100644
--- a/runtime/thread.h
+++ b/runtime/thread.h
@@ -581,6 +581,11 @@
     return poison_object_cookie_;
   }
 
+  // Parking for 0ns of relative time means an untimed park, negative (though
+  // should be handled in java code) returns immediately
+  void Park(bool is_absolute, int64_t time) REQUIRES_SHARED(Locks::mutator_lock_);
+  void Unpark();
+
  private:
   void NotifyLocked(Thread* self) REQUIRES(wait_mutex_);
 
@@ -1543,6 +1548,8 @@
     // Thread "interrupted" status; stays raised until queried or thrown.
     Atomic<bool32_t> interrupted;
 
+    AtomicInteger park_state_;
+
     // True if the thread is allowed to access a weak ref (Reference::GetReferent() and system
     // weaks) and to potentially mark an object alive/gray. This is used for concurrent reference
     // processing of the CC collector only. This is thread local so that we can enable/disable weak
diff --git a/runtime/well_known_classes.cc b/runtime/well_known_classes.cc
index 206418f..94faa62 100644
--- a/runtime/well_known_classes.cc
+++ b/runtime/well_known_classes.cc
@@ -128,6 +128,7 @@
 jfieldID WellKnownClasses::java_lang_Thread_name;
 jfieldID WellKnownClasses::java_lang_Thread_priority;
 jfieldID WellKnownClasses::java_lang_Thread_nativePeer;
+jfieldID WellKnownClasses::java_lang_Thread_unparkedBeforeStart;
 jfieldID WellKnownClasses::java_lang_ThreadGroup_groups;
 jfieldID WellKnownClasses::java_lang_ThreadGroup_ngroups;
 jfieldID WellKnownClasses::java_lang_ThreadGroup_mainThreadGroup;
@@ -376,6 +377,7 @@
   java_lang_Thread_name = CacheField(env, java_lang_Thread, false, "name", "Ljava/lang/String;");
   java_lang_Thread_priority = CacheField(env, java_lang_Thread, false, "priority", "I");
   java_lang_Thread_nativePeer = CacheField(env, java_lang_Thread, false, "nativePeer", "J");
+  java_lang_Thread_unparkedBeforeStart = CacheField(env, java_lang_Thread, false, "unparkedBeforeStart", "Z");
   java_lang_ThreadGroup_groups = CacheField(env, java_lang_ThreadGroup, false, "groups", "[Ljava/lang/ThreadGroup;");
   java_lang_ThreadGroup_ngroups = CacheField(env, java_lang_ThreadGroup, false, "ngroups", "I");
   java_lang_ThreadGroup_mainThreadGroup = CacheField(env, java_lang_ThreadGroup, true, "mainThreadGroup", "Ljava/lang/ThreadGroup;");
diff --git a/runtime/well_known_classes.h b/runtime/well_known_classes.h
index ce5ab1d..8c85228 100644
--- a/runtime/well_known_classes.h
+++ b/runtime/well_known_classes.h
@@ -137,6 +137,7 @@
   static jfieldID java_lang_Thread_name;
   static jfieldID java_lang_Thread_priority;
   static jfieldID java_lang_Thread_nativePeer;
+  static jfieldID java_lang_Thread_unparkedBeforeStart;
   static jfieldID java_lang_ThreadGroup_groups;
   static jfieldID java_lang_ThreadGroup_ngroups;
   static jfieldID java_lang_ThreadGroup_mainThreadGroup;
diff --git a/test/004-ThreadStress/src-art/Main.java b/test/004-ThreadStress/src-art/Main.java
index b8bfafb..e717852 100644
--- a/test/004-ThreadStress/src-art/Main.java
+++ b/test/004-ThreadStress/src-art/Main.java
@@ -53,6 +53,7 @@
 //    -sleep:X .......... frequency of Sleep (double)
 //    -wait:X ........... frequency of Wait (double)
 //    -timedwait:X ...... frequency of TimedWait (double)
+//    -timedpark:X ...... frequency of TimedPark (double)
 //    -syncandwork:X .... frequency of SyncAndWork (double)
 //    -queuedwait:X ..... frequency of QueuedWait (double)
 
@@ -264,19 +265,6 @@
         }
     }
 
-    private final static class UnparkAllThreads extends Operation {
-        public UnparkAllThreads() {}
-
-        @Override
-        public boolean perform() {
-            Set<Thread> threads = Thread.getAllStackTraces().keySet();
-            for (Thread candidate : threads) {
-                LockSupport.unpark(candidate);
-            }
-            return true;
-        }
-    }
-
     private final static class SyncAndWork extends Operation {
         private final Object lock;
 
@@ -346,9 +334,8 @@
         frequencyMap.put(new NonMovingAlloc(), 0.025);        //   5/200
         frequencyMap.put(new StackTrace(), 0.1);              //  20/200
         frequencyMap.put(new Exit(), 0.225);                  //  45/200
-        frequencyMap.put(new Sleep(), 0.125);                 //  15/200
-        frequencyMap.put(new TimedPark(), 0.025);             //   5/200
-        frequencyMap.put(new UnparkAllThreads(), 0.025);      //   5/200
+        frequencyMap.put(new Sleep(), 0.075);                 //  15/200
+        frequencyMap.put(new TimedPark(), 0.05);              //  10/200
         frequencyMap.put(new TimedWait(lock), 0.05);          //  10/200
         frequencyMap.put(new Wait(lock), 0.075);              //  15/200
         frequencyMap.put(new QueuedWait(semaphore), 0.05);    //  10/200
@@ -370,10 +357,9 @@
       Map<Operation, Double> frequencyMap = new HashMap<Operation, Double>();
       frequencyMap.put(new Sleep(), 0.2);                     //  40/200
       frequencyMap.put(new TimedWait(lock), 0.1);             //  20/200
-      frequencyMap.put(new Wait(lock), 0.1);                  //  20/200
+      frequencyMap.put(new Wait(lock), 0.2);                  //  40/200
       frequencyMap.put(new SyncAndWork(lock), 0.4);           //  80/200
       frequencyMap.put(new TimedPark(), 0.1);                 //  20/200
-      frequencyMap.put(new UnparkAllThreads(), 0.1);          //  20/200
 
       return frequencyMap;
     }
@@ -419,6 +405,8 @@
             op = new Wait(lock);
         } else if (split[0].equals("-timedwait")) {
             op = new TimedWait(lock);
+        } else if (split[0].equals("-timedpark")) {
+            op = new TimedPark();
         } else if (split[0].equals("-syncandwork")) {
             op = new SyncAndWork(lock);
         } else if (split[0].equals("-queuedwait")) {
@@ -723,7 +711,7 @@
         }
 
         // The notifier thread is a daemon just loops forever to wake
-        // up threads in operation Wait.
+        // up threads in operations Wait and Park.
         if (lock != null) {
             Thread notifier = new Thread("Notifier") {
                 public void run() {
@@ -731,6 +719,11 @@
                         synchronized (lock) {
                             lock.notifyAll();
                         }
+                        for (Thread runner : runners) {
+                          if (runner != null) {
+                            LockSupport.unpark(runner);
+                          }
+                        }
                     }
                 }
             };
diff --git a/test/099-vmdebug/check b/test/099-vmdebug/check
index d124ce8..6a3fed5 100755
--- a/test/099-vmdebug/check
+++ b/test/099-vmdebug/check
@@ -15,6 +15,6 @@
 # limitations under the License.
 
 # Strip the process pids and line numbers from exact error messages.
-sed -e '/^dalvikvm\(\|32\|64\) E.*\] /d' "$2" > "$2.tmp"
+sed -e '/^.*dalvikvm\(\|32\|64\) E.*\] /d' "$2" > "$2.tmp"
 
 diff --strip-trailing-cr -q "$1" "$2.tmp" >/dev/null
diff --git a/test/143-string-value/check b/test/143-string-value/check
index 2a3476c..b5e51ce 100755
--- a/test/143-string-value/check
+++ b/test/143-string-value/check
@@ -15,6 +15,6 @@
 # limitations under the License.
 
 # Strip error log messages.
-sed -e '/^dalvikvm\(\|32\|64\) E.*\] /d' "$2" > "$2.tmp"
+sed -e '/^.*dalvikvm\(\|32\|64\) E.*\] /d' "$2" > "$2.tmp"
 
 diff --strip-trailing-cr -q "$1" "$2.tmp" >/dev/null
diff --git a/test/160-read-barrier-stress/src/Main.java b/test/160-read-barrier-stress/src/Main.java
index 5865094..5e49e66 100644
--- a/test/160-read-barrier-stress/src/Main.java
+++ b/test/160-read-barrier-stress/src/Main.java
@@ -121,6 +121,23 @@
             assertSameObject(f4444, la[i4444]);
             assertDifferentObject(f4999, la[i4998]);
             assertSameObject(f4999, la[i4999]);
+
+            la = largeArray;
+            // Group the ArrayGets so they aren't divided by a function call; this will enable
+            // interm. address sharing for arm64.
+            Object tmp1 = la[i0];
+            Object tmp2 = la[i0 + 1];
+            Object tmp3 = la[i0 + 1024];
+            Object tmp4 = la[i0 + 4444];
+            Object tmp5 = la[i0 + 4998];
+            Object tmp6 = la[i0 + 4999];
+
+            assertSameObject(f0000, tmp1);
+            assertDifferentObject(f0000, tmp2);
+            assertSameObject(f1024, tmp3);
+            assertSameObject(f4444, tmp4);
+            assertDifferentObject(f4999, tmp5);
+            assertSameObject(f4999, tmp6);
         }
     }
 
diff --git a/test/527-checker-array-access-split/src/Main.java b/test/527-checker-array-access-split/src/Main.java
index f83c924..f39b5e2 100644
--- a/test/527-checker-array-access-split/src/Main.java
+++ b/test/527-checker-array-access-split/src/Main.java
@@ -572,6 +572,75 @@
     buf1[end] = 'n';
   }
 
+  //
+  // Check that IntermediateAddress can be shared for object ArrayGets.
+  //
+  /// CHECK-START-ARM64: int Main.checkObjectArrayGet(int, java.lang.Integer[], java.lang.Integer[]) instruction_simplifier_arm64 (before)
+  /// CHECK: <<Parameter:l\d+>>     ParameterValue
+  /// CHECK: <<Array:l\d+>>         NullCheck [<<Parameter>>]
+  /// CHECK:                        ArrayGet [<<Array>>,{{i\d+}}]
+  /// CHECK:                        ArrayGet [<<Array>>,{{i\d+}}]
+  /// CHECK:                        ArraySet [<<Array>>,{{i\d+}},{{l\d+}}]
+  /// CHECK:                        ArrayGet [<<Array>>,{{i\d+}}]
+  /// CHECK:                        ArraySet [<<Array>>,{{i\d+}},{{l\d+}}]
+  /// CHECK:                        ArraySet [<<Array>>,{{i\d+}},{{l\d+}}]
+
+  /// CHECK-START-ARM64: int Main.checkObjectArrayGet(int, java.lang.Integer[], java.lang.Integer[]) instruction_simplifier_arm64 (after)
+  /// CHECK: <<Parameter:l\d+>>     ParameterValue
+  /// CHECK: <<DataOffset:i\d+>>    IntConstant 12
+  /// CHECK: <<Array:l\d+>>         NullCheck [<<Parameter>>]
+  /// CHECK: <<IntAddr1:i\d+>>      IntermediateAddress [<<Array>>,<<DataOffset>>]
+  /// CHECK:                        ArrayGet [<<IntAddr1>>,{{i\d+}}]
+  /// CHECK: <<IntAddr2:i\d+>>      IntermediateAddress [<<Array>>,<<DataOffset>>]
+  /// CHECK:                        ArrayGet [<<IntAddr2>>,{{i\d+}}]
+  /// CHECK:                        ArraySet [<<Array>>,{{i\d+}},{{l\d+}}]
+  /// CHECK: <<IntAddr3:i\d+>>      IntermediateAddress [<<Array>>,<<DataOffset>>]
+  /// CHECK:                        ArrayGet [<<IntAddr3>>,{{i\d+}}]
+  /// CHECK:                        ArraySet [<<Array>>,{{i\d+}},{{l\d+}}]
+  /// CHECK:                        ArraySet [<<Array>>,{{i\d+}},{{l\d+}}]
+  //
+  /// CHECK-NOT:                    IntermediateAddress
+
+  /// CHECK-START-ARM64: int Main.checkObjectArrayGet(int, java.lang.Integer[], java.lang.Integer[]) GVN$after_arch (after)
+  /// CHECK: <<Parameter:l\d+>>     ParameterValue
+  /// CHECK: <<DataOffset:i\d+>>    IntConstant 12
+  /// CHECK: <<Array:l\d+>>         NullCheck [<<Parameter>>]
+  /// CHECK: <<IntAddr1:i\d+>>      IntermediateAddress [<<Array>>,<<DataOffset>>]
+  /// CHECK:                        ArrayGet [<<IntAddr1>>,{{i\d+}}]
+  /// CHECK:                        ArrayGet [<<IntAddr1>>,{{i\d+}}]
+  /// CHECK:                        ArraySet [<<Array>>,{{i\d+}},{{l\d+}}]
+  /// CHECK: <<IntAddr3:i\d+>>      IntermediateAddress [<<Array>>,<<DataOffset>>]
+  /// CHECK:                        ArrayGet [<<IntAddr3>>,{{i\d+}}]
+  /// CHECK:                        ArraySet [<<Array>>,{{i\d+}},{{l\d+}}]
+  /// CHECK:                        ArraySet [<<Array>>,{{i\d+}},{{l\d+}}]
+  //
+  /// CHECK-NOT:                    IntermediateAddress
+  public final static int checkObjectArrayGet(int index, Integer[] a, Integer[] b) {
+    Integer five = Integer.valueOf(5);
+    int tmp1 = a[index];
+    tmp1 += a[index + 1];
+    a[index + 1] = five;
+    tmp1 += a[index + 2];
+    a[index + 2] = five;
+    a[index + 3] = five;
+    return tmp1;
+  }
+
+  /// CHECK-START-ARM64: int Main.testIntAddressObjDisasm(java.lang.Integer[], int) disassembly (after)
+  /// CHECK: <<IntAddr:i\d+>>       IntermediateAddress
+  /// CHECK:                          add w<<AddrReg:\d+>>, {{w\d+}}, #0xc
+  /// CHECK:                        ArrayGet [<<IntAddr>>,{{i\d+}}]
+  /// CHECK:                          ldr {{w\d+}}, [x<<AddrReg>>, x{{\d+}}, lsl #2]
+  /// CHECK:                        ArrayGet [<<IntAddr>>,{{i\d+}}]
+  /// CHECK:                          ldr {{w\d+}}, [x<<AddrReg>>, x{{\d+}}, lsl #2]
+
+  /// CHECK-START-ARM64: int Main.testIntAddressObjDisasm(java.lang.Integer[], int) disassembly (after)
+  /// CHECK:                          add {{w\d+}}, {{w\d+}}, #0xc
+  /// CHECK-NOT:                      add {{w\d+}}, {{w\d+}}, #0xc
+  private int testIntAddressObjDisasm(Integer[] obj, int x) {
+    return obj[x] + obj[x + 1];
+  }
+
   public final static int ARRAY_SIZE = 128;
 
   public static void main(String[] args) {
diff --git a/test/580-crc32/expected.txt b/test/580-crc32/expected.txt
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/test/580-crc32/expected.txt
diff --git a/test/580-crc32/info.txt b/test/580-crc32/info.txt
new file mode 100644
index 0000000..24f31e0
--- /dev/null
+++ b/test/580-crc32/info.txt
@@ -0,0 +1 @@
+This test case is used to test java.util.zip.CRC32.
diff --git a/test/580-crc32/src/Main.java b/test/580-crc32/src/Main.java
new file mode 100644
index 0000000..7fc1273
--- /dev/null
+++ b/test/580-crc32/src/Main.java
@@ -0,0 +1,131 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+import java.util.zip.CRC32;
+
+/**
+ * The ART compiler can use intrinsics for the java.util.zip.CRC32 method:
+ *    private native static int update(int crc, int b)
+ *
+ * As the method is private it is not possible to check the use of intrinsics
+ * for it directly.
+ * The tests check that correct checksums are produced.
+ */
+public class Main {
+  private static CRC32 crc32 = new CRC32();
+
+  public Main() {
+  }
+
+  public static long TestInt(int value) {
+    crc32.reset();
+    crc32.update(value);
+    return crc32.getValue();
+  }
+
+  public static long TestInt(int... values) {
+    crc32.reset();
+    for (int value : values) {
+      crc32.update(value);
+    }
+    return crc32.getValue();
+  }
+
+  public static void assertEqual(long expected, long actual) {
+    if (expected != actual) {
+      throw new Error("Expected: " + expected + ", found: " + actual);
+    }
+  }
+
+  public static void main(String args[]) {
+    // public void update(int b)
+    //
+    // Tests for checksums of the byte 0x0
+    assertEqual(0xD202EF8DL, TestInt(0x0));
+    assertEqual(0xD202EF8DL, TestInt(0x0100));
+    assertEqual(0xD202EF8DL, TestInt(0x010000));
+    assertEqual(0xD202EF8DL, TestInt(0x01000000));
+    assertEqual(0xD202EF8DL, TestInt(0xff00));
+    assertEqual(0xD202EF8DL, TestInt(0xffff00));
+    assertEqual(0xD202EF8DL, TestInt(0xffffff00));
+    assertEqual(0xD202EF8DL, TestInt(0x1200));
+    assertEqual(0xD202EF8DL, TestInt(0x123400));
+    assertEqual(0xD202EF8DL, TestInt(0x12345600));
+    assertEqual(0xD202EF8DL, TestInt(Integer.MIN_VALUE));
+
+    // Tests for checksums of the byte 0x1
+    assertEqual(0xA505DF1BL, TestInt(0x1));
+    assertEqual(0xA505DF1BL, TestInt(0x0101));
+    assertEqual(0xA505DF1BL, TestInt(0x010001));
+    assertEqual(0xA505DF1BL, TestInt(0x01000001));
+    assertEqual(0xA505DF1BL, TestInt(0xff01));
+    assertEqual(0xA505DF1BL, TestInt(0xffff01));
+    assertEqual(0xA505DF1BL, TestInt(0xffffff01));
+    assertEqual(0xA505DF1BL, TestInt(0x1201));
+    assertEqual(0xA505DF1BL, TestInt(0x123401));
+    assertEqual(0xA505DF1BL, TestInt(0x12345601));
+
+    // Tests for checksums of the byte 0x0f
+    assertEqual(0x42BDF21CL, TestInt(0x0f));
+    assertEqual(0x42BDF21CL, TestInt(0x010f));
+    assertEqual(0x42BDF21CL, TestInt(0x01000f));
+    assertEqual(0x42BDF21CL, TestInt(0x0100000f));
+    assertEqual(0x42BDF21CL, TestInt(0xff0f));
+    assertEqual(0x42BDF21CL, TestInt(0xffff0f));
+    assertEqual(0x42BDF21CL, TestInt(0xffffff0f));
+    assertEqual(0x42BDF21CL, TestInt(0x120f));
+    assertEqual(0x42BDF21CL, TestInt(0x12340f));
+    assertEqual(0x42BDF21CL, TestInt(0x1234560f));
+
+    // Tests for checksums of the byte 0xff
+    assertEqual(0xFF000000L, TestInt(0x00ff));
+    assertEqual(0xFF000000L, TestInt(0x01ff));
+    assertEqual(0xFF000000L, TestInt(0x0100ff));
+    assertEqual(0xFF000000L, TestInt(0x010000ff));
+    assertEqual(0xFF000000L, TestInt(0x0000ffff));
+    assertEqual(0xFF000000L, TestInt(0x00ffffff));
+    assertEqual(0xFF000000L, TestInt(0xffffffff));
+    assertEqual(0xFF000000L, TestInt(0x12ff));
+    assertEqual(0xFF000000L, TestInt(0x1234ff));
+    assertEqual(0xFF000000L, TestInt(0x123456ff));
+    assertEqual(0xFF000000L, TestInt(Integer.MAX_VALUE));
+
+    // Tests for sequences
+    assertEqual(0xFF41D912L, TestInt(0, 0, 0));
+    assertEqual(0xFF41D912L, TestInt(0x0100, 0x010000, 0x01000000));
+    assertEqual(0xFF41D912L, TestInt(0xff00, 0xffff00, 0xffffff00));
+    assertEqual(0xFF41D912L, TestInt(0x1200, 0x123400, 0x12345600));
+
+    assertEqual(0x909FB2F2L, TestInt(1, 1, 1));
+    assertEqual(0x909FB2F2L, TestInt(0x0101, 0x010001, 0x01000001));
+    assertEqual(0x909FB2F2L, TestInt(0xff01, 0xffff01, 0xffffff01));
+    assertEqual(0x909FB2F2L, TestInt(0x1201, 0x123401, 0x12345601));
+
+    assertEqual(0xE33A9F71L, TestInt(0x0f, 0x0f, 0x0f));
+    assertEqual(0xE33A9F71L, TestInt(0x010f, 0x01000f, 0x0100000f));
+    assertEqual(0xE33A9F71L, TestInt(0xff0f, 0xffff0f, 0xffffff0f));
+    assertEqual(0xE33A9F71L, TestInt(0x120f, 0x12340f, 0x1234560f));
+
+    assertEqual(0xFFFFFF00L, TestInt(0x0ff, 0x0ff, 0x0ff));
+    assertEqual(0xFFFFFF00L, TestInt(0x01ff, 0x0100ff, 0x010000ff));
+    assertEqual(0xFFFFFF00L, TestInt(0x00ffff, 0x00ffffff, 0xffffffff));
+    assertEqual(0xFFFFFF00L, TestInt(0x12ff, 0x1234ff, 0x123456ff));
+
+    assertEqual(0xB6CC4292L, TestInt(0x01, 0x02));
+
+    assertEqual(0xB2DE047CL, TestInt(0x0, -1, Integer.MIN_VALUE, Integer.MAX_VALUE));
+  }
+}
diff --git a/test/624-checker-stringops/smali/Smali.smali b/test/624-checker-stringops/smali/Smali.smali
index 8600a0a..f8b9275 100644
--- a/test/624-checker-stringops/smali/Smali.smali
+++ b/test/624-checker-stringops/smali/Smali.smali
@@ -34,7 +34,7 @@
     invoke-virtual {v0, v1}, Ljava/lang/StringBuffer;->append(Ljava/lang/String;)Ljava/lang/StringBuffer;
     move-result-object v1
 
-    const-string v2, "x"
+    const-string v2, "y"
     invoke-virtual {v1, v2}, Ljava/lang/StringBuffer;->append(Ljava/lang/String;)Ljava/lang/StringBuffer;
     move-result-object v1
 
@@ -70,7 +70,7 @@
     invoke-virtual {v0, v1}, Ljava/lang/StringBuilder;->append(Ljava/lang/String;)Ljava/lang/StringBuilder;
     move-result-object v1
 
-    const-string v2, "x"
+    const-string v2, "y"
     invoke-virtual {v1, v2}, Ljava/lang/StringBuilder;->append(Ljava/lang/String;)Ljava/lang/StringBuilder;
     move-result-object v1
 
diff --git a/test/624-checker-stringops/src/Main.java b/test/624-checker-stringops/src/Main.java
index 3aa6e56..f52d81a 100644
--- a/test/624-checker-stringops/src/Main.java
+++ b/test/624-checker-stringops/src/Main.java
@@ -120,7 +120,7 @@
   /// CHECK-DAG:                  InvokeVirtual [<<New>>]             intrinsic:StringBufferLength
   static int bufferLen2() {
     StringBuffer s = new StringBuffer();
-    return s.append("x").append("x").length();
+    return s.append("x").append("y").length();
   }
 
   static int bufferLen2Smali() throws Exception {
@@ -150,7 +150,7 @@
   /// CHECK-DAG:                  InvokeVirtual [<<New>>]             intrinsic:StringBuilderLength
   static int builderLen2() {
     StringBuilder s = new StringBuilder();
-    return s.append("x").append("x").length();
+    return s.append("x").append("y").length();
   }
 
   static int builderLen2Smali() throws Exception {
diff --git a/test/911-get-stack-trace/expected.txt b/test/911-get-stack-trace/expected.txt
index b0a400a..8dd49aa 100644
--- a/test/911-get-stack-trace/expected.txt
+++ b/test/911-get-stack-trace/expected.txt
@@ -21,7 +21,7 @@
  baz (IIILart/ControlData;)Ljava/lang/Object; 8 34
  bar (IIILart/ControlData;)J 0 26
  foo (IIILart/ControlData;)I 0 21
- doTest ()V 33 25
+ doTest ()V 31 25
  run ()V 0 25
 ---------
  print (Ljava/lang/Thread;II)V 0 38
@@ -41,7 +41,7 @@
  baz (IIILart/ControlData;)Ljava/lang/Object; 8 34
  bar (IIILart/ControlData;)J 0 26
  foo (IIILart/ControlData;)I 0 21
- doTest ()V 37 26
+ doTest ()V 35 26
  run ()V 0 25
 ---------
  getStackTrace (Ljava/lang/Thread;II)[[Ljava/lang/String; -1 -2
@@ -62,7 +62,7 @@
  baz (IIILart/ControlData;)Ljava/lang/Object; 8 34
  bar (IIILart/ControlData;)J 0 26
  foo (IIILart/ControlData;)I 0 21
- doTest ()V 60 32
+ doTest ()V 58 32
  run ()V 0 25
 ---------
  bar (IIILart/ControlData;)J 0 26
@@ -388,7 +388,7 @@
 Test911
  getAllStackTraces (I)[[Ljava/lang/Object; -1 -2
  printAll (I)V 0 75
- doTest ()V 120 59
+ doTest ()V 118 59
  run ()V 24 37
 
 ---------
@@ -643,7 +643,7 @@
 Test911
  getAllStackTraces (I)[[Ljava/lang/Object; -1 -2
  printAll (I)V 0 75
- doTest ()V 125 61
+ doTest ()V 123 61
  run ()V 24 37
 
 ---------
@@ -675,7 +675,7 @@
 Test911
  getThreadListStackTraces ([Ljava/lang/Thread;I)[[Ljava/lang/Object; -1 -2
  printList ([Ljava/lang/Thread;I)V 0 68
- doTest ()V 110 54
+ doTest ()V 108 54
  run ()V 32 41
 
 ---------
@@ -732,7 +732,7 @@
 Test911
  getThreadListStackTraces ([Ljava/lang/Thread;I)[[Ljava/lang/Object; -1 -2
  printList ([Ljava/lang/Thread;I)V 0 68
- doTest ()V 115 56
+ doTest ()V 113 56
  run ()V 32 41
 
 ---------
@@ -857,7 +857,7 @@
 4
 JVMTI_ERROR_ILLEGAL_ARGUMENT
 [public static native java.lang.Object[] art.Frames.getFrameLocation(java.lang.Thread,int), ffffffff]
-[public static void art.Frames.doTestSameThread(), 40]
+[public static void art.Frames.doTestSameThread(), 3e]
 [public static void art.Frames.doTest() throws java.lang.Exception, 0]
 [public void art.Test911$1.run(), 28]
 JVMTI_ERROR_NO_MORE_FRAMES
diff --git a/test/913-heaps/expected.txt b/test/913-heaps/expected.txt
index 065b854..1bd56d1 100644
--- a/test/913-heaps/expected.txt
+++ b/test/913-heaps/expected.txt
@@ -1,9 +1,9 @@
 ---
 true true
-root@root --(jni-local[id=1,tag=3000,depth=0,method=followReferences])--> 3000@0 [size=132, length=-1]
+root@root --(jni-local[id=1,tag=3000,depth=0,method=followReferences])--> 3000@0 [size=124, length=-1]
 root@root --(stack-local[id=1,tag=3000,depth=2,method=doFollowReferencesTestNonRoot,vreg=8,location= 31])--> 1@1000 [size=16, length=-1]
-root@root --(stack-local[id=1,tag=3000,depth=5,method=run,vreg=2,location= 0])--> 3000@0 [size=132, length=-1]
-root@root --(thread)--> 3000@0 [size=132, length=-1]
+root@root --(stack-local[id=1,tag=3000,depth=5,method=run,vreg=2,location= 0])--> 3000@0 [size=124, length=-1]
+root@root --(thread)--> 3000@0 [size=124, length=-1]
 1001@0 --(superclass)--> 1000@0 [size=123456780000, length=-1]
 1002@0 --(interface)--> 2001@0 [size=123456780004, length=-1]
 1002@0 --(superclass)--> 1001@0 [size=123456780001, length=-1]
@@ -44,14 +44,14 @@
 ---
 root@root --(jni-global)--> 1@1000 [size=16, length=-1]
 root@root --(jni-local[id=1,tag=3000,depth=0,method=followReferences])--> 1@1000 [size=16, length=-1]
-root@root --(jni-local[id=1,tag=3000,depth=0,method=followReferences])--> 3000@0 [size=132, length=-1]
+root@root --(jni-local[id=1,tag=3000,depth=0,method=followReferences])--> 3000@0 [size=124, length=-1]
 root@root --(stack-local[id=1,tag=3000,depth=1,method=doFollowReferencesTestImpl,vreg=10,location= 8])--> 1@1000 [size=16, length=-1]
 root@root --(stack-local[id=1,tag=3000,depth=1,method=doFollowReferencesTestImpl,vreg=5,location= 8])--> 1@1000 [size=16, length=-1]
 root@root --(stack-local[id=1,tag=3000,depth=2,method=doFollowReferencesTestRoot,vreg=13,location= 20])--> 1@1000 [size=16, length=-1]
 root@root --(stack-local[id=1,tag=3000,depth=2,method=doFollowReferencesTestRoot,vreg=4,location= 20])--> 1@1000 [size=16, length=-1]
-root@root --(stack-local[id=1,tag=3000,depth=5,method=run,vreg=2,location= 0])--> 3000@0 [size=132, length=-1]
+root@root --(stack-local[id=1,tag=3000,depth=5,method=run,vreg=2,location= 0])--> 3000@0 [size=124, length=-1]
 root@root --(thread)--> 1@1000 [size=16, length=-1]
-root@root --(thread)--> 3000@0 [size=132, length=-1]
+root@root --(thread)--> 3000@0 [size=124, length=-1]
 1001@0 --(superclass)--> 1000@0 [size=123456780005, length=-1]
 1002@0 --(interface)--> 2001@0 [size=123456780009, length=-1]
 1002@0 --(superclass)--> 1001@0 [size=123456780006, length=-1]
@@ -90,18 +90,18 @@
 5@1002 --(field@9)--> 6@1000 [size=16, length=-1]
 6@1000 --(class)--> 1000@0 [size=123456780005, length=-1]
 ---
-root@root --(thread)--> 3000@0 [size=132, length=-1]
+root@root --(thread)--> 3000@0 [size=124, length=-1]
 ---
 3@1001 --(class)--> 1001@0 [size=123456780011, length=-1]
 ---
-root@root --(thread)--> 3000@0 [size=132, length=-1]
+root@root --(thread)--> 3000@0 [size=124, length=-1]
 ---
 3@1001 --(class)--> 1001@0 [size=123456780016, length=-1]
 ---
-root@root --(jni-local[id=1,tag=3000,depth=0,method=followReferences])--> 3000@0 [size=132, length=-1]
+root@root --(jni-local[id=1,tag=3000,depth=0,method=followReferences])--> 3000@0 [size=124, length=-1]
 root@root --(stack-local[id=1,tag=3000,depth=2,method=doFollowReferencesTestNonRoot,vreg=8,location= 31])--> 1@1000 [size=16, length=-1]
-root@root --(stack-local[id=1,tag=3000,depth=5,method=run,vreg=2,location= 0])--> 3000@0 [size=132, length=-1]
-root@root --(thread)--> 3000@0 [size=132, length=-1]
+root@root --(stack-local[id=1,tag=3000,depth=5,method=run,vreg=2,location= 0])--> 3000@0 [size=124, length=-1]
+root@root --(thread)--> 3000@0 [size=124, length=-1]
 ---
 1001@0 --(superclass)--> 1000@0 [size=123456780020, length=-1]
 3@1001 --(class)--> 1001@0 [size=123456780021, length=-1]
@@ -110,14 +110,14 @@
 ---
 root@root --(jni-global)--> 1@1000 [size=16, length=-1]
 root@root --(jni-local[id=1,tag=3000,depth=0,method=followReferences])--> 1@1000 [size=16, length=-1]
-root@root --(jni-local[id=1,tag=3000,depth=0,method=followReferences])--> 3000@0 [size=132, length=-1]
+root@root --(jni-local[id=1,tag=3000,depth=0,method=followReferences])--> 3000@0 [size=124, length=-1]
 root@root --(stack-local[id=1,tag=3000,depth=1,method=doFollowReferencesTestImpl,vreg=10,location= 8])--> 1@1000 [size=16, length=-1]
 root@root --(stack-local[id=1,tag=3000,depth=1,method=doFollowReferencesTestImpl,vreg=5,location= 8])--> 1@1000 [size=16, length=-1]
 root@root --(stack-local[id=1,tag=3000,depth=2,method=doFollowReferencesTestRoot,vreg=13,location= 20])--> 1@1000 [size=16, length=-1]
 root@root --(stack-local[id=1,tag=3000,depth=2,method=doFollowReferencesTestRoot,vreg=4,location= 20])--> 1@1000 [size=16, length=-1]
-root@root --(stack-local[id=1,tag=3000,depth=5,method=run,vreg=2,location= 0])--> 3000@0 [size=132, length=-1]
+root@root --(stack-local[id=1,tag=3000,depth=5,method=run,vreg=2,location= 0])--> 3000@0 [size=124, length=-1]
 root@root --(thread)--> 1@1000 [size=16, length=-1]
-root@root --(thread)--> 3000@0 [size=132, length=-1]
+root@root --(thread)--> 3000@0 [size=124, length=-1]
 ---
 1001@0 --(superclass)--> 1000@0 [size=123456780025, length=-1]
 3@1001 --(class)--> 1001@0 [size=123456780026, length=-1]
@@ -198,10 +198,10 @@
 ---
 ---
 ---- untagged objects
-root@root --(jni-local[id=1,tag=3000,depth=0,method=followReferences])--> 3000@0 [size=132, length=-1]
+root@root --(jni-local[id=1,tag=3000,depth=0,method=followReferences])--> 3000@0 [size=124, length=-1]
 root@root --(stack-local[id=1,tag=3000,depth=2,method=doFollowReferencesTestNonRoot,vreg=8,location= 31])--> 1@1000 [size=16, length=-1]
-root@root --(stack-local[id=1,tag=3000,depth=5,method=run,vreg=2,location= 0])--> 3000@0 [size=132, length=-1]
-root@root --(thread)--> 3000@0 [size=132, length=-1]
+root@root --(stack-local[id=1,tag=3000,depth=5,method=run,vreg=2,location= 0])--> 3000@0 [size=124, length=-1]
+root@root --(thread)--> 3000@0 [size=124, length=-1]
 1001@0 --(superclass)--> 1000@0 [size=123456780050, length=-1]
 1002@0 --(interface)--> 2001@0 [size=123456780054, length=-1]
 1002@0 --(superclass)--> 1001@0 [size=123456780051, length=-1]
@@ -242,14 +242,14 @@
 ---
 root@root --(jni-global)--> 1@1000 [size=16, length=-1]
 root@root --(jni-local[id=1,tag=3000,depth=0,method=followReferences])--> 1@1000 [size=16, length=-1]
-root@root --(jni-local[id=1,tag=3000,depth=0,method=followReferences])--> 3000@0 [size=132, length=-1]
+root@root --(jni-local[id=1,tag=3000,depth=0,method=followReferences])--> 3000@0 [size=124, length=-1]
 root@root --(stack-local[id=1,tag=3000,depth=1,method=doFollowReferencesTestImpl,vreg=10,location= 8])--> 1@1000 [size=16, length=-1]
 root@root --(stack-local[id=1,tag=3000,depth=1,method=doFollowReferencesTestImpl,vreg=5,location= 8])--> 1@1000 [size=16, length=-1]
 root@root --(stack-local[id=1,tag=3000,depth=2,method=doFollowReferencesTestRoot,vreg=13,location= 20])--> 1@1000 [size=16, length=-1]
 root@root --(stack-local[id=1,tag=3000,depth=2,method=doFollowReferencesTestRoot,vreg=4,location= 20])--> 1@1000 [size=16, length=-1]
-root@root --(stack-local[id=1,tag=3000,depth=5,method=run,vreg=2,location= 0])--> 3000@0 [size=132, length=-1]
+root@root --(stack-local[id=1,tag=3000,depth=5,method=run,vreg=2,location= 0])--> 3000@0 [size=124, length=-1]
 root@root --(thread)--> 1@1000 [size=16, length=-1]
-root@root --(thread)--> 3000@0 [size=132, length=-1]
+root@root --(thread)--> 3000@0 [size=124, length=-1]
 1001@0 --(superclass)--> 1000@0 [size=123456780055, length=-1]
 1002@0 --(interface)--> 2001@0 [size=123456780059, length=-1]
 1002@0 --(superclass)--> 1001@0 [size=123456780056, length=-1]
@@ -289,9 +289,9 @@
 6@1000 --(class)--> 1000@0 [size=123456780055, length=-1]
 ---
 ---- tagged classes
-root@root --(jni-local[id=1,tag=3000,depth=0,method=followReferences])--> 3000@0 [size=132, length=-1]
-root@root --(stack-local[id=1,tag=3000,depth=5,method=run,vreg=2,location= 0])--> 3000@0 [size=132, length=-1]
-root@root --(thread)--> 3000@0 [size=132, length=-1]
+root@root --(jni-local[id=1,tag=3000,depth=0,method=followReferences])--> 3000@0 [size=124, length=-1]
+root@root --(stack-local[id=1,tag=3000,depth=5,method=run,vreg=2,location= 0])--> 3000@0 [size=124, length=-1]
+root@root --(thread)--> 3000@0 [size=124, length=-1]
 1001@0 --(superclass)--> 1000@0 [size=123456780060, length=-1]
 1002@0 --(interface)--> 2001@0 [size=123456780064, length=-1]
 1002@0 --(superclass)--> 1001@0 [size=123456780061, length=-1]
@@ -316,9 +316,9 @@
 5@1002 --(field@8)--> 500@0 [size=20, length=2]
 6@1000 --(class)--> 1000@0 [size=123456780060, length=-1]
 ---
-root@root --(jni-local[id=1,tag=3000,depth=0,method=followReferences])--> 3000@0 [size=132, length=-1]
-root@root --(stack-local[id=1,tag=3000,depth=5,method=run,vreg=2,location= 0])--> 3000@0 [size=132, length=-1]
-root@root --(thread)--> 3000@0 [size=132, length=-1]
+root@root --(jni-local[id=1,tag=3000,depth=0,method=followReferences])--> 3000@0 [size=124, length=-1]
+root@root --(stack-local[id=1,tag=3000,depth=5,method=run,vreg=2,location= 0])--> 3000@0 [size=124, length=-1]
+root@root --(thread)--> 3000@0 [size=124, length=-1]
 1001@0 --(superclass)--> 1000@0 [size=123456780065, length=-1]
 1002@0 --(interface)--> 2001@0 [size=123456780069, length=-1]
 1002@0 --(superclass)--> 1001@0 [size=123456780066, length=-1]
diff --git a/test/Android.run-test.mk b/test/Android.run-test.mk
index 64c1d4f..148aea4 100644
--- a/test/Android.run-test.mk
+++ b/test/Android.run-test.mk
@@ -59,6 +59,7 @@
 ART_TEST_HOST_RUN_TEST_DEPENDENCIES := \
   $(ART_HOST_EXECUTABLES) \
   $(HOST_OUT_EXECUTABLES)/hprof-conv \
+  $(HOST_OUT_EXECUTABLES)/timeout_dumper \
   $(OUT_DIR)/$(ART_TEST_LIST_host_$(ART_HOST_ARCH)_libtiagent) \
   $(OUT_DIR)/$(ART_TEST_LIST_host_$(ART_HOST_ARCH)_libtiagentd) \
   $(OUT_DIR)/$(ART_TEST_LIST_host_$(ART_HOST_ARCH)_libtistress) \
diff --git a/test/etc/run-test-jar b/test/etc/run-test-jar
index 900b1d7..6488d24 100755
--- a/test/etc/run-test-jar
+++ b/test/etc/run-test-jar
@@ -31,6 +31,8 @@
 GDB_SERVER="gdbserver"
 HAVE_IMAGE="y"
 HOST="n"
+BIONIC="n"
+CREATE_ANDROID_ROOT="n"
 INTERPRETER="n"
 JIT="n"
 INVOKE_WITH=""
@@ -209,6 +211,13 @@
         HOST="y"
         ANDROID_ROOT="$ANDROID_HOST_OUT"
         shift
+    elif [ "x$1" = "x--bionic" ]; then
+        BIONIC="y"
+        # We need to create an ANDROID_ROOT because currently we cannot create
+        # the frameworks/libcore with linux_bionic so we need to use the normal
+        # host ones which are in a different location.
+        CREATE_ANDROID_ROOT="y"
+        shift
     elif [ "x$1" = "x--no-prebuild" ]; then
         PREBUILD="n"
         shift
@@ -374,6 +383,10 @@
     done
 fi
 
+if [ "$CREATE_ANDROID_ROOT" = "y" ]; then
+    ANDROID_ROOT=$DEX_LOCATION/android-root
+fi
+
 if [ "x$1" = "x" ] ; then
   MAIN="Main"
 else
@@ -644,6 +657,15 @@
   fi
 fi
 
+if [ "$BIONIC" = "y" ]; then
+  # This is the location that soong drops linux_bionic builds. Despite being
+  # called linux_bionic-x86 the build is actually amd64 (x86_64) only.
+  if [ ! -e "$OUT_DIR/soong/host/linux_bionic-x86" ]; then
+    echo "linux_bionic-x86 target doesn't seem to have been built!" >&2
+    exit 1
+  fi
+fi
+
 # Prevent test from silently falling back to interpreter in no-prebuild mode. This happens
 # when DEX_LOCATION path is too long, because vdex/odex filename is constructed by taking
 # full path to dex, stripping leading '/', appending '@classes.vdex' and changing every
@@ -671,6 +693,21 @@
 mkdir_locations="${DEX_LOCATION}/dalvik-cache/$ISA"
 strip_cmdline="true"
 sync_cmdline="true"
+linkroot_cmdline="true"
+linkroot_overlay_cmdline="true"
+
+linkdirs() {
+  find "$1" -maxdepth 1 -mindepth 1 -type d | xargs -i ln -sf '{}' "$2"
+}
+
+if [ "$CREATE_ANDROID_ROOT" = "y" ]; then
+  mkdir_locations="${mkdir_locations} ${ANDROID_ROOT}"
+  linkroot_cmdline="linkdirs ${ANDROID_HOST_OUT} ${ANDROID_ROOT}"
+  if [ "${BIONIC}" = "y" ]; then
+    # TODO Make this overlay more generic.
+    linkroot_overlay_cmdline="linkdirs $OUT_DIR/soong/host/linux_bionic-x86 ${ANDROID_ROOT}"
+  fi
+fi
 
 # PROFILE takes precedence over RANDOM_PROFILE, since PROFILE tests require a
 # specific profile to run properly.
@@ -942,14 +979,15 @@
       # Note: We first send SIGRTMIN+2 (usually 36) to ART, which will induce a full thread dump
       #       before abort. However, dumping threads might deadlock, so we also use the "-k"
       #       option to definitely kill the child.
-      cmdline="timeout -k 120s -s SIGRTMIN+2 ${TIME_OUT_VALUE}s $cmdline"
+      cmdline="timeout -k 120s -s SIGRTMIN+2 ${TIME_OUT_VALUE}s timeout_dumper $cmdline"
     fi
 
     if [ "$DEV_MODE" = "y" ]; then
       for var in ANDROID_PRINTF_LOG ANDROID_DATA ANDROID_ROOT LD_LIBRARY_PATH DYLD_LIBRARY_PATH PATH LD_USE_LOAD_BIAS; do
         echo EXPORT $var=${!var}
       done
-      echo "mkdir -p ${mkdir_locations} && $profman_cmdline && $dex2oat_cmdline && $dm_cmdline && $vdex_cmdline && $strip_cmdline && $sync_cmdline && $cmdline"
+      echo "$(declare -f linkdirs)"
+      echo "mkdir -p ${mkdir_locations} && $linkroot_cmdline && $linkroot_overlay_cmdline && $profman_cmdline && $dex2oat_cmdline && $dm_cmdline && $vdex_cmdline && $strip_cmdline && $sync_cmdline && $cmdline"
     fi
 
     cd $ANDROID_BUILD_TOP
@@ -963,6 +1001,8 @@
     export ASAN_OPTIONS=$RUN_TEST_ASAN_OPTIONS
 
     mkdir -p ${mkdir_locations} || exit 1
+    $linkroot_cmdline || { echo "create symlink android-root failed." >&2 ; exit 2; }
+    $linkroot_overlay_cmdline || { echo "overlay android-root failed." >&2 ; exit 2; }
     $profman_cmdline || { echo "Profman failed." >&2 ; exit 2; }
     $dex2oat_cmdline || { echo "Dex2oat failed." >&2 ; exit 2; }
     $dm_cmdline || { echo "Dex2oat failed." >&2 ; exit 2; }
diff --git a/test/run-test b/test/run-test
index 229e201..2363152 100755
--- a/test/run-test
+++ b/test/run-test
@@ -88,6 +88,8 @@
     export ANDROID_HOST_OUT=${OUT_DIR}/host/linux-x86
 fi
 
+host_lib_root=${ANDROID_HOST_OUT}
+
 # Allow changing DESUGAR script to something else, or to disable it with DESUGAR=false.
 if [ -z "$DESUGAR" ]; then
   export DESUGAR="$ANDROID_BUILD_TOP/art/tools/desugar.sh"
@@ -385,6 +387,14 @@
         run_args="${run_args} --64"
         suffix64="64"
         shift
+    elif [ "x$1" = "x--bionic" ]; then
+        # soong linux_bionic builds are 64bit only.
+        run_args="${run_args} --bionic --host --64"
+        suffix64="64"
+        target_mode="no"
+        DEX_LOCATION=$tmp_dir
+        host_lib_root=$OUT_DIR/soong/host/linux_bionic-x86
+        shift
     elif [ "x$1" = "x--trace" ]; then
         trace="true"
         shift
@@ -584,7 +594,7 @@
     if [ "$target_mode" = "no" ]; then
         guess_host_arch_name
         run_args="${run_args} --boot ${ANDROID_HOST_OUT}/framework/core${image_suffix}.art"
-        run_args="${run_args} --runtime-option -Djava.library.path=${ANDROID_HOST_OUT}/lib${suffix64}:${ANDROID_HOST_OUT}/nativetest${suffix64}"
+        run_args="${run_args} --runtime-option -Djava.library.path=${host_lib_root}/lib${suffix64}:${host_lib_root}/nativetest${suffix64}"
     else
         guess_target_arch_name
         run_args="${run_args} --runtime-option -Djava.library.path=/data/nativetest${suffix64}/art/${target_arch_name}"
@@ -711,6 +721,7 @@
         echo "    --output-path [path]  Location where to store the build" \
              "files."
         echo "    --64                  Run the test in 64-bit mode"
+        echo "    --bionic              Use the (host, 64-bit only) linux_bionic libc runtime"
         echo "    --trace               Run with method tracing"
         echo "    --strace              Run with syscall tracing from strace."
         echo "    --stream              Run method tracing in streaming mode (requires --trace)"
diff --git a/tools/build_linux_bionic_tests.sh b/tools/build_linux_bionic_tests.sh
new file mode 100755
index 0000000..dba2d50
--- /dev/null
+++ b/tools/build_linux_bionic_tests.sh
@@ -0,0 +1,101 @@
+#!/bin/bash
+#
+# Copyright (C) 2018 The Android Open Source Project
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#      http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+
+if [[ -z $ANDROID_BUILD_TOP ]]; then
+  pushd .
+else
+  pushd $ANDROID_BUILD_TOP
+fi
+
+if [ ! -d art ]; then
+  echo "Script needs to be run at the root of the android tree"
+  exit 1
+fi
+
+source build/envsetup.sh >&/dev/null # for get_build_var
+
+out_dir=$(get_build_var OUT_DIR)
+
+# TODO(b/31559095) Figure out a better way to do this.
+#
+# There is no good way to force soong to generate host-bionic builds currently
+# so this is a hacky workaround.
+
+# First build all the targets still in .mk files (also build normal glibc host
+# targets so we know what's needed to run the tests).
+build/soong/soong_ui.bash --make-mode "$@" test-art-host-run-test-dependencies build-art-host-tests
+if [ $? != 0 ]; then
+  exit 1
+fi
+
+tmp_soong_var=$(mktemp --tmpdir soong.variables.bak.XXXXXX)
+
+echo "Saving soong.variables to " $tmp_soong_var
+cat $out_dir/soong/soong.variables > ${tmp_soong_var}
+python3 <<END - ${tmp_soong_var} ${out_dir}/soong/soong.variables
+import json
+import sys
+x = json.load(open(sys.argv[1]))
+x['Allow_missing_dependencies'] = True
+x['HostArch'] = 'x86_64'
+x['CrossHost'] = 'linux_bionic'
+x['CrossHostArch'] = 'x86_64'
+if 'CrossHostSecondaryArch' in x:
+  del x['CrossHostSecondaryArch']
+json.dump(x, open(sys.argv[2], mode='w'))
+END
+if [ $? != 0 ]; then
+  mv $tmp_soong_var $out_dir/soong/soong.variables
+  exit 2
+fi
+
+soong_out=$out_dir/soong/host/linux_bionic-x86
+declare -a bionic_targets
+# These are the binaries actually used in tests. Since some of the files are
+# java targets or 32 bit we cannot just do the same find for the bin files.
+#
+# We look at what the earlier build generated to figure out what to ask soong to
+# build since we cannot use the .mk defined phony targets.
+bionic_targets=(
+  $soong_out/bin/dalvikvm
+  $soong_out/bin/dalvikvm64
+  $soong_out/bin/dex2oat
+  $soong_out/bin/dex2oatd
+  $soong_out/bin/profman
+  $soong_out/bin/profmand
+  $soong_out/bin/hiddenapi
+  $soong_out/bin/hprof-conv
+  $(find $ANDROID_HOST_OUT/lib64 -type f | sed "s:$ANDROID_HOST_OUT:$soong_out:g")
+  $(find $ANDROID_HOST_OUT/nativetest64 -type f | sed "s:$ANDROID_HOST_OUT:$soong_out:g"))
+
+echo building ${bionic_targets[*]}
+
+build/soong/soong_ui.bash --make-mode --skip-make "$@" ${bionic_targets[*]}
+ret=$?
+
+mv $tmp_soong_var $out_dir/soong/soong.variables
+
+# Having built with host-bionic confuses soong somewhat by making it think the
+# linux_bionic targets are needed for art phony targets like
+# test-art-host-run-test-dependencies. To work around this blow away all
+# ninja files in OUT_DIR. The build system is smart enough to not need to
+# rebuild stuff so this should be fine.
+rm -f $OUT_DIR/*.ninja $OUT_DIR/soong/*.ninja
+
+popd
+
+exit $ret
diff --git a/tools/timeout_dumper/Android.bp b/tools/timeout_dumper/Android.bp
new file mode 100644
index 0000000..dfd5442
--- /dev/null
+++ b/tools/timeout_dumper/Android.bp
@@ -0,0 +1,39 @@
+//
+// Copyright (C) 2018 The Android Open Source Project
+//
+// Licensed under the Apache License, Version 2.0 (the "License");
+// you may not use this file except in compliance with the License.
+// You may obtain a copy of the License at
+//
+//      http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing, software
+// distributed under the License is distributed on an "AS IS" BASIS,
+// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+// See the License for the specific language governing permissions and
+// limitations under the License.
+//
+
+art_cc_binary {
+    name: "timeout_dumper",
+
+    host_supported: true,
+    target: {
+        darwin: {
+            enabled: false,
+        },
+    },
+    device_supported: false,
+
+    defaults: ["art_defaults"],
+
+    srcs: ["timeout_dumper.cc"],
+
+    shared_libs: [
+        "libbacktrace",
+        "libbase",
+    ],
+    sanitize: {
+        address: true,
+    },
+}
diff --git a/tools/timeout_dumper/timeout_dumper.cc b/tools/timeout_dumper/timeout_dumper.cc
new file mode 100644
index 0000000..cb3eaa5
--- /dev/null
+++ b/tools/timeout_dumper/timeout_dumper.cc
@@ -0,0 +1,590 @@
+/*
+ * Copyright (C) 2018 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <dirent.h>
+#include <poll.h>
+#include <sys/prctl.h>
+#include <sys/ptrace.h>
+#include <sys/types.h>
+#include <sys/wait.h>
+#include <unistd.h>
+
+#include <csignal>
+#include <cstdlib>
+#include <cstring>
+#include <thread>
+#include <memory>
+#include <set>
+
+#include <android-base/file.h>
+#include <android-base/logging.h>
+#include <android-base/macros.h>
+#include <android-base/stringprintf.h>
+#include <android-base/strings.h>
+#include <android-base/unique_fd.h>
+#include <backtrace/Backtrace.h>
+#include <backtrace/BacktraceMap.h>
+
+namespace art {
+namespace {
+
+using android::base::StringPrintf;
+using android::base::unique_fd;
+
+constexpr bool kUseAddr2line = true;
+
+namespace timeout_signal {
+
+class SignalSet {
+ public:
+  SignalSet() {
+    if (sigemptyset(&set_) == -1) {
+      PLOG(FATAL) << "sigemptyset failed";
+    }
+  }
+
+  void Add(int signal) {
+    if (sigaddset(&set_, signal) == -1) {
+      PLOG(FATAL) << "sigaddset " << signal << " failed";
+    }
+  }
+
+  void Block() {
+    if (pthread_sigmask(SIG_BLOCK, &set_, nullptr) != 0) {
+      PLOG(FATAL) << "pthread_sigmask failed";
+    }
+  }
+
+  int Wait() {
+    // Sleep in sigwait() until a signal arrives. gdb causes EINTR failures.
+    int signal_number;
+    int rc = TEMP_FAILURE_RETRY(sigwait(&set_, &signal_number));
+    if (rc != 0) {
+      PLOG(FATAL) << "sigwait failed";
+    }
+    return signal_number;
+  }
+
+ private:
+  sigset_t set_;
+};
+
+int GetTimeoutSignal() {
+  return SIGRTMIN + 2;
+}
+
+}  // namespace timeout_signal
+
+namespace addr2line {
+
+constexpr const char* kAddr2linePath =
+    "/prebuilts/gcc/linux-x86/host/x86_64-linux-glibc2.15-4.8/bin/x86_64-linux-addr2line";
+
+std::unique_ptr<std::string> FindAddr2line() {
+  const char* env_value = getenv("ANDROID_BUILD_TOP");
+  if (env_value != nullptr) {
+    std::string path = std::string(env_value) + kAddr2linePath;
+    if (access(path.c_str(), X_OK) == 0) {
+      return std::make_unique<std::string>(path);
+    }
+  }
+
+  std::string path = std::string(".") + kAddr2linePath;
+  if (access(path.c_str(), X_OK) == 0) {
+    return std::make_unique<std::string>(path);
+  }
+
+  constexpr const char* kHostAddr2line = "/usr/bin/addr2line";
+  if (access(kHostAddr2line, F_OK) == 0) {
+    return std::make_unique<std::string>(kHostAddr2line);
+  }
+
+  return nullptr;
+}
+
+// The state of an open pipe to addr2line. In "server" mode, addr2line takes input on stdin
+// and prints the result to stdout. This struct keeps the state of the open connection.
+struct Addr2linePipe {
+  Addr2linePipe(int in_fd, int out_fd, const std::string& file_name, pid_t pid)
+      : in(in_fd), out(out_fd), file(file_name), child_pid(pid), odd(true) {}
+
+  ~Addr2linePipe() {
+    kill(child_pid, SIGKILL);
+  }
+
+  unique_fd in;      // The file descriptor that is connected to the output of addr2line.
+  unique_fd out;     // The file descriptor that is connected to the input of addr2line.
+
+  const std::string file;     // The file addr2line is working on, so that we know when to close
+                              // and restart.
+  const pid_t child_pid;      // The pid of the child, which we should kill when we're done.
+  bool odd;                   // Print state for indentation of lines.
+};
+
+std::unique_ptr<Addr2linePipe> Connect(const std::string& name, const char* args[]) {
+  int caller_to_addr2line[2];
+  int addr2line_to_caller[2];
+
+  if (pipe(caller_to_addr2line) == -1) {
+    return nullptr;
+  }
+  if (pipe(addr2line_to_caller) == -1) {
+    close(caller_to_addr2line[0]);
+    close(caller_to_addr2line[1]);
+    return nullptr;
+  }
+
+  pid_t pid = fork();
+  if (pid == -1) {
+    close(caller_to_addr2line[0]);
+    close(caller_to_addr2line[1]);
+    close(addr2line_to_caller[0]);
+    close(addr2line_to_caller[1]);
+    return nullptr;
+  }
+
+  if (pid == 0) {
+    dup2(caller_to_addr2line[0], STDIN_FILENO);
+    dup2(addr2line_to_caller[1], STDOUT_FILENO);
+
+    close(caller_to_addr2line[0]);
+    close(caller_to_addr2line[1]);
+    close(addr2line_to_caller[0]);
+    close(addr2line_to_caller[1]);
+
+    execv(args[0], const_cast<char* const*>(args));
+    exit(1);
+  } else {
+    close(caller_to_addr2line[0]);
+    close(addr2line_to_caller[1]);
+    return std::make_unique<Addr2linePipe>(addr2line_to_caller[0],
+                                           caller_to_addr2line[1],
+                                           name,
+                                           pid);
+  }
+}
+
+void WritePrefix(std::ostream& os, const char* prefix, bool odd) {
+  if (prefix != nullptr) {
+    os << prefix;
+  }
+  os << "  ";
+  if (!odd) {
+    os << " ";
+  }
+}
+
+void Drain(size_t expected,
+           const char* prefix,
+           std::unique_ptr<Addr2linePipe>* pipe /* inout */,
+           std::ostream& os) {
+  DCHECK(pipe != nullptr);
+  DCHECK(pipe->get() != nullptr);
+  int in = pipe->get()->in.get();
+  DCHECK_GE(in, 0);
+
+  bool prefix_written = false;
+
+  for (;;) {
+    constexpr uint32_t kWaitTimeExpectedMilli = 500;
+    constexpr uint32_t kWaitTimeUnexpectedMilli = 50;
+
+    int timeout = expected > 0 ? kWaitTimeExpectedMilli : kWaitTimeUnexpectedMilli;
+    struct pollfd read_fd{in, POLLIN, 0};
+    int retval = TEMP_FAILURE_RETRY(poll(&read_fd, 1, timeout));
+    if (retval == -1) {
+      // An error occurred.
+      pipe->reset();
+      return;
+    }
+
+    if (retval == 0) {
+      // Timeout.
+      return;
+    }
+
+    if (!(read_fd.revents & POLLIN)) {
+      // addr2line call exited.
+      pipe->reset();
+      return;
+    }
+
+    constexpr size_t kMaxBuffer = 128;  // Relatively small buffer. Should be OK as we're on an
+    // alt stack, but just to be sure...
+    char buffer[kMaxBuffer];
+    memset(buffer, 0, kMaxBuffer);
+    int bytes_read = TEMP_FAILURE_RETRY(read(in, buffer, kMaxBuffer - 1));
+    if (bytes_read <= 0) {
+      // This should not really happen...
+      pipe->reset();
+      return;
+    }
+    buffer[bytes_read] = '\0';
+
+    char* tmp = buffer;
+    while (*tmp != 0) {
+      if (!prefix_written) {
+        WritePrefix(os, prefix, (*pipe)->odd);
+        prefix_written = true;
+      }
+      char* new_line = strchr(tmp, '\n');
+      if (new_line == nullptr) {
+        os << tmp;
+
+        break;
+      } else {
+        char saved = *(new_line + 1);
+        *(new_line + 1) = 0;
+        os << tmp;
+        *(new_line + 1) = saved;
+
+        tmp = new_line + 1;
+        prefix_written = false;
+        (*pipe)->odd = !(*pipe)->odd;
+
+        if (expected > 0) {
+          expected--;
+        }
+      }
+    }
+  }
+}
+
+void Addr2line(const std::string& addr2line,
+               const std::string& map_src,
+               uintptr_t offset,
+               std::ostream& os,
+               const char* prefix,
+               std::unique_ptr<Addr2linePipe>* pipe /* inout */) {
+  DCHECK(pipe != nullptr);
+
+  if (map_src == "[vdso]" || android::base::EndsWith(map_src, ".vdex")) {
+    // addr2line will not work on the vdso.
+    // vdex files are special frames injected for the interpreter
+    // so they don't have any line number information available.
+    return;
+  }
+
+  if (*pipe == nullptr || (*pipe)->file != map_src) {
+    if (*pipe != nullptr) {
+      Drain(0, prefix, pipe, os);
+    }
+    pipe->reset();  // Close early.
+
+    const char* args[7] = {
+        addr2line.c_str(),
+        "--functions",
+        "--inlines",
+        "--demangle",
+        "-e",
+        map_src.c_str(),
+        nullptr
+    };
+    *pipe = Connect(map_src, args);
+  }
+
+  Addr2linePipe* pipe_ptr = pipe->get();
+  if (pipe_ptr == nullptr) {
+    // Failed...
+    return;
+  }
+
+  // Send the offset.
+  const std::string hex_offset = StringPrintf("%zx\n", offset);
+
+  if (!android::base::WriteFully(pipe_ptr->out.get(), hex_offset.data(), hex_offset.length())) {
+    // Error. :-(
+    pipe->reset();
+    return;
+  }
+
+  // Now drain (expecting two lines).
+  Drain(2U, prefix, pipe, os);
+}
+
+}  // namespace addr2line
+
+namespace ptrace {
+
+std::set<pid_t> PtraceSiblings(pid_t pid) {
+  std::set<pid_t> ret;
+  std::string task_path = android::base::StringPrintf("/proc/%d/task", pid);
+
+  std::unique_ptr<DIR, int (*)(DIR*)> d(opendir(task_path.c_str()), closedir);
+
+  // Bail early if the task directory cannot be opened.
+  if (d == nullptr) {
+    PLOG(ERROR) << "Failed to scan task folder";
+    return ret;
+  }
+
+  struct dirent* de;
+  while ((de = readdir(d.get())) != nullptr) {
+    // Ignore "." and "..".
+    if (!strcmp(de->d_name, ".") || !strcmp(de->d_name, "..")) {
+      continue;
+    }
+
+    char* end;
+    pid_t tid = strtoul(de->d_name, &end, 10);
+    if (*end) {
+      continue;
+    }
+
+    if (tid == pid) {
+      continue;
+    }
+
+    if (::ptrace(PTRACE_ATTACH, tid, 0, 0) != 0) {
+      PLOG(ERROR) << "Failed to attach to tid " << tid;
+      continue;
+    }
+
+    ret.insert(tid);
+  }
+  return ret;
+}
+
+}  // namespace ptrace
+
+bool WaitForSigStoppedOrError(pid_t pid) {
+  int status;
+  pid_t res = TEMP_FAILURE_RETRY(waitpid(pid, &status, 0));
+  if (res == -1) {
+    PLOG(ERROR) << "Failed to waitpid for " << pid;
+    return false;
+  }
+  if (!(WIFSTOPPED(status))) {
+    LOG(ERROR) << "Did not get expected stopped signal for " << pid;
+    return false;
+  }
+  return true;
+}
+
+#ifdef __LP64__
+constexpr bool kIs64Bit = true;
+#else
+constexpr bool kIs64Bit = false;
+#endif
+
+void DumpThread(pid_t pid,
+                pid_t tid,
+                const std::string* addr2line_path,
+                const char* prefix,
+                BacktraceMap* map) {
+  if (pid != tid && !WaitForSigStoppedOrError(tid)) {
+    return;
+  }
+
+  std::unique_ptr<Backtrace> backtrace(Backtrace::Create(pid, tid, map));
+  if (backtrace == nullptr) {
+    LOG(ERROR) << prefix << "(failed to create Backtrace for thread " << tid << ")";
+    return;
+  }
+  backtrace->SetSkipFrames(0);
+  if (!backtrace->Unwind(0, nullptr)) {
+    LOG(ERROR) << prefix << "(backtrace::Unwind failed for thread " << tid
+               << ": " <<  backtrace->GetErrorString(backtrace->GetError()) << ")";
+    return;
+  }
+  if (backtrace->NumFrames() == 0) {
+    LOG(ERROR) << prefix << "(no native stack frames for thread " << tid << ")";
+    return;
+  }
+
+  std::unique_ptr<addr2line::Addr2linePipe> addr2line_state;
+
+  for (Backtrace::const_iterator it = backtrace->begin();
+      it != backtrace->end(); ++it) {
+    std::ostringstream oss;
+    oss << prefix << StringPrintf("#%02zu pc ", it->num);
+    bool try_addr2line = false;
+    if (!BacktraceMap::IsValid(it->map)) {
+      oss << StringPrintf(kIs64Bit ? "%016" PRIx64 "  ???" : "%08" PRIx64 "  ???", it->pc);
+    } else {
+      oss << StringPrintf(kIs64Bit ? "%016" PRIx64 "  " : "%08" PRIx64 "  ", it->rel_pc);
+      if (it->map.name.empty()) {
+        oss << StringPrintf("<anonymous:%" PRIx64 ">", it->map.start);
+      } else {
+        oss << it->map.name;
+      }
+      if (it->map.offset != 0) {
+        oss << StringPrintf(" (offset %" PRIx64 ")", it->map.offset);
+      }
+      oss << " (";
+      if (!it->func_name.empty()) {
+        oss << it->func_name;
+        if (it->func_offset != 0) {
+          oss << "+" << it->func_offset;
+        }
+        // Functions found using the gdb jit interface will be in an empty
+        // map that cannot be found using addr2line.
+        if (!it->map.name.empty()) {
+          try_addr2line = true;
+        }
+      } else {
+        oss << "???";
+      }
+      oss << ")";
+    }
+    LOG(ERROR) << oss.str();
+    if (try_addr2line && addr2line_path != nullptr) {
+      addr2line::Addr2line(*addr2line_path,
+                           it->map.name,
+                           it->pc - it->map.start,
+                           LOG_STREAM(ERROR),
+                           prefix,
+                           &addr2line_state);
+    }
+  }
+
+  if (addr2line_state != nullptr) {
+    addr2line::Drain(0, prefix, &addr2line_state, LOG_STREAM(ERROR));
+  }
+}
+
+bool WaitForMainSigStop(const std::atomic<bool>& saw_wif_stopped_for_main) {
+  constexpr uint32_t kWaitMicros = 10;
+  constexpr size_t kMaxLoopCount = 10 * 1000 * 1000 / kWaitMicros;  // 10s wait.
+
+  for (size_t loop_count = 0; !saw_wif_stopped_for_main; ++loop_count) {
+    if (loop_count > kMaxLoopCount) {
+      LOG(ERROR) << "Waited too long for main pid to stop";
+      return false;
+    }
+
+    timespec tm;
+    tm.tv_sec = 0;
+    tm.tv_nsec = kWaitMicros * 1000;
+    nanosleep(&tm, nullptr);
+  }
+  return true;
+}
+
+void DumpProcess(pid_t forked_pid, const std::atomic<bool>& saw_wif_stopped_for_main) {
+  CHECK_EQ(0, ::ptrace(PTRACE_ATTACH, forked_pid, 0, 0));
+  std::set<pid_t> tids = ptrace::PtraceSiblings(forked_pid);
+  tids.insert(forked_pid);
+
+  // Check whether we have and should use addr2line.
+  std::unique_ptr<std::string> addr2line_path = addr2line::FindAddr2line();
+  if (addr2line_path != nullptr) {
+    LOG(ERROR) << "Found addr2line at " << *addr2line_path;
+  } else {
+    LOG(ERROR) << "Did not find usable addr2line";
+  }
+  bool use_addr2line = kUseAddr2line && addr2line_path != nullptr;
+  LOG(ERROR) << (use_addr2line ? "U" : "Not u") << "sing addr2line";
+
+  if (!WaitForMainSigStop(saw_wif_stopped_for_main)) {
+    return;
+  }
+
+  std::unique_ptr<BacktraceMap> backtrace_map(BacktraceMap::Create(forked_pid));
+  if (backtrace_map == nullptr) {
+    LOG(ERROR) << "Could not create BacktraceMap";
+    return;
+  }
+
+  for (pid_t tid : tids) {
+    LOG(ERROR) << "pid: " << forked_pid << " tid: " << tid;
+    DumpThread(forked_pid,
+               tid,
+               use_addr2line ? addr2line_path.get() : nullptr,
+               "  ",
+               backtrace_map.get());
+  }
+}
+
+[[noreturn]]
+void WaitMainLoop(pid_t forked_pid, std::atomic<bool>* saw_wif_stopped_for_main) {
+  for (;;) {
+    // Consider switching to waitid to not get woken up for WIFSTOPPED.
+    int status;
+    pid_t res = TEMP_FAILURE_RETRY(waitpid(forked_pid, &status, 0));
+    if (res == -1) {
+      PLOG(FATAL) << "Failure during waitpid";
+      __builtin_unreachable();
+    }
+
+    if (WIFEXITED(status)) {
+      _exit(WEXITSTATUS(status));
+      __builtin_unreachable();
+    }
+    if (WIFSIGNALED(status)) {
+      _exit(1);
+      __builtin_unreachable();
+    }
+    if (WIFSTOPPED(status)) {
+      *saw_wif_stopped_for_main = true;
+      continue;
+    }
+    if (WIFCONTINUED(status)) {
+      continue;
+    }
+
+    LOG(FATAL) << "Unknown status " << std::hex << status;
+  }
+}
+
+[[noreturn]]
+void SetupAndWait(pid_t forked_pid) {
+  timeout_signal::SignalSet signals;
+  signals.Add(timeout_signal::GetTimeoutSignal());
+  signals.Block();
+
+  std::atomic<bool> saw_wif_stopped_for_main(false);
+
+  std::thread signal_catcher([&]() {
+    signals.Block();
+    int sig = signals.Wait();
+    CHECK_EQ(sig, timeout_signal::GetTimeoutSignal());
+
+    DumpProcess(forked_pid, saw_wif_stopped_for_main);
+
+    // Don't clean up. Just kill the child and exit.
+    kill(forked_pid, SIGKILL);
+    _exit(1);
+  });
+
+  WaitMainLoop(forked_pid, &saw_wif_stopped_for_main);
+}
+
+}  // namespace
+}  // namespace art
+
+int main(int argc ATTRIBUTE_UNUSED, char** argv) {
+  pid_t orig_ppid = getpid();
+
+  pid_t pid = fork();
+  if (pid == 0) {
+    if (prctl(PR_SET_PDEATHSIG, SIGTERM) == -1) {
+      _exit(1);
+    }
+
+    if (getppid() != orig_ppid) {
+      _exit(2);
+    }
+
+    execvp(argv[1], &argv[1]);
+
+    _exit(3);
+    __builtin_unreachable();
+  }
+
+  art::SetupAndWait(pid);
+  __builtin_unreachable();
+}