Merge "ART: Conditionally add debug version to art-runtime package"
diff --git a/build/art.go b/build/art.go
index db626fd..1b9c646 100644
--- a/build/art.go
+++ b/build/art.go
@@ -19,8 +19,6 @@
 	"android/soong/cc"
 	"fmt"
 	"sync"
-
-	"github.com/google/blueprint"
 )
 
 var supportedArches = []string{"arm", "arm64", "mips", "mips64", "x86", "x86_64"}
@@ -266,67 +264,67 @@
 	android.RegisterModuleType("art_debug_defaults", artDebugDefaultsFactory)
 }
 
-func artGlobalDefaultsFactory() (blueprint.Module, []interface{}) {
-	module, props := artDefaultsFactory()
+func artGlobalDefaultsFactory() android.Module {
+	module := artDefaultsFactory()
 	android.AddLoadHook(module, globalDefaults)
 
-	return module, props
+	return module
 }
 
-func artDebugDefaultsFactory() (blueprint.Module, []interface{}) {
-	module, props := artDefaultsFactory()
+func artDebugDefaultsFactory() android.Module {
+	module := artDefaultsFactory()
 	android.AddLoadHook(module, debugDefaults)
 
-	return module, props
+	return module
 }
 
-func artDefaultsFactory() (blueprint.Module, []interface{}) {
+func artDefaultsFactory() android.Module {
 	c := &codegenProperties{}
-	module, props := cc.DefaultsFactory(c)
+	module := cc.DefaultsFactory(c)
 	android.AddLoadHook(module, func(ctx android.LoadHookContext) { codegen(ctx, c, true) })
 
-	return module, props
+	return module
 }
 
-func artLibrary() (blueprint.Module, []interface{}) {
+func artLibrary() android.Module {
 	library, _ := cc.NewLibrary(android.HostAndDeviceSupported)
-	module, props := library.Init()
+	module := library.Init()
 
-	props = installCodegenCustomizer(module, props, true)
+	installCodegenCustomizer(module, true)
 
-	return module, props
+	return module
 }
 
-func artBinary() (blueprint.Module, []interface{}) {
+func artBinary() android.Module {
 	binary, _ := cc.NewBinary(android.HostAndDeviceSupported)
-	module, props := binary.Init()
+	module := binary.Init()
 
 	android.AddLoadHook(module, customLinker)
 	android.AddLoadHook(module, prefer32Bit)
-	return module, props
+	return module
 }
 
-func artTest() (blueprint.Module, []interface{}) {
+func artTest() android.Module {
 	test := cc.NewTest(android.HostAndDeviceSupported)
-	module, props := test.Init()
+	module := test.Init()
 
-	props = installCodegenCustomizer(module, props, false)
+	installCodegenCustomizer(module, false)
 
 	android.AddLoadHook(module, customLinker)
 	android.AddLoadHook(module, prefer32Bit)
 	android.AddInstallHook(module, testInstall)
-	return module, props
+	return module
 }
 
-func artTestLibrary() (blueprint.Module, []interface{}) {
+func artTestLibrary() android.Module {
 	test := cc.NewTestLibrary(android.HostAndDeviceSupported)
-	module, props := test.Init()
+	module := test.Init()
 
-	props = installCodegenCustomizer(module, props, false)
+	installCodegenCustomizer(module, false)
 
 	android.AddLoadHook(module, prefer32Bit)
 	android.AddInstallHook(module, testInstall)
-	return module, props
+	return module
 }
 
 func envDefault(ctx android.BaseContext, key string, defaultValue string) string {
diff --git a/build/codegen.go b/build/codegen.go
index ba6f214..8526bf1 100644
--- a/build/codegen.go
+++ b/build/codegen.go
@@ -22,8 +22,6 @@
 	"android/soong/android"
 	"sort"
 	"strings"
-
-	"github.com/google/blueprint"
 )
 
 func codegen(ctx android.LoadHookContext, c *codegenProperties, library bool) {
@@ -159,10 +157,8 @@
 	return ret
 }
 
-func installCodegenCustomizer(module blueprint.Module, props []interface{}, library bool) []interface{} {
+func installCodegenCustomizer(module android.Module, library bool) {
 	c := &codegenProperties{}
 	android.AddLoadHook(module, func(ctx android.LoadHookContext) { codegen(ctx, c, library) })
-	props = append(props, c)
-
-	return props
+	module.AddProperties(c)
 }
diff --git a/compiler/driver/compiler_driver-inl.h b/compiler/driver/compiler_driver-inl.h
index 8cc1cc3..a04349e 100644
--- a/compiler/driver/compiler_driver-inl.h
+++ b/compiler/driver/compiler_driver-inl.h
@@ -102,35 +102,6 @@
   return std::make_pair(fast_get, fast_put);
 }
 
-template <typename ArtMember>
-inline bool CompilerDriver::CanAccessResolvedMember(mirror::Class* referrer_class ATTRIBUTE_UNUSED,
-                                                    mirror::Class* access_to ATTRIBUTE_UNUSED,
-                                                    ArtMember* member ATTRIBUTE_UNUSED,
-                                                    mirror::DexCache* dex_cache ATTRIBUTE_UNUSED,
-                                                    uint32_t field_idx ATTRIBUTE_UNUSED) {
-  // Not defined for ArtMember values other than ArtField or ArtMethod.
-  UNREACHABLE();
-}
-
-template <>
-inline bool CompilerDriver::CanAccessResolvedMember<ArtField>(mirror::Class* referrer_class,
-                                                              mirror::Class* access_to,
-                                                              ArtField* field,
-                                                              mirror::DexCache* dex_cache,
-                                                              uint32_t field_idx) {
-  return referrer_class->CanAccessResolvedField(access_to, field, dex_cache, field_idx);
-}
-
-template <>
-inline bool CompilerDriver::CanAccessResolvedMember<ArtMethod>(
-    mirror::Class* referrer_class,
-    mirror::Class* access_to,
-    ArtMethod* method,
-    mirror::DexCache* dex_cache,
-    uint32_t field_idx) {
-  return referrer_class->CanAccessResolvedMethod(access_to, method, dex_cache, field_idx);
-}
-
 inline ArtMethod* CompilerDriver::ResolveMethod(
     ScopedObjectAccess& soa, Handle<mirror::DexCache> dex_cache,
     Handle<mirror::ClassLoader> class_loader, const DexCompilationUnit* mUnit,
diff --git a/compiler/driver/compiler_driver.cc b/compiler/driver/compiler_driver.cc
index 622448f..f834f30 100644
--- a/compiler/driver/compiler_driver.cc
+++ b/compiler/driver/compiler_driver.cc
@@ -2244,6 +2244,10 @@
     mirror::Class::Status old_status = klass->GetStatus();;
     // Only try to initialize classes that were successfully verified.
     if (klass->IsVerified()) {
+      // Don't initialize classes in boot space when compiling app image
+      if (is_app_image && klass->IsBootStrapClassLoaded()) {
+        return;
+      }
       // Attempt to initialize the class but bail if we either need to initialize the super-class
       // or static fields.
       manager_->GetClassLinker()->EnsureInitialized(soa.Self(), klass, false, false);
@@ -2261,12 +2265,19 @@
         ObjectLock<mirror::Class> lock(soa.Self(), h_klass);
         // Attempt to initialize allowing initialization of parent classes but still not static
         // fields.
-        manager_->GetClassLinker()->EnsureInitialized(soa.Self(), klass, false, true);
+        // Initialize dependencies first only for app image, to make TryInitialize recursive.
+        bool is_superclass_initialized = !is_app_image ? true :
+            InitializeDependencies(klass, class_loader, soa.Self());
+        if (!is_app_image || (is_app_image && is_superclass_initialized)) {
+          manager_->GetClassLinker()->EnsureInitialized(soa.Self(), klass, false, true);
+        }
+        // Otherwise it's in app image but superclasses can't be initialized, no need to proceed.
         old_status = klass->GetStatus();
         // If the class was not initialized, we can proceed to see if we can initialize static
         // fields.
         if (!klass->IsInitialized() &&
             (is_app_image || is_boot_image) &&
+            is_superclass_initialized &&
             manager_->GetCompiler()->IsImageClass(descriptor)) {
           bool can_init_static_fields = false;
           if (is_boot_image) {
@@ -2278,8 +2289,6 @@
             CHECK(is_app_image);
             // The boot image case doesn't need to recursively initialize the dependencies with
             // special logic since the class linker already does this.
-            bool is_superclass_initialized =
-                InitializeDependencies(klass, class_loader, soa.Self());
             can_init_static_fields =
                 !soa.Self()->IsExceptionPending() &&
                 is_superclass_initialized &&
diff --git a/compiler/driver/compiler_driver.h b/compiler/driver/compiler_driver.h
index 69f7b1b..cd4f400 100644
--- a/compiler/driver/compiler_driver.h
+++ b/compiler/driver/compiler_driver.h
@@ -381,19 +381,6 @@
   }
 
  private:
-  // Can `referrer_class` access the resolved `member`?
-  // Dispatch call to mirror::Class::CanAccessResolvedField or
-  // mirror::Class::CanAccessResolvedMember depending on the value of
-  // ArtMember.
-  template <typename ArtMember>
-  static bool CanAccessResolvedMember(mirror::Class* referrer_class,
-                                      mirror::Class* access_to,
-                                      ArtMember* member,
-                                      mirror::DexCache* dex_cache,
-                                      uint32_t field_idx)
-      REQUIRES_SHARED(Locks::mutator_lock_);
-
- private:
   void PreCompile(jobject class_loader,
                   const std::vector<const DexFile*>& dex_files,
                   TimingLogger* timings)
diff --git a/compiler/image_writer.cc b/compiler/image_writer.cc
index a8fdeca..4ff5dd2 100644
--- a/compiler/image_writer.cc
+++ b/compiler/image_writer.cc
@@ -473,6 +473,11 @@
                                  start + layout.MethodTypesOffset(),
                                  dex_cache);
     }
+    if (dex_cache->GetResolvedCallSites() != nullptr) {
+      AddDexCacheArrayRelocation(dex_cache->GetResolvedCallSites(),
+                                 start + layout.CallSitesOffset(),
+                                 dex_cache);
+    }
   }
 }
 
@@ -946,11 +951,18 @@
     ArtMethod* method =
         mirror::DexCache::GetElementPtrSize(resolved_methods, i, target_ptr_size_);
     DCHECK(method != nullptr) << "Expected resolution method instead of null method";
-    mirror::Class* declaring_class = method->GetDeclaringClass();
+    // Check if the referenced class is in the image. Note that we want to check the referenced
+    // class rather than the declaring class to preserve the semantics, i.e. using a MethodId
+    // results in resolving the referenced class and that can for example throw OOME.
+    ObjPtr<mirror::Class> referencing_class = class_linker->LookupResolvedType(
+        dex_file,
+        dex_file.GetMethodId(i).class_idx_,
+        dex_cache,
+        class_loader);
     // Copied methods may be held live by a class which was not an image class but have a
     // declaring class which is an image class. Set it to the resolution method to be safe and
     // prevent dangling pointers.
-    if (method->IsCopied() || !KeepClass(declaring_class)) {
+    if (method->IsCopied() || !KeepClass(referencing_class)) {
       mirror::DexCache::SetElementPtrSize(resolved_methods,
                                           i,
                                           resolution_method,
@@ -958,8 +970,8 @@
     } else if (kIsDebugBuild) {
       // Check that the class is still in the classes table.
       ReaderMutexLock mu(Thread::Current(), *Locks::classlinker_classes_lock_);
-      CHECK(class_linker->ClassInClassTable(declaring_class)) << "Class "
-          << Class::PrettyClass(declaring_class) << " not in class linker table";
+      CHECK(class_linker->ClassInClassTable(referencing_class)) << "Class "
+          << Class::PrettyClass(referencing_class) << " not in class linker table";
     }
   }
   // Prune fields and make the contents of the field array deterministic.
diff --git a/compiler/linker/mips/relative_patcher_mips.cc b/compiler/linker/mips/relative_patcher_mips.cc
index d99d237..3bec30f 100644
--- a/compiler/linker/mips/relative_patcher_mips.cc
+++ b/compiler/linker/mips/relative_patcher_mips.cc
@@ -49,43 +49,27 @@
                                                    uint32_t target_offset) {
   uint32_t anchor_literal_offset = patch.PcInsnOffset();
   uint32_t literal_offset = patch.LiteralOffset();
-  uint32_t literal_low_offset;
+  bool high_patch = ((*code)[literal_offset + 0] == 0x34) && ((*code)[literal_offset + 1] == 0x12);
 
-  // Perform basic sanity checks and initialize `literal_low_offset` to point
-  // to the instruction containing the 16 least significant bits of the
-  // relative address.
-  if (is_r6) {
-    DCHECK_GE(code->size(), 8u);
-    DCHECK_LE(literal_offset, code->size() - 8u);
-    DCHECK_EQ(literal_offset, anchor_literal_offset);
-    // AUIPC reg, offset_high
-    DCHECK_EQ((*code)[literal_offset + 0], 0x34);
-    DCHECK_EQ((*code)[literal_offset + 1], 0x12);
-    DCHECK_EQ(((*code)[literal_offset + 2] & 0x1F), 0x1E);
-    DCHECK_EQ(((*code)[literal_offset + 3] & 0xFC), 0xEC);
-    // instr reg(s), offset_low
-    DCHECK_EQ((*code)[literal_offset + 4], 0x78);
-    DCHECK_EQ((*code)[literal_offset + 5], 0x56);
-    literal_low_offset = literal_offset + 4;
+  // Perform basic sanity checks.
+  if (high_patch) {
+    if (is_r6) {
+      // auipc reg, offset_high
+      DCHECK_EQ(((*code)[literal_offset + 2] & 0x1F), 0x1E);
+      DCHECK_EQ(((*code)[literal_offset + 3] & 0xFC), 0xEC);
+    } else {
+      // lui reg, offset_high
+      DCHECK_EQ(((*code)[literal_offset + 2] & 0xE0), 0x00);
+      DCHECK_EQ((*code)[literal_offset + 3], 0x3C);
+      // addu reg, reg, reg2
+      DCHECK_EQ((*code)[literal_offset + 4], 0x21);
+      DCHECK_EQ(((*code)[literal_offset + 5] & 0x07), 0x00);
+      DCHECK_EQ(((*code)[literal_offset + 7] & 0xFC), 0x00);
+    }
   } else {
-    DCHECK_GE(code->size(), 16u);
-    DCHECK_LE(literal_offset, code->size() - 12u);
-    DCHECK_GE(literal_offset, 4u);
-    // The NAL instruction does not precede immediately as the PC+0
-    // comes from HMipsComputeBaseMethodAddress.
-    // LUI reg, offset_high
-    DCHECK_EQ((*code)[literal_offset + 0], 0x34);
-    DCHECK_EQ((*code)[literal_offset + 1], 0x12);
-    DCHECK_EQ(((*code)[literal_offset + 2] & 0xE0), 0x00);
-    DCHECK_EQ((*code)[literal_offset + 3], 0x3C);
-    // ADDU reg, reg, reg2
-    DCHECK_EQ((*code)[literal_offset + 4], 0x21);
-    DCHECK_EQ(((*code)[literal_offset + 5] & 0x07), 0x00);
-    DCHECK_EQ(((*code)[literal_offset + 7] & 0xFC), 0x00);
     // instr reg(s), offset_low
-    DCHECK_EQ((*code)[literal_offset + 8], 0x78);
-    DCHECK_EQ((*code)[literal_offset + 9], 0x56);
-    literal_low_offset = literal_offset + 8;
+    CHECK_EQ((*code)[literal_offset + 0], 0x78);
+    CHECK_EQ((*code)[literal_offset + 1], 0x56);
   }
 
   // Apply patch.
@@ -93,12 +77,15 @@
   uint32_t diff = target_offset - anchor_offset;
   diff += (diff & 0x8000) << 1;  // Account for sign extension in "instr reg(s), offset_low".
 
-  // LUI reg, offset_high / AUIPC reg, offset_high
-  (*code)[literal_offset + 0] = static_cast<uint8_t>(diff >> 16);
-  (*code)[literal_offset + 1] = static_cast<uint8_t>(diff >> 24);
-  // instr reg(s), offset_low
-  (*code)[literal_low_offset + 0] = static_cast<uint8_t>(diff >> 0);
-  (*code)[literal_low_offset + 1] = static_cast<uint8_t>(diff >> 8);
+  if (high_patch) {
+    // lui reg, offset_high / auipc reg, offset_high
+    (*code)[literal_offset + 0] = static_cast<uint8_t>(diff >> 16);
+    (*code)[literal_offset + 1] = static_cast<uint8_t>(diff >> 24);
+  } else {
+    // instr reg(s), offset_low
+    (*code)[literal_offset + 0] = static_cast<uint8_t>(diff >> 0);
+    (*code)[literal_offset + 1] = static_cast<uint8_t>(diff >> 8);
+  }
 }
 
 void MipsRelativePatcher::PatchBakerReadBarrierBranch(std::vector<uint8_t>* code ATTRIBUTE_UNUSED,
diff --git a/compiler/linker/mips/relative_patcher_mips32r6_test.cc b/compiler/linker/mips/relative_patcher_mips32r6_test.cc
index 63ad8a5..d1a75e2 100644
--- a/compiler/linker/mips/relative_patcher_mips32r6_test.cc
+++ b/compiler/linker/mips/relative_patcher_mips32r6_test.cc
@@ -26,7 +26,9 @@
 
  protected:
   static const uint8_t kUnpatchedPcRelativeRawCode[];
-  static const uint32_t kLiteralOffset;
+  static const uint32_t kLiteralOffsetHigh;
+  static const uint32_t kLiteralOffsetLow1;
+  static const uint32_t kLiteralOffsetLow2;
   static const uint32_t kAnchorOffset;
   static const ArrayRef<const uint8_t> kUnpatchedPcRelativeCode;
 
@@ -44,9 +46,11 @@
 const uint8_t Mips32r6RelativePatcherTest::kUnpatchedPcRelativeRawCode[] = {
     0x34, 0x12, 0x5E, 0xEE,  // auipc s2, high(diff); placeholder = 0x1234
     0x78, 0x56, 0x52, 0x26,  // addiu s2, s2, low(diff); placeholder = 0x5678
+    0x78, 0x56, 0x52, 0x8E,  // lw    s2, (low(diff))(s2) ; placeholder = 0x5678
 };
-const uint32_t Mips32r6RelativePatcherTest::kLiteralOffset = 0;  // At auipc (where
-                                                                 // patching starts).
+const uint32_t Mips32r6RelativePatcherTest::kLiteralOffsetHigh = 0;  // At auipc.
+const uint32_t Mips32r6RelativePatcherTest::kLiteralOffsetLow1 = 4;  // At addiu.
+const uint32_t Mips32r6RelativePatcherTest::kLiteralOffsetLow2 = 8;  // At lw.
 const uint32_t Mips32r6RelativePatcherTest::kAnchorOffset = 0;  // At auipc (where PC+0 points).
 const ArrayRef<const uint8_t> Mips32r6RelativePatcherTest::kUnpatchedPcRelativeCode(
     kUnpatchedPcRelativeRawCode);
@@ -60,11 +64,12 @@
   ASSERT_TRUE(result.first);
 
   uint32_t diff = target_offset - (result.second + kAnchorOffset);
-  diff += (diff & 0x8000) << 1;  // Account for sign extension in addiu.
+  diff += (diff & 0x8000) << 1;  // Account for sign extension in addiu/lw.
 
   const uint8_t expected_code[] = {
       static_cast<uint8_t>(diff >> 16), static_cast<uint8_t>(diff >> 24), 0x5E, 0xEE,
       static_cast<uint8_t>(diff), static_cast<uint8_t>(diff >> 8), 0x52, 0x26,
+      static_cast<uint8_t>(diff), static_cast<uint8_t>(diff >> 8), 0x52, 0x8E,
   };
   EXPECT_TRUE(CheckLinkedMethod(MethodRef(1u), ArrayRef<const uint8_t>(expected_code)));
 }
@@ -75,7 +80,9 @@
   string_index_to_offset_map_.Put(kStringIndex, string_entry_offset);
   bss_begin_ = bss_begin;
   LinkerPatch patches[] = {
-      LinkerPatch::StringBssEntryPatch(kLiteralOffset, nullptr, kAnchorOffset, kStringIndex)
+      LinkerPatch::StringBssEntryPatch(kLiteralOffsetHigh, nullptr, kAnchorOffset, kStringIndex),
+      LinkerPatch::StringBssEntryPatch(kLiteralOffsetLow1, nullptr, kAnchorOffset, kStringIndex),
+      LinkerPatch::StringBssEntryPatch(kLiteralOffsetLow2, nullptr, kAnchorOffset, kStringIndex)
   };
   CheckPcRelativePatch(ArrayRef<const LinkerPatch>(patches), bss_begin_ + string_entry_offset);
 }
@@ -84,7 +91,9 @@
   constexpr uint32_t kStringIndex = 1u;
   string_index_to_offset_map_.Put(kStringIndex, string_offset);
   LinkerPatch patches[] = {
-      LinkerPatch::RelativeStringPatch(kLiteralOffset, nullptr, kAnchorOffset, kStringIndex)
+      LinkerPatch::RelativeStringPatch(kLiteralOffsetHigh, nullptr, kAnchorOffset, kStringIndex),
+      LinkerPatch::RelativeStringPatch(kLiteralOffsetLow1, nullptr, kAnchorOffset, kStringIndex),
+      LinkerPatch::RelativeStringPatch(kLiteralOffsetLow2, nullptr, kAnchorOffset, kStringIndex)
   };
   CheckPcRelativePatch(ArrayRef<const LinkerPatch>(patches), string_offset);
 }
diff --git a/compiler/linker/mips/relative_patcher_mips_test.cc b/compiler/linker/mips/relative_patcher_mips_test.cc
index 49af7c6..2f7a075 100644
--- a/compiler/linker/mips/relative_patcher_mips_test.cc
+++ b/compiler/linker/mips/relative_patcher_mips_test.cc
@@ -26,7 +26,9 @@
 
  protected:
   static const uint8_t kUnpatchedPcRelativeRawCode[];
-  static const uint32_t kLiteralOffset;
+  static const uint32_t kLiteralOffsetHigh;
+  static const uint32_t kLiteralOffsetLow1;
+  static const uint32_t kLiteralOffsetLow2;
   static const uint32_t kAnchorOffset;
   static const ArrayRef<const uint8_t> kUnpatchedPcRelativeCode;
 
@@ -46,8 +48,11 @@
     0x34, 0x12, 0x12, 0x3C,  // lui   s2, high(diff); placeholder = 0x1234
     0x21, 0x90, 0x5F, 0x02,  // addu  s2, s2, ra
     0x78, 0x56, 0x52, 0x26,  // addiu s2, s2, low(diff); placeholder = 0x5678
+    0x78, 0x56, 0x52, 0x8E,  // lw    s2, (low(diff))(s2) ; placeholder = 0x5678
 };
-const uint32_t MipsRelativePatcherTest::kLiteralOffset = 4;  // At lui (where patching starts).
+const uint32_t MipsRelativePatcherTest::kLiteralOffsetHigh = 4;  // At lui.
+const uint32_t MipsRelativePatcherTest::kLiteralOffsetLow1 = 12;  // At addiu.
+const uint32_t MipsRelativePatcherTest::kLiteralOffsetLow2 = 16;  // At lw.
 const uint32_t MipsRelativePatcherTest::kAnchorOffset = 8;  // At addu (where PC+0 points).
 const ArrayRef<const uint8_t> MipsRelativePatcherTest::kUnpatchedPcRelativeCode(
     kUnpatchedPcRelativeRawCode);
@@ -61,13 +66,14 @@
   ASSERT_TRUE(result.first);
 
   uint32_t diff = target_offset - (result.second + kAnchorOffset);
-  diff += (diff & 0x8000) << 1;  // Account for sign extension in addiu.
+  diff += (diff & 0x8000) << 1;  // Account for sign extension in addiu/lw.
 
   const uint8_t expected_code[] = {
       0x00, 0x00, 0x10, 0x04,
       static_cast<uint8_t>(diff >> 16), static_cast<uint8_t>(diff >> 24), 0x12, 0x3C,
       0x21, 0x90, 0x5F, 0x02,
       static_cast<uint8_t>(diff), static_cast<uint8_t>(diff >> 8), 0x52, 0x26,
+      static_cast<uint8_t>(diff), static_cast<uint8_t>(diff >> 8), 0x52, 0x8E,
   };
   EXPECT_TRUE(CheckLinkedMethod(MethodRef(1u), ArrayRef<const uint8_t>(expected_code)));
 }
@@ -78,7 +84,9 @@
   string_index_to_offset_map_.Put(kStringIndex, string_entry_offset);
   bss_begin_ = bss_begin;
   LinkerPatch patches[] = {
-      LinkerPatch::StringBssEntryPatch(kLiteralOffset, nullptr, kAnchorOffset, kStringIndex)
+      LinkerPatch::StringBssEntryPatch(kLiteralOffsetHigh, nullptr, kAnchorOffset, kStringIndex),
+      LinkerPatch::StringBssEntryPatch(kLiteralOffsetLow1, nullptr, kAnchorOffset, kStringIndex),
+      LinkerPatch::StringBssEntryPatch(kLiteralOffsetLow2, nullptr, kAnchorOffset, kStringIndex)
   };
   CheckPcRelativePatch(ArrayRef<const LinkerPatch>(patches), bss_begin_ + string_entry_offset);
 }
@@ -87,7 +95,9 @@
   constexpr uint32_t kStringIndex = 1u;
   string_index_to_offset_map_.Put(kStringIndex, string_offset);
   LinkerPatch patches[] = {
-      LinkerPatch::RelativeStringPatch(kLiteralOffset, nullptr, kAnchorOffset, kStringIndex)
+      LinkerPatch::RelativeStringPatch(kLiteralOffsetHigh, nullptr, kAnchorOffset, kStringIndex),
+      LinkerPatch::RelativeStringPatch(kLiteralOffsetLow1, nullptr, kAnchorOffset, kStringIndex),
+      LinkerPatch::RelativeStringPatch(kLiteralOffsetLow2, nullptr, kAnchorOffset, kStringIndex)
   };
   CheckPcRelativePatch(ArrayRef<const LinkerPatch>(patches), string_offset);
 }
diff --git a/compiler/linker/mips64/relative_patcher_mips64.cc b/compiler/linker/mips64/relative_patcher_mips64.cc
index 3488d6d..d9f4758 100644
--- a/compiler/linker/mips64/relative_patcher_mips64.cc
+++ b/compiler/linker/mips64/relative_patcher_mips64.cc
@@ -36,38 +36,11 @@
   return offset;  // No thunks added; no limit on relative call distance.
 }
 
-void Mips64RelativePatcher::PatchCall(std::vector<uint8_t>* code,
-                                      uint32_t literal_offset,
-                                      uint32_t patch_offset,
-                                      uint32_t target_offset) {
-  // Basic sanity checks.
-  DCHECK_GE(code->size(), 8u);
-  DCHECK_LE(literal_offset, code->size() - 8u);
-  // auipc reg, offset_high
-  DCHECK_EQ((*code)[literal_offset + 0], 0x34);
-  DCHECK_EQ((*code)[literal_offset + 1], 0x12);
-  DCHECK_EQ(((*code)[literal_offset + 2] & 0x1F), 0x1E);
-  DCHECK_EQ(((*code)[literal_offset + 3] & 0xFC), 0xEC);
-  // jialc reg, offset_low
-  DCHECK_EQ((*code)[literal_offset + 4], 0x78);
-  DCHECK_EQ((*code)[literal_offset + 5], 0x56);
-  DCHECK_EQ(((*code)[literal_offset + 6] & 0xE0), 0x00);
-  DCHECK_EQ((*code)[literal_offset + 7], 0xF8);
-
-  // Apply patch.
-  uint32_t diff = target_offset - patch_offset;
-  // Note that a combination of auipc with an instruction that adds a sign-extended
-  // 16-bit immediate operand (e.g. jialc) provides a PC-relative range of
-  // PC-0x80000000 to PC+0x7FFF7FFF on MIPS64, that is, short of 2GB on one end
-  // by 32KB.
-  diff += (diff & 0x8000) << 1;  // Account for sign extension in jialc.
-
-  // auipc reg, offset_high
-  (*code)[literal_offset + 0] = static_cast<uint8_t>(diff >> 16);
-  (*code)[literal_offset + 1] = static_cast<uint8_t>(diff >> 24);
-  // jialc reg, offset_low
-  (*code)[literal_offset + 4] = static_cast<uint8_t>(diff >> 0);
-  (*code)[literal_offset + 5] = static_cast<uint8_t>(diff >> 8);
+void Mips64RelativePatcher::PatchCall(std::vector<uint8_t>* code ATTRIBUTE_UNUSED,
+                                      uint32_t literal_offset ATTRIBUTE_UNUSED,
+                                      uint32_t patch_offset ATTRIBUTE_UNUSED,
+                                      uint32_t target_offset ATTRIBUTE_UNUSED) {
+  UNIMPLEMENTED(FATAL) << "PatchCall unimplemented on MIPS64";
 }
 
 void Mips64RelativePatcher::PatchPcRelativeReference(std::vector<uint8_t>* code,
@@ -76,19 +49,18 @@
                                                      uint32_t target_offset) {
   uint32_t anchor_literal_offset = patch.PcInsnOffset();
   uint32_t literal_offset = patch.LiteralOffset();
+  bool high_patch = ((*code)[literal_offset + 0] == 0x34) && ((*code)[literal_offset + 1] == 0x12);
 
-  // Basic sanity checks.
-  DCHECK_GE(code->size(), 8u);
-  DCHECK_LE(literal_offset, code->size() - 8u);
-  DCHECK_EQ(literal_offset, anchor_literal_offset);
-  // auipc reg, offset_high
-  DCHECK_EQ((*code)[literal_offset + 0], 0x34);
-  DCHECK_EQ((*code)[literal_offset + 1], 0x12);
-  DCHECK_EQ(((*code)[literal_offset + 2] & 0x1F), 0x1E);
-  DCHECK_EQ(((*code)[literal_offset + 3] & 0xFC), 0xEC);
-  // instr reg(s), offset_low
-  DCHECK_EQ((*code)[literal_offset + 4], 0x78);
-  DCHECK_EQ((*code)[literal_offset + 5], 0x56);
+  // Perform basic sanity checks.
+  if (high_patch) {
+    // auipc reg, offset_high
+    DCHECK_EQ(((*code)[literal_offset + 2] & 0x1F), 0x1E);
+    DCHECK_EQ(((*code)[literal_offset + 3] & 0xFC), 0xEC);
+  } else {
+    // instr reg(s), offset_low
+    CHECK_EQ((*code)[literal_offset + 0], 0x78);
+    CHECK_EQ((*code)[literal_offset + 1], 0x56);
+  }
 
   // Apply patch.
   uint32_t anchor_offset = patch_offset - literal_offset + anchor_literal_offset;
@@ -97,14 +69,17 @@
   // 16-bit immediate operand (e.g. ld) provides a PC-relative range of
   // PC-0x80000000 to PC+0x7FFF7FFF on MIPS64, that is, short of 2GB on one end
   // by 32KB.
-  diff += (diff & 0x8000) << 1;  // Account for sign extension in instruction following auipc.
+  diff += (diff & 0x8000) << 1;  // Account for sign extension in "instr reg(s), offset_low".
 
-  // auipc reg, offset_high
-  (*code)[literal_offset + 0] = static_cast<uint8_t>(diff >> 16);
-  (*code)[literal_offset + 1] = static_cast<uint8_t>(diff >> 24);
-  // instr reg(s), offset_low
-  (*code)[literal_offset + 4] = static_cast<uint8_t>(diff >> 0);
-  (*code)[literal_offset + 5] = static_cast<uint8_t>(diff >> 8);
+  if (high_patch) {
+    // auipc reg, offset_high
+    (*code)[literal_offset + 0] = static_cast<uint8_t>(diff >> 16);
+    (*code)[literal_offset + 1] = static_cast<uint8_t>(diff >> 24);
+  } else {
+    // instr reg(s), offset_low
+    (*code)[literal_offset + 0] = static_cast<uint8_t>(diff >> 0);
+    (*code)[literal_offset + 1] = static_cast<uint8_t>(diff >> 8);
+  }
 }
 
 void Mips64RelativePatcher::PatchBakerReadBarrierBranch(std::vector<uint8_t>* code ATTRIBUTE_UNUSED,
diff --git a/compiler/linker/mips64/relative_patcher_mips64_test.cc b/compiler/linker/mips64/relative_patcher_mips64_test.cc
index 9c9e24a..a5f494d 100644
--- a/compiler/linker/mips64/relative_patcher_mips64_test.cc
+++ b/compiler/linker/mips64/relative_patcher_mips64_test.cc
@@ -27,10 +27,11 @@
  protected:
   static const uint8_t kUnpatchedPcRelativeRawCode[];
   static const uint8_t kUnpatchedPcRelativeCallRawCode[];
-  static const uint32_t kLiteralOffset;
+  static const uint32_t kLiteralOffsetHigh;
+  static const uint32_t kLiteralOffsetLow1;
+  static const uint32_t kLiteralOffsetLow2;
   static const uint32_t kAnchorOffset;
   static const ArrayRef<const uint8_t> kUnpatchedPcRelativeCode;
-  static const ArrayRef<const uint8_t> kUnpatchedPcRelativeCallCode;
 
   uint32_t GetMethodOffset(uint32_t method_idx) {
     auto result = method_offset_map_.FindMethodOffset(MethodRef(method_idx));
@@ -44,19 +45,16 @@
 };
 
 const uint8_t Mips64RelativePatcherTest::kUnpatchedPcRelativeRawCode[] = {
-    0x34, 0x12, 0x5E, 0xEE,  // auipc s2, high(diff); placeholder = 0x1234
+    0x34, 0x12, 0x5E, 0xEE,  // auipc  s2, high(diff); placeholder = 0x1234
     0x78, 0x56, 0x52, 0x66,  // daddiu s2, s2, low(diff); placeholder = 0x5678
+    0x78, 0x56, 0x52, 0x9E,  // lwu    s2, (low(diff))(s2) ; placeholder = 0x5678
 };
-const uint8_t Mips64RelativePatcherTest::kUnpatchedPcRelativeCallRawCode[] = {
-    0x34, 0x12, 0x3E, 0xEC,  // auipc at, high(diff); placeholder = 0x1234
-    0x78, 0x56, 0x01, 0xF8,  // jialc at, low(diff); placeholder = 0x5678
-};
-const uint32_t Mips64RelativePatcherTest::kLiteralOffset = 0;  // At auipc (where patching starts).
+const uint32_t Mips64RelativePatcherTest::kLiteralOffsetHigh = 0;  // At auipc.
+const uint32_t Mips64RelativePatcherTest::kLiteralOffsetLow1 = 4;  // At daddiu.
+const uint32_t Mips64RelativePatcherTest::kLiteralOffsetLow2 = 8;  // At lwu.
 const uint32_t Mips64RelativePatcherTest::kAnchorOffset = 0;  // At auipc (where PC+0 points).
 const ArrayRef<const uint8_t> Mips64RelativePatcherTest::kUnpatchedPcRelativeCode(
     kUnpatchedPcRelativeRawCode);
-const ArrayRef<const uint8_t> Mips64RelativePatcherTest::kUnpatchedPcRelativeCallCode(
-    kUnpatchedPcRelativeCallRawCode);
 
 void Mips64RelativePatcherTest::CheckPcRelativePatch(const ArrayRef<const LinkerPatch>& patches,
                                                      uint32_t target_offset) {
@@ -67,11 +65,12 @@
   ASSERT_TRUE(result.first);
 
   uint32_t diff = target_offset - (result.second + kAnchorOffset);
-  diff += (diff & 0x8000) << 1;  // Account for sign extension in instruction following auipc.
+  diff += (diff & 0x8000) << 1;  // Account for sign extension in daddiu/lwu.
 
   const uint8_t expected_code[] = {
       static_cast<uint8_t>(diff >> 16), static_cast<uint8_t>(diff >> 24), 0x5E, 0xEE,
       static_cast<uint8_t>(diff), static_cast<uint8_t>(diff >> 8), 0x52, 0x66,
+      static_cast<uint8_t>(diff), static_cast<uint8_t>(diff >> 8), 0x52, 0x9E,
   };
   EXPECT_TRUE(CheckLinkedMethod(MethodRef(1u), ArrayRef<const uint8_t>(expected_code)));
 }
@@ -82,7 +81,9 @@
   string_index_to_offset_map_.Put(kStringIndex, string_entry_offset);
   bss_begin_ = bss_begin;
   LinkerPatch patches[] = {
-      LinkerPatch::StringBssEntryPatch(kLiteralOffset, nullptr, kAnchorOffset, kStringIndex)
+      LinkerPatch::StringBssEntryPatch(kLiteralOffsetHigh, nullptr, kAnchorOffset, kStringIndex),
+      LinkerPatch::StringBssEntryPatch(kLiteralOffsetLow1, nullptr, kAnchorOffset, kStringIndex),
+      LinkerPatch::StringBssEntryPatch(kLiteralOffsetLow2, nullptr, kAnchorOffset, kStringIndex)
   };
   CheckPcRelativePatch(ArrayRef<const LinkerPatch>(patches), bss_begin_ + string_entry_offset);
 }
@@ -91,38 +92,5 @@
   TestStringBssEntry(/* bss_begin */ 0x12345678, /* string_entry_offset */ 0x1234);
 }
 
-TEST_F(Mips64RelativePatcherTest, CallOther) {
-  LinkerPatch method1_patches[] = {
-      LinkerPatch::RelativeCodePatch(kLiteralOffset, nullptr, 2u),
-  };
-  AddCompiledMethod(MethodRef(1u),
-                    kUnpatchedPcRelativeCallCode,
-                    ArrayRef<const LinkerPatch>(method1_patches));
-  LinkerPatch method2_patches[] = {
-      LinkerPatch::RelativeCodePatch(kLiteralOffset, nullptr, 1u),
-  };
-  AddCompiledMethod(MethodRef(2u),
-                    kUnpatchedPcRelativeCallCode,
-                    ArrayRef<const LinkerPatch>(method2_patches));
-  Link();
-
-  uint32_t method1_offset = GetMethodOffset(1u);
-  uint32_t method2_offset = GetMethodOffset(2u);
-  uint32_t diff_after = method2_offset - (method1_offset + kAnchorOffset /* PC adjustment */);
-  diff_after += (diff_after & 0x8000) << 1;  // Account for sign extension in jialc.
-  static const uint8_t method1_expected_code[] = {
-      static_cast<uint8_t>(diff_after >> 16), static_cast<uint8_t>(diff_after >> 24), 0x3E, 0xEC,
-      static_cast<uint8_t>(diff_after), static_cast<uint8_t>(diff_after >> 8), 0x01, 0xF8,
-  };
-  EXPECT_TRUE(CheckLinkedMethod(MethodRef(1u), ArrayRef<const uint8_t>(method1_expected_code)));
-  uint32_t diff_before = method1_offset - (method2_offset + kAnchorOffset /* PC adjustment */);
-  diff_before += (diff_before & 0x8000) << 1;  // Account for sign extension in jialc.
-  static const uint8_t method2_expected_code[] = {
-      static_cast<uint8_t>(diff_before >> 16), static_cast<uint8_t>(diff_before >> 24), 0x3E, 0xEC,
-      static_cast<uint8_t>(diff_before), static_cast<uint8_t>(diff_before >> 8), 0x01, 0xF8,
-  };
-  EXPECT_TRUE(CheckLinkedMethod(MethodRef(2u), ArrayRef<const uint8_t>(method2_expected_code)));
-}
-
 }  // namespace linker
 }  // namespace art
diff --git a/compiler/optimizing/code_generator_arm_vixl.h b/compiler/optimizing/code_generator_arm_vixl.h
index 805a3f4..ad3283a 100644
--- a/compiler/optimizing/code_generator_arm_vixl.h
+++ b/compiler/optimizing/code_generator_arm_vixl.h
@@ -408,6 +408,17 @@
   void GenerateDivRemConstantIntegral(HBinaryOperation* instruction);
   void HandleGoto(HInstruction* got, HBasicBlock* successor);
 
+  vixl::aarch32::MemOperand VecAddress(
+      HVecMemoryOperation* instruction,
+      // This function may acquire a scratch register.
+      vixl::aarch32::UseScratchRegisterScope* temps_scope,
+      /*out*/ vixl32::Register* scratch);
+  vixl::aarch32::AlignedMemOperand VecAddressUnaligned(
+      HVecMemoryOperation* instruction,
+      // This function may acquire a scratch register.
+      vixl::aarch32::UseScratchRegisterScope* temps_scope,
+      /*out*/ vixl32::Register* scratch);
+
   ArmVIXLAssembler* const assembler_;
   CodeGeneratorARMVIXL* const codegen_;
 
diff --git a/compiler/optimizing/code_generator_mips.cc b/compiler/optimizing/code_generator_mips.cc
index b39d412..4c4d97b 100644
--- a/compiler/optimizing/code_generator_mips.cc
+++ b/compiler/optimizing/code_generator_mips.cc
@@ -208,8 +208,13 @@
   LoadClassSlowPathMIPS(HLoadClass* cls,
                         HInstruction* at,
                         uint32_t dex_pc,
-                        bool do_clinit)
-      : SlowPathCodeMIPS(at), cls_(cls), dex_pc_(dex_pc), do_clinit_(do_clinit) {
+                        bool do_clinit,
+                        const CodeGeneratorMIPS::PcRelativePatchInfo* bss_info_high = nullptr)
+      : SlowPathCodeMIPS(at),
+        cls_(cls),
+        dex_pc_(dex_pc),
+        do_clinit_(do_clinit),
+        bss_info_high_(bss_info_high) {
     DCHECK(at->IsLoadClass() || at->IsClinitCheck());
   }
 
@@ -217,8 +222,7 @@
     LocationSummary* locations = instruction_->GetLocations();
     Location out = locations->Out();
     CodeGeneratorMIPS* mips_codegen = down_cast<CodeGeneratorMIPS*>(codegen);
-    const bool isR6 = mips_codegen->GetInstructionSetFeatures().IsR6();
-    const bool r2_baker_or_no_read_barriers = !isR6 && (!kUseReadBarrier || kUseBakerReadBarrier);
+    const bool baker_or_no_read_barriers = (!kUseReadBarrier || kUseBakerReadBarrier);
     InvokeRuntimeCallingConvention calling_convention;
     DCHECK_EQ(instruction_->IsLoadClass(), cls_ == instruction_);
     const bool is_load_class_bss_entry =
@@ -228,7 +232,7 @@
 
     // For HLoadClass/kBssEntry/kSaveEverything, make sure we preserve the address of the entry.
     Register entry_address = kNoRegister;
-    if (is_load_class_bss_entry && r2_baker_or_no_read_barriers) {
+    if (is_load_class_bss_entry && baker_or_no_read_barriers) {
       Register temp = locations->GetTemp(0).AsRegister<Register>();
       bool temp_is_a0 = (temp == calling_convention.GetRegisterAt(0));
       // In the unlucky case that `temp` is A0, we preserve the address in `out` across the
@@ -252,9 +256,18 @@
     }
 
     // For HLoadClass/kBssEntry, store the resolved class to the BSS entry.
-    if (is_load_class_bss_entry && r2_baker_or_no_read_barriers) {
+    if (is_load_class_bss_entry && baker_or_no_read_barriers) {
       // The class entry address was preserved in `entry_address` thanks to kSaveEverything.
-      __ StoreToOffset(kStoreWord, calling_convention.GetRegisterAt(0), entry_address, 0);
+      DCHECK(bss_info_high_);
+      CodeGeneratorMIPS::PcRelativePatchInfo* info_low =
+          mips_codegen->NewTypeBssEntryPatch(cls_->GetDexFile(), type_index, bss_info_high_);
+      bool reordering = __ SetReorder(false);
+      __ Bind(&info_low->label);
+      __ StoreToOffset(kStoreWord,
+                       calling_convention.GetRegisterAt(0),
+                       entry_address,
+                       /* placeholder */ 0x5678);
+      __ SetReorder(reordering);
     }
 
     // Move the class to the desired location.
@@ -268,14 +281,17 @@
     RestoreLiveRegisters(codegen, locations);
 
     // For HLoadClass/kBssEntry, store the resolved class to the BSS entry.
-    if (is_load_class_bss_entry && !r2_baker_or_no_read_barriers) {
-      // For non-Baker read barriers (or on R6), we need to re-calculate the address of
+    if (is_load_class_bss_entry && !baker_or_no_read_barriers) {
+      // For non-Baker read barriers we need to re-calculate the address of
       // the class entry.
+      const bool isR6 = mips_codegen->GetInstructionSetFeatures().IsR6();
       Register base = isR6 ? ZERO : locations->InAt(0).AsRegister<Register>();
-      CodeGeneratorMIPS::PcRelativePatchInfo* info =
+      CodeGeneratorMIPS::PcRelativePatchInfo* info_high =
           mips_codegen->NewTypeBssEntryPatch(cls_->GetDexFile(), type_index);
+      CodeGeneratorMIPS::PcRelativePatchInfo* info_low =
+          mips_codegen->NewTypeBssEntryPatch(cls_->GetDexFile(), type_index, info_high);
       bool reordering = __ SetReorder(false);
-      mips_codegen->EmitPcRelativeAddressPlaceholderHigh(info, TMP, base);
+      mips_codegen->EmitPcRelativeAddressPlaceholderHigh(info_high, TMP, base, info_low);
       __ StoreToOffset(kStoreWord, out.AsRegister<Register>(), TMP, /* placeholder */ 0x5678);
       __ SetReorder(reordering);
     }
@@ -294,12 +310,17 @@
   // Whether to initialize the class.
   const bool do_clinit_;
 
+  // Pointer to the high half PC-relative patch info for HLoadClass/kBssEntry.
+  const CodeGeneratorMIPS::PcRelativePatchInfo* bss_info_high_;
+
   DISALLOW_COPY_AND_ASSIGN(LoadClassSlowPathMIPS);
 };
 
 class LoadStringSlowPathMIPS : public SlowPathCodeMIPS {
  public:
-  explicit LoadStringSlowPathMIPS(HLoadString* instruction) : SlowPathCodeMIPS(instruction) {}
+  explicit LoadStringSlowPathMIPS(HLoadString* instruction,
+                                  const CodeGeneratorMIPS::PcRelativePatchInfo* bss_info_high)
+      : SlowPathCodeMIPS(instruction), bss_info_high_(bss_info_high) {}
 
   void EmitNativeCode(CodeGenerator* codegen) OVERRIDE {
     DCHECK(instruction_->IsLoadString());
@@ -310,15 +331,14 @@
     const dex::StringIndex string_index = load->GetStringIndex();
     Register out = locations->Out().AsRegister<Register>();
     CodeGeneratorMIPS* mips_codegen = down_cast<CodeGeneratorMIPS*>(codegen);
-    const bool isR6 = mips_codegen->GetInstructionSetFeatures().IsR6();
-    const bool r2_baker_or_no_read_barriers = !isR6 && (!kUseReadBarrier || kUseBakerReadBarrier);
+    const bool baker_or_no_read_barriers = (!kUseReadBarrier || kUseBakerReadBarrier);
     InvokeRuntimeCallingConvention calling_convention;
     __ Bind(GetEntryLabel());
     SaveLiveRegisters(codegen, locations);
 
     // For HLoadString/kBssEntry/kSaveEverything, make sure we preserve the address of the entry.
     Register entry_address = kNoRegister;
-    if (r2_baker_or_no_read_barriers) {
+    if (baker_or_no_read_barriers) {
       Register temp = locations->GetTemp(0).AsRegister<Register>();
       bool temp_is_a0 = (temp == calling_convention.GetRegisterAt(0));
       // In the unlucky case that `temp` is A0, we preserve the address in `out` across the
@@ -335,9 +355,18 @@
     CheckEntrypointTypes<kQuickResolveString, void*, uint32_t>();
 
     // Store the resolved string to the BSS entry.
-    if (r2_baker_or_no_read_barriers) {
+    if (baker_or_no_read_barriers) {
       // The string entry address was preserved in `entry_address` thanks to kSaveEverything.
-      __ StoreToOffset(kStoreWord, calling_convention.GetRegisterAt(0), entry_address, 0);
+      DCHECK(bss_info_high_);
+      CodeGeneratorMIPS::PcRelativePatchInfo* info_low =
+          mips_codegen->NewPcRelativeStringPatch(load->GetDexFile(), string_index, bss_info_high_);
+      bool reordering = __ SetReorder(false);
+      __ Bind(&info_low->label);
+      __ StoreToOffset(kStoreWord,
+                       calling_convention.GetRegisterAt(0),
+                       entry_address,
+                       /* placeholder */ 0x5678);
+      __ SetReorder(reordering);
     }
 
     Primitive::Type type = instruction_->GetType();
@@ -347,14 +376,17 @@
     RestoreLiveRegisters(codegen, locations);
 
     // Store the resolved string to the BSS entry.
-    if (!r2_baker_or_no_read_barriers) {
-      // For non-Baker read barriers (or on R6), we need to re-calculate the address of
+    if (!baker_or_no_read_barriers) {
+      // For non-Baker read barriers we need to re-calculate the address of
       // the string entry.
+      const bool isR6 = mips_codegen->GetInstructionSetFeatures().IsR6();
       Register base = isR6 ? ZERO : locations->InAt(0).AsRegister<Register>();
-      CodeGeneratorMIPS::PcRelativePatchInfo* info =
+      CodeGeneratorMIPS::PcRelativePatchInfo* info_high =
           mips_codegen->NewPcRelativeStringPatch(load->GetDexFile(), string_index);
+      CodeGeneratorMIPS::PcRelativePatchInfo* info_low =
+          mips_codegen->NewPcRelativeStringPatch(load->GetDexFile(), string_index, info_high);
       bool reordering = __ SetReorder(false);
-      mips_codegen->EmitPcRelativeAddressPlaceholderHigh(info, TMP, base);
+      mips_codegen->EmitPcRelativeAddressPlaceholderHigh(info_high, TMP, base, info_low);
       __ StoreToOffset(kStoreWord, out, TMP, /* placeholder */ 0x5678);
       __ SetReorder(reordering);
     }
@@ -364,6 +396,9 @@
   const char* GetDescription() const OVERRIDE { return "LoadStringSlowPathMIPS"; }
 
  private:
+  // Pointer to the high half PC-relative patch info.
+  const CodeGeneratorMIPS::PcRelativePatchInfo* bss_info_high_;
+
   DISALLOW_COPY_AND_ASSIGN(LoadStringSlowPathMIPS);
 };
 
@@ -950,7 +985,9 @@
                                 this);
     CheckEntrypointTypes<
         kQuickReadBarrierSlow, mirror::Object*, mirror::Object*, mirror::Object*, uint32_t>();
-    mips_codegen->Move32(out_, calling_convention.GetReturnLocation(Primitive::kPrimNot));
+    mips_codegen->MoveLocation(out_,
+                               calling_convention.GetReturnLocation(Primitive::kPrimNot),
+                               Primitive::kPrimNot);
 
     RestoreLiveRegisters(codegen, locations);
     __ B(GetExitLabel());
@@ -1013,13 +1050,17 @@
 
     InvokeRuntimeCallingConvention calling_convention;
     CodeGeneratorMIPS* mips_codegen = down_cast<CodeGeneratorMIPS*>(codegen);
-    mips_codegen->Move32(Location::RegisterLocation(calling_convention.GetRegisterAt(0)), root_);
+    mips_codegen->MoveLocation(Location::RegisterLocation(calling_convention.GetRegisterAt(0)),
+                               root_,
+                               Primitive::kPrimNot);
     mips_codegen->InvokeRuntime(kQuickReadBarrierForRootSlow,
                                 instruction_,
                                 instruction_->GetDexPc(),
                                 this);
     CheckEntrypointTypes<kQuickReadBarrierForRootSlow, mirror::Object*, GcRoot<mirror::Object>*>();
-    mips_codegen->Move32(out_, calling_convention.GetReturnLocation(Primitive::kPrimNot));
+    mips_codegen->MoveLocation(out_,
+                               calling_convention.GetReturnLocation(Primitive::kPrimNot),
+                               Primitive::kPrimNot);
 
     RestoreLiveRegisters(codegen, locations);
     __ B(GetExitLabel());
@@ -1407,106 +1448,92 @@
   __ Bind(GetLabelOf(block));
 }
 
-void CodeGeneratorMIPS::MoveLocation(Location dst, Location src, Primitive::Type dst_type) {
-  if (src.Equals(dst)) {
-    return;
-  }
-
-  if (src.IsConstant()) {
-    MoveConstant(dst, src.GetConstant());
-  } else {
-    if (Primitive::Is64BitType(dst_type)) {
-      Move64(dst, src);
-    } else {
-      Move32(dst, src);
-    }
-  }
-}
-
-void CodeGeneratorMIPS::Move32(Location destination, Location source) {
+void CodeGeneratorMIPS::MoveLocation(Location destination,
+                                     Location source,
+                                     Primitive::Type dst_type) {
   if (source.Equals(destination)) {
     return;
   }
 
-  if (destination.IsRegister()) {
-    if (source.IsRegister()) {
-      __ Move(destination.AsRegister<Register>(), source.AsRegister<Register>());
-    } else if (source.IsFpuRegister()) {
-      __ Mfc1(destination.AsRegister<Register>(), source.AsFpuRegister<FRegister>());
-    } else {
-      DCHECK(source.IsStackSlot()) << "Cannot move from " << source << " to " << destination;
+  if (source.IsConstant()) {
+    MoveConstant(destination, source.GetConstant());
+  } else {
+    if (destination.IsRegister()) {
+      if (source.IsRegister()) {
+        __ Move(destination.AsRegister<Register>(), source.AsRegister<Register>());
+      } else if (source.IsFpuRegister()) {
+        __ Mfc1(destination.AsRegister<Register>(), source.AsFpuRegister<FRegister>());
+      } else {
+        DCHECK(source.IsStackSlot()) << "Cannot move from " << source << " to " << destination;
       __ LoadFromOffset(kLoadWord, destination.AsRegister<Register>(), SP, source.GetStackIndex());
-    }
-  } else if (destination.IsFpuRegister()) {
-    if (source.IsRegister()) {
-      __ Mtc1(source.AsRegister<Register>(), destination.AsFpuRegister<FRegister>());
-    } else if (source.IsFpuRegister()) {
-      __ MovS(destination.AsFpuRegister<FRegister>(), source.AsFpuRegister<FRegister>());
+      }
+    } else if (destination.IsRegisterPair()) {
+      if (source.IsRegisterPair()) {
+        __ Move(destination.AsRegisterPairHigh<Register>(), source.AsRegisterPairHigh<Register>());
+        __ Move(destination.AsRegisterPairLow<Register>(), source.AsRegisterPairLow<Register>());
+      } else if (source.IsFpuRegister()) {
+        Register dst_high = destination.AsRegisterPairHigh<Register>();
+        Register dst_low =  destination.AsRegisterPairLow<Register>();
+        FRegister src = source.AsFpuRegister<FRegister>();
+        __ Mfc1(dst_low, src);
+        __ MoveFromFpuHigh(dst_high, src);
+      } else {
+        DCHECK(source.IsDoubleStackSlot()) << "Cannot move from " << source << " to " << destination;
+        int32_t off = source.GetStackIndex();
+        Register r = destination.AsRegisterPairLow<Register>();
+        __ LoadFromOffset(kLoadDoubleword, r, SP, off);
+      }
+    } else if (destination.IsFpuRegister()) {
+      if (source.IsRegister()) {
+        DCHECK(!Primitive::Is64BitType(dst_type));
+        __ Mtc1(source.AsRegister<Register>(), destination.AsFpuRegister<FRegister>());
+      } else if (source.IsRegisterPair()) {
+        DCHECK(Primitive::Is64BitType(dst_type));
+        FRegister dst = destination.AsFpuRegister<FRegister>();
+        Register src_high = source.AsRegisterPairHigh<Register>();
+        Register src_low = source.AsRegisterPairLow<Register>();
+        __ Mtc1(src_low, dst);
+        __ MoveToFpuHigh(src_high, dst);
+      } else if (source.IsFpuRegister()) {
+        if (Primitive::Is64BitType(dst_type)) {
+          __ MovD(destination.AsFpuRegister<FRegister>(), source.AsFpuRegister<FRegister>());
+        } else {
+          DCHECK_EQ(dst_type, Primitive::kPrimFloat);
+          __ MovS(destination.AsFpuRegister<FRegister>(), source.AsFpuRegister<FRegister>());
+        }
+      } else if (source.IsDoubleStackSlot()) {
+        DCHECK(Primitive::Is64BitType(dst_type));
+        __ LoadDFromOffset(destination.AsFpuRegister<FRegister>(), SP, source.GetStackIndex());
+      } else {
+        DCHECK(!Primitive::Is64BitType(dst_type));
+        DCHECK(source.IsStackSlot()) << "Cannot move from " << source << " to " << destination;
+        __ LoadSFromOffset(destination.AsFpuRegister<FRegister>(), SP, source.GetStackIndex());
+      }
+    } else if (destination.IsDoubleStackSlot()) {
+      int32_t dst_offset = destination.GetStackIndex();
+      if (source.IsRegisterPair()) {
+        __ StoreToOffset(kStoreDoubleword, source.AsRegisterPairLow<Register>(), SP, dst_offset);
+      } else if (source.IsFpuRegister()) {
+        __ StoreDToOffset(source.AsFpuRegister<FRegister>(), SP, dst_offset);
+      } else {
+        DCHECK(source.IsDoubleStackSlot()) << "Cannot move from " << source << " to " << destination;
+        __ LoadFromOffset(kLoadWord, TMP, SP, source.GetStackIndex());
+        __ StoreToOffset(kStoreWord, TMP, SP, dst_offset);
+        __ LoadFromOffset(kLoadWord, TMP, SP, source.GetStackIndex() + 4);
+        __ StoreToOffset(kStoreWord, TMP, SP, dst_offset + 4);
+      }
     } else {
-      DCHECK(source.IsStackSlot()) << "Cannot move from " << source << " to " << destination;
-      __ LoadSFromOffset(destination.AsFpuRegister<FRegister>(), SP, source.GetStackIndex());
-    }
-  } else {
-    DCHECK(destination.IsStackSlot()) << destination;
-    if (source.IsRegister()) {
-      __ StoreToOffset(kStoreWord, source.AsRegister<Register>(), SP, destination.GetStackIndex());
-    } else if (source.IsFpuRegister()) {
-      __ StoreSToOffset(source.AsFpuRegister<FRegister>(), SP, destination.GetStackIndex());
-    } else {
-      DCHECK(source.IsStackSlot()) << "Cannot move from " << source << " to " << destination;
-      __ LoadFromOffset(kLoadWord, TMP, SP, source.GetStackIndex());
-      __ StoreToOffset(kStoreWord, TMP, SP, destination.GetStackIndex());
-    }
-  }
-}
-
-void CodeGeneratorMIPS::Move64(Location destination, Location source) {
-  if (source.Equals(destination)) {
-    return;
-  }
-
-  if (destination.IsRegisterPair()) {
-    if (source.IsRegisterPair()) {
-      __ Move(destination.AsRegisterPairHigh<Register>(), source.AsRegisterPairHigh<Register>());
-      __ Move(destination.AsRegisterPairLow<Register>(), source.AsRegisterPairLow<Register>());
-    } else if (source.IsFpuRegister()) {
-      Register dst_high = destination.AsRegisterPairHigh<Register>();
-      Register dst_low =  destination.AsRegisterPairLow<Register>();
-      FRegister src = source.AsFpuRegister<FRegister>();
-      __ Mfc1(dst_low, src);
-      __ MoveFromFpuHigh(dst_high, src);
-    } else {
-      DCHECK(source.IsDoubleStackSlot()) << "Cannot move from " << source << " to " << destination;
-      int32_t off = source.GetStackIndex();
-      Register r = destination.AsRegisterPairLow<Register>();
-      __ LoadFromOffset(kLoadDoubleword, r, SP, off);
-    }
-  } else if (destination.IsFpuRegister()) {
-    if (source.IsRegisterPair()) {
-      FRegister dst = destination.AsFpuRegister<FRegister>();
-      Register src_high = source.AsRegisterPairHigh<Register>();
-      Register src_low = source.AsRegisterPairLow<Register>();
-      __ Mtc1(src_low, dst);
-      __ MoveToFpuHigh(src_high, dst);
-    } else if (source.IsFpuRegister()) {
-      __ MovD(destination.AsFpuRegister<FRegister>(), source.AsFpuRegister<FRegister>());
-    } else {
-      DCHECK(source.IsDoubleStackSlot()) << "Cannot move from " << source << " to " << destination;
-      __ LoadDFromOffset(destination.AsFpuRegister<FRegister>(), SP, source.GetStackIndex());
-    }
-  } else {
-    DCHECK(destination.IsDoubleStackSlot()) << destination;
-    int32_t off = destination.GetStackIndex();
-    if (source.IsRegisterPair()) {
-      __ StoreToOffset(kStoreDoubleword, source.AsRegisterPairLow<Register>(), SP, off);
-    } else if (source.IsFpuRegister()) {
-      __ StoreDToOffset(source.AsFpuRegister<FRegister>(), SP, off);
-    } else {
-      DCHECK(source.IsDoubleStackSlot()) << "Cannot move from " << source << " to " << destination;
-      __ LoadFromOffset(kLoadWord, TMP, SP, source.GetStackIndex());
-      __ StoreToOffset(kStoreWord, TMP, SP, off);
-      __ LoadFromOffset(kLoadWord, TMP, SP, source.GetStackIndex() + 4);
-      __ StoreToOffset(kStoreWord, TMP, SP, off + 4);
+      DCHECK(destination.IsStackSlot()) << destination;
+      int32_t dst_offset = destination.GetStackIndex();
+      if (source.IsRegister()) {
+        __ StoreToOffset(kStoreWord, source.AsRegister<Register>(), SP, dst_offset);
+      } else if (source.IsFpuRegister()) {
+        __ StoreSToOffset(source.AsFpuRegister<FRegister>(), SP, dst_offset);
+      } else {
+        DCHECK(source.IsStackSlot()) << "Cannot move from " << source << " to " << destination;
+        __ LoadFromOffset(kLoadWord, TMP, SP, source.GetStackIndex());
+        __ StoreToOffset(kStoreWord, TMP, SP, dst_offset);
+      }
     }
   }
 }
@@ -1584,14 +1611,15 @@
   for (const PcRelativePatchInfo& info : infos) {
     const DexFile& dex_file = info.target_dex_file;
     size_t offset_or_index = info.offset_or_index;
-    DCHECK(info.high_label.IsBound());
-    uint32_t high_offset = __ GetLabelLocation(&info.high_label);
+    DCHECK(info.label.IsBound());
+    uint32_t literal_offset = __ GetLabelLocation(&info.label);
     // On R2 we use HMipsComputeBaseMethodAddress and patch relative to
     // the assembler's base label used for PC-relative addressing.
-    uint32_t pc_rel_offset = info.pc_rel_label.IsBound()
-        ? __ GetLabelLocation(&info.pc_rel_label)
+    const PcRelativePatchInfo& info_high = info.patch_info_high ? *info.patch_info_high : info;
+    uint32_t pc_rel_offset = info_high.pc_rel_label.IsBound()
+        ? __ GetLabelLocation(&info_high.pc_rel_label)
         : __ GetPcRelBaseLabelLocation();
-    linker_patches->push_back(Factory(high_offset, &dex_file, pc_rel_offset, offset_or_index));
+    linker_patches->push_back(Factory(literal_offset, &dex_file, pc_rel_offset, offset_or_index));
   }
 }
 
@@ -1625,37 +1653,50 @@
 }
 
 CodeGeneratorMIPS::PcRelativePatchInfo* CodeGeneratorMIPS::NewPcRelativeMethodPatch(
-    MethodReference target_method) {
+    MethodReference target_method,
+    const PcRelativePatchInfo* info_high) {
   return NewPcRelativePatch(*target_method.dex_file,
                             target_method.dex_method_index,
+                            info_high,
                             &pc_relative_method_patches_);
 }
 
 CodeGeneratorMIPS::PcRelativePatchInfo* CodeGeneratorMIPS::NewMethodBssEntryPatch(
-    MethodReference target_method) {
+    MethodReference target_method,
+    const PcRelativePatchInfo* info_high) {
   return NewPcRelativePatch(*target_method.dex_file,
                             target_method.dex_method_index,
+                            info_high,
                             &method_bss_entry_patches_);
 }
 
 CodeGeneratorMIPS::PcRelativePatchInfo* CodeGeneratorMIPS::NewPcRelativeTypePatch(
-    const DexFile& dex_file, dex::TypeIndex type_index) {
-  return NewPcRelativePatch(dex_file, type_index.index_, &pc_relative_type_patches_);
+    const DexFile& dex_file,
+    dex::TypeIndex type_index,
+    const PcRelativePatchInfo* info_high) {
+  return NewPcRelativePatch(dex_file, type_index.index_, info_high, &pc_relative_type_patches_);
 }
 
 CodeGeneratorMIPS::PcRelativePatchInfo* CodeGeneratorMIPS::NewTypeBssEntryPatch(
-    const DexFile& dex_file, dex::TypeIndex type_index) {
-  return NewPcRelativePatch(dex_file, type_index.index_, &type_bss_entry_patches_);
+    const DexFile& dex_file,
+    dex::TypeIndex type_index,
+    const PcRelativePatchInfo* info_high) {
+  return NewPcRelativePatch(dex_file, type_index.index_, info_high, &type_bss_entry_patches_);
 }
 
 CodeGeneratorMIPS::PcRelativePatchInfo* CodeGeneratorMIPS::NewPcRelativeStringPatch(
-    const DexFile& dex_file, dex::StringIndex string_index) {
-  return NewPcRelativePatch(dex_file, string_index.index_, &pc_relative_string_patches_);
+    const DexFile& dex_file,
+    dex::StringIndex string_index,
+    const PcRelativePatchInfo* info_high) {
+  return NewPcRelativePatch(dex_file, string_index.index_, info_high, &pc_relative_string_patches_);
 }
 
 CodeGeneratorMIPS::PcRelativePatchInfo* CodeGeneratorMIPS::NewPcRelativePatch(
-    const DexFile& dex_file, uint32_t offset_or_index, ArenaDeque<PcRelativePatchInfo>* patches) {
-  patches->emplace_back(dex_file, offset_or_index);
+    const DexFile& dex_file,
+    uint32_t offset_or_index,
+    const PcRelativePatchInfo* info_high,
+    ArenaDeque<PcRelativePatchInfo>* patches) {
+  patches->emplace_back(dex_file, offset_or_index, info_high);
   return &patches->back();
 }
 
@@ -1669,14 +1710,16 @@
   return DeduplicateUint32Literal(dchecked_integral_cast<uint32_t>(address), &uint32_literals_);
 }
 
-void CodeGeneratorMIPS::EmitPcRelativeAddressPlaceholderHigh(PcRelativePatchInfo* info,
+void CodeGeneratorMIPS::EmitPcRelativeAddressPlaceholderHigh(PcRelativePatchInfo* info_high,
                                                              Register out,
-                                                             Register base) {
+                                                             Register base,
+                                                             PcRelativePatchInfo* info_low) {
+  DCHECK(!info_high->patch_info_high);
   DCHECK_NE(out, base);
   if (GetInstructionSetFeatures().IsR6()) {
     DCHECK_EQ(base, ZERO);
-    __ Bind(&info->high_label);
-    __ Bind(&info->pc_rel_label);
+    __ Bind(&info_high->label);
+    __ Bind(&info_high->pc_rel_label);
     // Add the high half of a 32-bit offset to PC.
     __ Auipc(out, /* placeholder */ 0x1234);
   } else {
@@ -1685,18 +1728,20 @@
       // Generate a dummy PC-relative call to obtain PC.
       __ Nal();
     }
-    __ Bind(&info->high_label);
+    __ Bind(&info_high->label);
     __ Lui(out, /* placeholder */ 0x1234);
     // If we emitted the NAL, bind the pc_rel_label, otherwise base is a register holding
     // the HMipsComputeBaseMethodAddress which has its own label stored in MipsAssembler.
     if (base == ZERO) {
-      __ Bind(&info->pc_rel_label);
+      __ Bind(&info_high->pc_rel_label);
     }
     // Add the high half of a 32-bit offset to PC.
     __ Addu(out, out, (base == ZERO) ? RA : base);
   }
-  // The immediately following instruction will add the sign-extended low half of the 32-bit
+  // A following instruction will add the sign-extended low half of the 32-bit
   // offset to `out` (e.g. lw, jialc, addiu).
+  DCHECK_EQ(info_low->patch_info_high, info_high);
+  __ Bind(&info_low->label);
 }
 
 CodeGeneratorMIPS::JitPatchInfo* CodeGeneratorMIPS::NewJitRootStringPatch(
@@ -2285,7 +2330,7 @@
       Register lhs_low = locations->InAt(0).AsRegisterPairLow<Register>();
       if (use_imm) {
           if (shift_value == 0) {
-            codegen_->Move64(locations->Out(), locations->InAt(0));
+            codegen_->MoveLocation(locations->Out(), locations->InAt(0), type);
           } else if (shift_value < kMipsBitsPerWord) {
             if (has_ins_rotr) {
               if (instr->IsShl()) {
@@ -7140,10 +7185,12 @@
       break;
     case HInvokeStaticOrDirect::MethodLoadKind::kBootImageLinkTimePcRelative: {
       DCHECK(GetCompilerOptions().IsBootImage());
-      PcRelativePatchInfo* info = NewPcRelativeMethodPatch(invoke->GetTargetMethod());
+      PcRelativePatchInfo* info_high = NewPcRelativeMethodPatch(invoke->GetTargetMethod());
+      PcRelativePatchInfo* info_low =
+          NewPcRelativeMethodPatch(invoke->GetTargetMethod(), info_high);
       bool reordering = __ SetReorder(false);
       Register temp_reg = temp.AsRegister<Register>();
-      EmitPcRelativeAddressPlaceholderHigh(info, TMP, base_reg);
+      EmitPcRelativeAddressPlaceholderHigh(info_high, TMP, base_reg, info_low);
       __ Addiu(temp_reg, TMP, /* placeholder */ 0x5678);
       __ SetReorder(reordering);
       break;
@@ -7152,11 +7199,13 @@
       __ LoadConst32(temp.AsRegister<Register>(), invoke->GetMethodAddress());
       break;
     case HInvokeStaticOrDirect::MethodLoadKind::kBssEntry: {
-      PcRelativePatchInfo* info = NewMethodBssEntryPatch(
+      PcRelativePatchInfo* info_high = NewMethodBssEntryPatch(
           MethodReference(&GetGraph()->GetDexFile(), invoke->GetDexMethodIndex()));
+      PcRelativePatchInfo* info_low = NewMethodBssEntryPatch(
+          MethodReference(&GetGraph()->GetDexFile(), invoke->GetDexMethodIndex()), info_high);
       Register temp_reg = temp.AsRegister<Register>();
       bool reordering = __ SetReorder(false);
-      EmitPcRelativeAddressPlaceholderHigh(info, TMP, base_reg);
+      EmitPcRelativeAddressPlaceholderHigh(info_high, TMP, base_reg, info_low);
       __ Lw(temp_reg, TMP, /* placeholder */ 0x5678);
       __ SetReorder(reordering);
       break;
@@ -7286,11 +7335,8 @@
   if (load_kind == HLoadClass::LoadKind::kBssEntry) {
     if (!kUseReadBarrier || kUseBakerReadBarrier) {
       // Rely on the type resolution or initialization and marking to save everything we need.
-      // Request a temp to hold the BSS entry location for the slow path on R2
-      // (no benefit for R6).
-      if (!isR6) {
-        locations->AddTemp(Location::RequiresRegister());
-      }
+      // Request a temp to hold the BSS entry location for the slow path.
+      locations->AddTemp(Location::RequiresRegister());
       RegisterSet caller_saves = RegisterSet::Empty();
       InvokeRuntimeCallingConvention calling_convention;
       caller_saves.Add(Location::RegisterLocation(calling_convention.GetRegisterAt(0)));
@@ -7336,6 +7382,7 @@
       ? kWithoutReadBarrier
       : kCompilerReadBarrierOption;
   bool generate_null_check = false;
+  CodeGeneratorMIPS::PcRelativePatchInfo* bss_info_high = nullptr;
   switch (load_kind) {
     case HLoadClass::LoadKind::kReferrersClass: {
       DCHECK(!cls->CanCallRuntime());
@@ -7351,10 +7398,15 @@
     case HLoadClass::LoadKind::kBootImageLinkTimePcRelative: {
       DCHECK(codegen_->GetCompilerOptions().IsBootImage());
       DCHECK_EQ(read_barrier_option, kWithoutReadBarrier);
-      CodeGeneratorMIPS::PcRelativePatchInfo* info =
+      CodeGeneratorMIPS::PcRelativePatchInfo* info_high =
           codegen_->NewPcRelativeTypePatch(cls->GetDexFile(), cls->GetTypeIndex());
+      CodeGeneratorMIPS::PcRelativePatchInfo* info_low =
+          codegen_->NewPcRelativeTypePatch(cls->GetDexFile(), cls->GetTypeIndex(), info_high);
       bool reordering = __ SetReorder(false);
-      codegen_->EmitPcRelativeAddressPlaceholderHigh(info, out, base_or_current_method_reg);
+      codegen_->EmitPcRelativeAddressPlaceholderHigh(info_high,
+                                                     out,
+                                                     base_or_current_method_reg,
+                                                     info_low);
       __ Addiu(out, out, /* placeholder */ 0x5678);
       __ SetReorder(reordering);
       break;
@@ -7370,24 +7422,18 @@
       break;
     }
     case HLoadClass::LoadKind::kBssEntry: {
-      CodeGeneratorMIPS::PcRelativePatchInfo* info =
-          codegen_->NewTypeBssEntryPatch(cls->GetDexFile(), cls->GetTypeIndex());
+      bss_info_high = codegen_->NewTypeBssEntryPatch(cls->GetDexFile(), cls->GetTypeIndex());
+      CodeGeneratorMIPS::PcRelativePatchInfo* info_low =
+          codegen_->NewTypeBssEntryPatch(cls->GetDexFile(), cls->GetTypeIndex(), bss_info_high);
       constexpr bool non_baker_read_barrier = kUseReadBarrier && !kUseBakerReadBarrier;
-      if (isR6 || non_baker_read_barrier) {
-        bool reordering = __ SetReorder(false);
-        codegen_->EmitPcRelativeAddressPlaceholderHigh(info, out, base_or_current_method_reg);
-        GenerateGcRootFieldLoad(cls, out_loc, out, /* placeholder */ 0x5678, read_barrier_option);
-        __ SetReorder(reordering);
-      } else {
-        // On R2 save the BSS entry address in a temporary register instead of
-        // recalculating it in the slow path.
-        Register temp = locations->GetTemp(0).AsRegister<Register>();
-        bool reordering = __ SetReorder(false);
-        codegen_->EmitPcRelativeAddressPlaceholderHigh(info, temp, base_or_current_method_reg);
-        __ Addiu(temp, temp, /* placeholder */ 0x5678);
-        __ SetReorder(reordering);
-        GenerateGcRootFieldLoad(cls, out_loc, temp, /* offset */ 0, read_barrier_option);
-      }
+      Register temp = non_baker_read_barrier ? out : locations->GetTemp(0).AsRegister<Register>();
+      bool reordering = __ SetReorder(false);
+      codegen_->EmitPcRelativeAddressPlaceholderHigh(bss_info_high,
+                                                     temp,
+                                                     base_or_current_method_reg,
+                                                     info_low);
+      GenerateGcRootFieldLoad(cls, out_loc, temp, /* placeholder */ 0x5678, read_barrier_option);
+      __ SetReorder(reordering);
       generate_null_check = true;
       break;
     }
@@ -7411,7 +7457,7 @@
   if (generate_null_check || cls->MustGenerateClinitCheck()) {
     DCHECK(cls->CanCallRuntime());
     SlowPathCodeMIPS* slow_path = new (GetGraph()->GetArena()) LoadClassSlowPathMIPS(
-        cls, cls, cls->GetDexPc(), cls->MustGenerateClinitCheck());
+        cls, cls, cls->GetDexPc(), cls->MustGenerateClinitCheck(), bss_info_high);
     codegen_->AddSlowPath(slow_path);
     if (generate_null_check) {
       __ Beqz(out, slow_path->GetEntryLabel());
@@ -7476,11 +7522,8 @@
     if (load_kind == HLoadString::LoadKind::kBssEntry) {
       if (!kUseReadBarrier || kUseBakerReadBarrier) {
         // Rely on the pResolveString and marking to save everything we need.
-        // Request a temp to hold the BSS entry location for the slow path on R2
-        // (no benefit for R6).
-        if (!isR6) {
-          locations->AddTemp(Location::RequiresRegister());
-        }
+        // Request a temp to hold the BSS entry location for the slow path.
+        locations->AddTemp(Location::RequiresRegister());
         RegisterSet caller_saves = RegisterSet::Empty();
         InvokeRuntimeCallingConvention calling_convention;
         caller_saves.Add(Location::RegisterLocation(calling_convention.GetRegisterAt(0)));
@@ -7516,10 +7559,15 @@
   switch (load_kind) {
     case HLoadString::LoadKind::kBootImageLinkTimePcRelative: {
       DCHECK(codegen_->GetCompilerOptions().IsBootImage());
-      CodeGeneratorMIPS::PcRelativePatchInfo* info =
+      CodeGeneratorMIPS::PcRelativePatchInfo* info_high =
           codegen_->NewPcRelativeStringPatch(load->GetDexFile(), load->GetStringIndex());
+      CodeGeneratorMIPS::PcRelativePatchInfo* info_low =
+          codegen_->NewPcRelativeStringPatch(load->GetDexFile(), load->GetStringIndex(), info_high);
       bool reordering = __ SetReorder(false);
-      codegen_->EmitPcRelativeAddressPlaceholderHigh(info, out, base_or_current_method_reg);
+      codegen_->EmitPcRelativeAddressPlaceholderHigh(info_high,
+                                                     out,
+                                                     base_or_current_method_reg,
+                                                     info_low);
       __ Addiu(out, out, /* placeholder */ 0x5678);
       __ SetReorder(reordering);
       return;  // No dex cache slow path.
@@ -7535,29 +7583,25 @@
     }
     case HLoadString::LoadKind::kBssEntry: {
       DCHECK(!codegen_->GetCompilerOptions().IsBootImage());
-      CodeGeneratorMIPS::PcRelativePatchInfo* info =
+      CodeGeneratorMIPS::PcRelativePatchInfo* info_high =
           codegen_->NewPcRelativeStringPatch(load->GetDexFile(), load->GetStringIndex());
+      CodeGeneratorMIPS::PcRelativePatchInfo* info_low =
+          codegen_->NewPcRelativeStringPatch(load->GetDexFile(), load->GetStringIndex(), info_high);
       constexpr bool non_baker_read_barrier = kUseReadBarrier && !kUseBakerReadBarrier;
-      if (isR6 || non_baker_read_barrier) {
-        bool reordering = __ SetReorder(false);
-        codegen_->EmitPcRelativeAddressPlaceholderHigh(info, out, base_or_current_method_reg);
-        GenerateGcRootFieldLoad(load,
-                                out_loc,
-                                out,
-                                /* placeholder */ 0x5678,
-                                kCompilerReadBarrierOption);
-        __ SetReorder(reordering);
-      } else {
-        // On R2 save the BSS entry address in a temporary register instead of
-        // recalculating it in the slow path.
-        Register temp = locations->GetTemp(0).AsRegister<Register>();
-        bool reordering = __ SetReorder(false);
-        codegen_->EmitPcRelativeAddressPlaceholderHigh(info, temp, base_or_current_method_reg);
-        __ Addiu(temp, temp, /* placeholder */ 0x5678);
-        __ SetReorder(reordering);
-        GenerateGcRootFieldLoad(load, out_loc, temp, /* offset */ 0, kCompilerReadBarrierOption);
-      }
-      SlowPathCodeMIPS* slow_path = new (GetGraph()->GetArena()) LoadStringSlowPathMIPS(load);
+      Register temp = non_baker_read_barrier ? out : locations->GetTemp(0).AsRegister<Register>();
+      bool reordering = __ SetReorder(false);
+      codegen_->EmitPcRelativeAddressPlaceholderHigh(info_high,
+                                                     temp,
+                                                     base_or_current_method_reg,
+                                                     info_low);
+      GenerateGcRootFieldLoad(load,
+                              out_loc,
+                              temp,
+                              /* placeholder */ 0x5678,
+                              kCompilerReadBarrierOption);
+      __ SetReorder(reordering);
+      SlowPathCodeMIPS* slow_path =
+          new (GetGraph()->GetArena()) LoadStringSlowPathMIPS(load, info_high);
       codegen_->AddSlowPath(slow_path);
       __ Beqz(out, slow_path->GetEntryLabel());
       __ Bind(slow_path->GetExitLabel());
diff --git a/compiler/optimizing/code_generator_mips.h b/compiler/optimizing/code_generator_mips.h
index e72e838d..c259ea3 100644
--- a/compiler/optimizing/code_generator_mips.h
+++ b/compiler/optimizing/code_generator_mips.h
@@ -368,8 +368,6 @@
 
   void Bind(HBasicBlock* block) OVERRIDE;
 
-  void Move32(Location destination, Location source);
-  void Move64(Location destination, Location source);
   void MoveConstant(Location location, HConstant* c);
 
   size_t GetWordSize() const OVERRIDE { return kMipsWordSize; }
@@ -568,31 +566,68 @@
 
   // The PcRelativePatchInfo is used for PC-relative addressing of dex cache arrays
   // and boot image strings. The only difference is the interpretation of the offset_or_index.
+  // The 16-bit halves of the 32-bit PC-relative offset are patched separately, necessitating
+  // two patches/infos. There can be more than two patches/infos if the instruction supplying
+  // the high half is shared with e.g. a slow path, while the low half is supplied by separate
+  // instructions, e.g.:
+  //     lui   r1, high       // patch
+  //     addu  r1, r1, rbase
+  //     lw    r2, low(r1)    // patch
+  //     beqz  r2, slow_path
+  //   back:
+  //     ...
+  //   slow_path:
+  //     ...
+  //     sw    r2, low(r1)    // patch
+  //     b     back
   struct PcRelativePatchInfo {
-    PcRelativePatchInfo(const DexFile& dex_file, uint32_t off_or_idx)
-        : target_dex_file(dex_file), offset_or_index(off_or_idx) { }
-    PcRelativePatchInfo(PcRelativePatchInfo&& other) = default;
+    PcRelativePatchInfo(const DexFile& dex_file,
+                        uint32_t off_or_idx,
+                        const PcRelativePatchInfo* info_high)
+        : target_dex_file(dex_file),
+          offset_or_index(off_or_idx),
+          label(),
+          pc_rel_label(),
+          patch_info_high(info_high) { }
 
     const DexFile& target_dex_file;
     // Either the dex cache array element offset or the string/type index.
     uint32_t offset_or_index;
-    // Label for the instruction loading the most significant half of the offset that's added to PC
-    // to form the base address (the least significant half is loaded with the instruction that
-    // follows).
-    MipsLabel high_label;
-    // Label for the instruction corresponding to PC+0.
+    // Label for the instruction to patch.
+    MipsLabel label;
+    // Label for the instruction corresponding to PC+0. Not bound or used in low half patches.
+    // Not bound in high half patches on R2 when using HMipsComputeBaseMethodAddress.
+    // Bound in high half patches on R2 when using the NAL instruction instead of
+    // HMipsComputeBaseMethodAddress.
+    // Bound in high half patches on R6.
     MipsLabel pc_rel_label;
+    // Pointer to the info for the high half patch or nullptr if this is the high half patch info.
+    const PcRelativePatchInfo* patch_info_high;
+
+   private:
+    PcRelativePatchInfo(PcRelativePatchInfo&& other) = delete;
+    DISALLOW_COPY_AND_ASSIGN(PcRelativePatchInfo);
   };
 
-  PcRelativePatchInfo* NewPcRelativeMethodPatch(MethodReference target_method);
-  PcRelativePatchInfo* NewMethodBssEntryPatch(MethodReference target_method);
-  PcRelativePatchInfo* NewPcRelativeTypePatch(const DexFile& dex_file, dex::TypeIndex type_index);
-  PcRelativePatchInfo* NewTypeBssEntryPatch(const DexFile& dex_file, dex::TypeIndex type_index);
+  PcRelativePatchInfo* NewPcRelativeMethodPatch(MethodReference target_method,
+                                                const PcRelativePatchInfo* info_high = nullptr);
+  PcRelativePatchInfo* NewMethodBssEntryPatch(MethodReference target_method,
+                                              const PcRelativePatchInfo* info_high = nullptr);
+  PcRelativePatchInfo* NewPcRelativeTypePatch(const DexFile& dex_file,
+                                              dex::TypeIndex type_index,
+                                              const PcRelativePatchInfo* info_high = nullptr);
+  PcRelativePatchInfo* NewTypeBssEntryPatch(const DexFile& dex_file,
+                                            dex::TypeIndex type_index,
+                                            const PcRelativePatchInfo* info_high = nullptr);
   PcRelativePatchInfo* NewPcRelativeStringPatch(const DexFile& dex_file,
-                                                dex::StringIndex string_index);
+                                                dex::StringIndex string_index,
+                                                const PcRelativePatchInfo* info_high = nullptr);
   Literal* DeduplicateBootImageAddressLiteral(uint32_t address);
 
-  void EmitPcRelativeAddressPlaceholderHigh(PcRelativePatchInfo* info, Register out, Register base);
+  void EmitPcRelativeAddressPlaceholderHigh(PcRelativePatchInfo* info_high,
+                                            Register out,
+                                            Register base,
+                                            PcRelativePatchInfo* info_low);
 
   // The JitPatchInfo is used for JIT string and class loads.
   struct JitPatchInfo {
@@ -627,6 +662,7 @@
   Literal* DeduplicateUint32Literal(uint32_t value, Uint32ToLiteralMap* map);
   PcRelativePatchInfo* NewPcRelativePatch(const DexFile& dex_file,
                                           uint32_t offset_or_index,
+                                          const PcRelativePatchInfo* info_high,
                                           ArenaDeque<PcRelativePatchInfo>* patches);
 
   template <LinkerPatch (*Factory)(size_t, const DexFile*, uint32_t, uint32_t)>
diff --git a/compiler/optimizing/code_generator_mips64.cc b/compiler/optimizing/code_generator_mips64.cc
index e4f1cbd..5fb8755 100644
--- a/compiler/optimizing/code_generator_mips64.cc
+++ b/compiler/optimizing/code_generator_mips64.cc
@@ -164,19 +164,42 @@
   LoadClassSlowPathMIPS64(HLoadClass* cls,
                           HInstruction* at,
                           uint32_t dex_pc,
-                          bool do_clinit)
-      : SlowPathCodeMIPS64(at), cls_(cls), dex_pc_(dex_pc), do_clinit_(do_clinit) {
+                          bool do_clinit,
+                          const CodeGeneratorMIPS64::PcRelativePatchInfo* bss_info_high = nullptr)
+      : SlowPathCodeMIPS64(at),
+        cls_(cls),
+        dex_pc_(dex_pc),
+        do_clinit_(do_clinit),
+        bss_info_high_(bss_info_high) {
     DCHECK(at->IsLoadClass() || at->IsClinitCheck());
   }
 
   void EmitNativeCode(CodeGenerator* codegen) OVERRIDE {
     LocationSummary* locations = instruction_->GetLocations();
+    Location out = locations->Out();
     CodeGeneratorMIPS64* mips64_codegen = down_cast<CodeGeneratorMIPS64*>(codegen);
-
+    const bool baker_or_no_read_barriers = (!kUseReadBarrier || kUseBakerReadBarrier);
+    InvokeRuntimeCallingConvention calling_convention;
+    DCHECK_EQ(instruction_->IsLoadClass(), cls_ == instruction_);
+    const bool is_load_class_bss_entry =
+        (cls_ == instruction_) && (cls_->GetLoadKind() == HLoadClass::LoadKind::kBssEntry);
     __ Bind(GetEntryLabel());
     SaveLiveRegisters(codegen, locations);
 
-    InvokeRuntimeCallingConvention calling_convention;
+    // For HLoadClass/kBssEntry/kSaveEverything, make sure we preserve the address of the entry.
+    GpuRegister entry_address = kNoGpuRegister;
+    if (is_load_class_bss_entry && baker_or_no_read_barriers) {
+      GpuRegister temp = locations->GetTemp(0).AsRegister<GpuRegister>();
+      bool temp_is_a0 = (temp == calling_convention.GetRegisterAt(0));
+      // In the unlucky case that `temp` is A0, we preserve the address in `out` across the
+      // kSaveEverything call.
+      entry_address = temp_is_a0 ? out.AsRegister<GpuRegister>() : temp;
+      DCHECK_NE(entry_address, calling_convention.GetRegisterAt(0));
+      if (temp_is_a0) {
+        __ Move(entry_address, temp);
+      }
+    }
+
     dex::TypeIndex type_index = cls_->GetTypeIndex();
     __ LoadConst32(calling_convention.GetRegisterAt(0), type_index.index_);
     QuickEntrypointEnum entrypoint = do_clinit_ ? kQuickInitializeStaticStorage
@@ -188,8 +211,20 @@
       CheckEntrypointTypes<kQuickInitializeType, void*, uint32_t>();
     }
 
+    // For HLoadClass/kBssEntry, store the resolved class to the BSS entry.
+    if (is_load_class_bss_entry && baker_or_no_read_barriers) {
+      // The class entry address was preserved in `entry_address` thanks to kSaveEverything.
+      DCHECK(bss_info_high_);
+      CodeGeneratorMIPS64::PcRelativePatchInfo* info_low =
+          mips64_codegen->NewTypeBssEntryPatch(cls_->GetDexFile(), type_index, bss_info_high_);
+      __ Bind(&info_low->label);
+      __ StoreToOffset(kStoreWord,
+                       calling_convention.GetRegisterAt(0),
+                       entry_address,
+                       /* placeholder */ 0x5678);
+    }
+
     // Move the class to the desired location.
-    Location out = locations->Out();
     if (out.IsValid()) {
       DCHECK(out.IsRegister() && !locations->GetLiveRegisters()->ContainsCoreRegister(out.reg()));
       Primitive::Type type = instruction_->GetType();
@@ -197,16 +232,18 @@
                                    Location::RegisterLocation(calling_convention.GetRegisterAt(0)),
                                    type);
     }
-
     RestoreLiveRegisters(codegen, locations);
-    // For HLoadClass/kBssEntry, store the resolved Class to the BSS entry.
-    DCHECK_EQ(instruction_->IsLoadClass(), cls_ == instruction_);
-    if (cls_ == instruction_ && cls_->GetLoadKind() == HLoadClass::LoadKind::kBssEntry) {
-      DCHECK(out.IsValid());
-      CodeGeneratorMIPS64::PcRelativePatchInfo* info =
+
+    // For HLoadClass/kBssEntry, store the resolved class to the BSS entry.
+    if (is_load_class_bss_entry && !baker_or_no_read_barriers) {
+      // For non-Baker read barriers we need to re-calculate the address of
+      // the class entry.
+      CodeGeneratorMIPS64::PcRelativePatchInfo* info_high =
           mips64_codegen->NewTypeBssEntryPatch(cls_->GetDexFile(), type_index);
-      mips64_codegen->EmitPcRelativeAddressPlaceholderHigh(info, AT);
-      __ Sw(out.AsRegister<GpuRegister>(), AT, /* placeholder */ 0x5678);
+      CodeGeneratorMIPS64::PcRelativePatchInfo* info_low =
+          mips64_codegen->NewTypeBssEntryPatch(cls_->GetDexFile(), type_index, info_high);
+      mips64_codegen->EmitPcRelativeAddressPlaceholderHigh(info_high, TMP, info_low);
+      __ StoreToOffset(kStoreWord, out.AsRegister<GpuRegister>(), TMP, /* placeholder */ 0x5678);
     }
     __ Bc(GetExitLabel());
   }
@@ -223,50 +260,94 @@
   // Whether to initialize the class.
   const bool do_clinit_;
 
+  // Pointer to the high half PC-relative patch info for HLoadClass/kBssEntry.
+  const CodeGeneratorMIPS64::PcRelativePatchInfo* bss_info_high_;
+
   DISALLOW_COPY_AND_ASSIGN(LoadClassSlowPathMIPS64);
 };
 
 class LoadStringSlowPathMIPS64 : public SlowPathCodeMIPS64 {
  public:
-  explicit LoadStringSlowPathMIPS64(HLoadString* instruction) : SlowPathCodeMIPS64(instruction) {}
+  explicit LoadStringSlowPathMIPS64(HLoadString* instruction,
+                                    const CodeGeneratorMIPS64::PcRelativePatchInfo* bss_info_high)
+      : SlowPathCodeMIPS64(instruction), bss_info_high_(bss_info_high) {}
 
   void EmitNativeCode(CodeGenerator* codegen) OVERRIDE {
+    DCHECK(instruction_->IsLoadString());
+    DCHECK_EQ(instruction_->AsLoadString()->GetLoadKind(), HLoadString::LoadKind::kBssEntry);
     LocationSummary* locations = instruction_->GetLocations();
     DCHECK(!locations->GetLiveRegisters()->ContainsCoreRegister(locations->Out().reg()));
+    HLoadString* load = instruction_->AsLoadString();
+    const dex::StringIndex string_index = load->GetStringIndex();
+    GpuRegister out = locations->Out().AsRegister<GpuRegister>();
     CodeGeneratorMIPS64* mips64_codegen = down_cast<CodeGeneratorMIPS64*>(codegen);
-
+    const bool baker_or_no_read_barriers = (!kUseReadBarrier || kUseBakerReadBarrier);
+    InvokeRuntimeCallingConvention calling_convention;
     __ Bind(GetEntryLabel());
     SaveLiveRegisters(codegen, locations);
 
-    InvokeRuntimeCallingConvention calling_convention;
-    HLoadString* load = instruction_->AsLoadString();
-    const dex::StringIndex string_index = instruction_->AsLoadString()->GetStringIndex();
+    // For HLoadString/kBssEntry/kSaveEverything, make sure we preserve the address of the entry.
+    GpuRegister entry_address = kNoGpuRegister;
+    if (baker_or_no_read_barriers) {
+      GpuRegister temp = locations->GetTemp(0).AsRegister<GpuRegister>();
+      bool temp_is_a0 = (temp == calling_convention.GetRegisterAt(0));
+      // In the unlucky case that `temp` is A0, we preserve the address in `out` across the
+      // kSaveEverything call.
+      entry_address = temp_is_a0 ? out : temp;
+      DCHECK_NE(entry_address, calling_convention.GetRegisterAt(0));
+      if (temp_is_a0) {
+        __ Move(entry_address, temp);
+      }
+    }
+
     __ LoadConst32(calling_convention.GetRegisterAt(0), string_index.index_);
     mips64_codegen->InvokeRuntime(kQuickResolveString,
                                   instruction_,
                                   instruction_->GetDexPc(),
                                   this);
     CheckEntrypointTypes<kQuickResolveString, void*, uint32_t>();
+
+    // Store the resolved string to the BSS entry.
+    if (baker_or_no_read_barriers) {
+      // The string entry address was preserved in `entry_address` thanks to kSaveEverything.
+      DCHECK(bss_info_high_);
+      CodeGeneratorMIPS64::PcRelativePatchInfo* info_low =
+          mips64_codegen->NewPcRelativeStringPatch(load->GetDexFile(),
+                                                   string_index,
+                                                   bss_info_high_);
+      __ Bind(&info_low->label);
+      __ StoreToOffset(kStoreWord,
+                       calling_convention.GetRegisterAt(0),
+                       entry_address,
+                       /* placeholder */ 0x5678);
+    }
+
     Primitive::Type type = instruction_->GetType();
     mips64_codegen->MoveLocation(locations->Out(),
                                  Location::RegisterLocation(calling_convention.GetRegisterAt(0)),
                                  type);
-
     RestoreLiveRegisters(codegen, locations);
 
-    // Store the resolved String to the BSS entry.
-    GpuRegister out = locations->Out().AsRegister<GpuRegister>();
-    CodeGeneratorMIPS64::PcRelativePatchInfo* info =
-        mips64_codegen->NewPcRelativeStringPatch(load->GetDexFile(), string_index);
-    mips64_codegen->EmitPcRelativeAddressPlaceholderHigh(info, AT);
-    __ Sw(out, AT, /* placeholder */ 0x5678);
-
+    // Store the resolved string to the BSS entry.
+    if (!baker_or_no_read_barriers) {
+      // For non-Baker read barriers we need to re-calculate the address of
+      // the string entry.
+      CodeGeneratorMIPS64::PcRelativePatchInfo* info_high =
+          mips64_codegen->NewPcRelativeStringPatch(load->GetDexFile(), string_index);
+      CodeGeneratorMIPS64::PcRelativePatchInfo* info_low =
+          mips64_codegen->NewPcRelativeStringPatch(load->GetDexFile(), string_index, info_high);
+      mips64_codegen->EmitPcRelativeAddressPlaceholderHigh(info_high, TMP, info_low);
+      __ StoreToOffset(kStoreWord, out, TMP, /* placeholder */ 0x5678);
+    }
     __ Bc(GetExitLabel());
   }
 
   const char* GetDescription() const OVERRIDE { return "LoadStringSlowPathMIPS64"; }
 
  private:
+  // Pointer to the high half PC-relative patch info.
+  const CodeGeneratorMIPS64::PcRelativePatchInfo* bss_info_high_;
+
   DISALLOW_COPY_AND_ASSIGN(LoadStringSlowPathMIPS64);
 };
 
@@ -1431,9 +1512,11 @@
   for (const PcRelativePatchInfo& info : infos) {
     const DexFile& dex_file = info.target_dex_file;
     size_t offset_or_index = info.offset_or_index;
-    DCHECK(info.pc_rel_label.IsBound());
-    uint32_t pc_rel_offset = __ GetLabelLocation(&info.pc_rel_label);
-    linker_patches->push_back(Factory(pc_rel_offset, &dex_file, pc_rel_offset, offset_or_index));
+    DCHECK(info.label.IsBound());
+    uint32_t literal_offset = __ GetLabelLocation(&info.label);
+    const PcRelativePatchInfo& info_high = info.patch_info_high ? *info.patch_info_high : info;
+    uint32_t pc_rel_offset = __ GetLabelLocation(&info_high.label);
+    linker_patches->push_back(Factory(literal_offset, &dex_file, pc_rel_offset, offset_or_index));
   }
 }
 
@@ -1467,37 +1550,50 @@
 }
 
 CodeGeneratorMIPS64::PcRelativePatchInfo* CodeGeneratorMIPS64::NewPcRelativeMethodPatch(
-    MethodReference target_method) {
+    MethodReference target_method,
+    const PcRelativePatchInfo* info_high) {
   return NewPcRelativePatch(*target_method.dex_file,
                             target_method.dex_method_index,
+                            info_high,
                             &pc_relative_method_patches_);
 }
 
 CodeGeneratorMIPS64::PcRelativePatchInfo* CodeGeneratorMIPS64::NewMethodBssEntryPatch(
-    MethodReference target_method) {
+    MethodReference target_method,
+    const PcRelativePatchInfo* info_high) {
   return NewPcRelativePatch(*target_method.dex_file,
                             target_method.dex_method_index,
+                            info_high,
                             &method_bss_entry_patches_);
 }
 
 CodeGeneratorMIPS64::PcRelativePatchInfo* CodeGeneratorMIPS64::NewPcRelativeTypePatch(
-    const DexFile& dex_file, dex::TypeIndex type_index) {
-  return NewPcRelativePatch(dex_file, type_index.index_, &pc_relative_type_patches_);
+    const DexFile& dex_file,
+    dex::TypeIndex type_index,
+    const PcRelativePatchInfo* info_high) {
+  return NewPcRelativePatch(dex_file, type_index.index_, info_high, &pc_relative_type_patches_);
 }
 
 CodeGeneratorMIPS64::PcRelativePatchInfo* CodeGeneratorMIPS64::NewTypeBssEntryPatch(
-    const DexFile& dex_file, dex::TypeIndex type_index) {
-  return NewPcRelativePatch(dex_file, type_index.index_, &type_bss_entry_patches_);
+    const DexFile& dex_file,
+    dex::TypeIndex type_index,
+    const PcRelativePatchInfo* info_high) {
+  return NewPcRelativePatch(dex_file, type_index.index_, info_high, &type_bss_entry_patches_);
 }
 
 CodeGeneratorMIPS64::PcRelativePatchInfo* CodeGeneratorMIPS64::NewPcRelativeStringPatch(
-    const DexFile& dex_file, dex::StringIndex string_index) {
-  return NewPcRelativePatch(dex_file, string_index.index_, &pc_relative_string_patches_);
+    const DexFile& dex_file,
+    dex::StringIndex string_index,
+    const PcRelativePatchInfo* info_high) {
+  return NewPcRelativePatch(dex_file, string_index.index_, info_high, &pc_relative_string_patches_);
 }
 
 CodeGeneratorMIPS64::PcRelativePatchInfo* CodeGeneratorMIPS64::NewPcRelativePatch(
-    const DexFile& dex_file, uint32_t offset_or_index, ArenaDeque<PcRelativePatchInfo>* patches) {
-  patches->emplace_back(dex_file, offset_or_index);
+    const DexFile& dex_file,
+    uint32_t offset_or_index,
+    const PcRelativePatchInfo* info_high,
+    ArenaDeque<PcRelativePatchInfo>* patches) {
+  patches->emplace_back(dex_file, offset_or_index, info_high);
   return &patches->back();
 }
 
@@ -1517,13 +1613,17 @@
   return DeduplicateUint32Literal(dchecked_integral_cast<uint32_t>(address), &uint32_literals_);
 }
 
-void CodeGeneratorMIPS64::EmitPcRelativeAddressPlaceholderHigh(PcRelativePatchInfo* info,
-                                                               GpuRegister out) {
-  __ Bind(&info->pc_rel_label);
+void CodeGeneratorMIPS64::EmitPcRelativeAddressPlaceholderHigh(PcRelativePatchInfo* info_high,
+                                                               GpuRegister out,
+                                                               PcRelativePatchInfo* info_low) {
+  DCHECK(!info_high->patch_info_high);
+  __ Bind(&info_high->label);
   // Add the high half of a 32-bit offset to PC.
   __ Auipc(out, /* placeholder */ 0x1234);
-  // The immediately following instruction will add the sign-extended low half of the 32-bit
+  // A following instruction will add the sign-extended low half of the 32-bit
   // offset to `out` (e.g. ld, jialc, daddiu).
+  DCHECK_EQ(info_low->patch_info_high, info_high);
+  __ Bind(&info_low->label);
 }
 
 Literal* CodeGeneratorMIPS64::DeduplicateJitStringLiteral(const DexFile& dex_file,
@@ -4940,9 +5040,11 @@
       break;
     case HInvokeStaticOrDirect::MethodLoadKind::kBootImageLinkTimePcRelative: {
       DCHECK(GetCompilerOptions().IsBootImage());
-      CodeGeneratorMIPS64::PcRelativePatchInfo* info =
+      CodeGeneratorMIPS64::PcRelativePatchInfo* info_high =
           NewPcRelativeMethodPatch(invoke->GetTargetMethod());
-      EmitPcRelativeAddressPlaceholderHigh(info, AT);
+      CodeGeneratorMIPS64::PcRelativePatchInfo* info_low =
+          NewPcRelativeMethodPatch(invoke->GetTargetMethod(), info_high);
+      EmitPcRelativeAddressPlaceholderHigh(info_high, AT, info_low);
       __ Daddiu(temp.AsRegister<GpuRegister>(), AT, /* placeholder */ 0x5678);
       break;
     }
@@ -4952,9 +5054,11 @@
                      DeduplicateUint64Literal(invoke->GetMethodAddress()));
       break;
     case HInvokeStaticOrDirect::MethodLoadKind::kBssEntry: {
-      PcRelativePatchInfo* info = NewMethodBssEntryPatch(
+      PcRelativePatchInfo* info_high = NewMethodBssEntryPatch(
           MethodReference(&GetGraph()->GetDexFile(), invoke->GetDexMethodIndex()));
-      EmitPcRelativeAddressPlaceholderHigh(info, AT);
+      PcRelativePatchInfo* info_low = NewMethodBssEntryPatch(
+          MethodReference(&GetGraph()->GetDexFile(), invoke->GetDexMethodIndex()), info_high);
+      EmitPcRelativeAddressPlaceholderHigh(info_high, AT, info_low);
       __ Ld(temp.AsRegister<GpuRegister>(), AT, /* placeholder */ 0x5678);
       break;
     }
@@ -5071,12 +5175,14 @@
   if (load_kind == HLoadClass::LoadKind::kBssEntry) {
     if (!kUseReadBarrier || kUseBakerReadBarrier) {
       // Rely on the type resolution or initialization and marking to save everything we need.
+      // Request a temp to hold the BSS entry location for the slow path.
+      locations->AddTemp(Location::RequiresRegister());
       RegisterSet caller_saves = RegisterSet::Empty();
       InvokeRuntimeCallingConvention calling_convention;
       caller_saves.Add(Location::RegisterLocation(calling_convention.GetRegisterAt(0)));
       locations->SetCustomSlowPathCallerSaves(caller_saves);
     } else {
-      // For non-Baker read barrier we have a temp-clobbering call.
+      // For non-Baker read barriers we have a temp-clobbering call.
     }
   }
 }
@@ -5104,6 +5210,7 @@
       ? kWithoutReadBarrier
       : kCompilerReadBarrierOption;
   bool generate_null_check = false;
+  CodeGeneratorMIPS64::PcRelativePatchInfo* bss_info_high = nullptr;
   switch (load_kind) {
     case HLoadClass::LoadKind::kReferrersClass:
       DCHECK(!cls->CanCallRuntime());
@@ -5118,9 +5225,11 @@
     case HLoadClass::LoadKind::kBootImageLinkTimePcRelative: {
       DCHECK(codegen_->GetCompilerOptions().IsBootImage());
       DCHECK_EQ(read_barrier_option, kWithoutReadBarrier);
-      CodeGeneratorMIPS64::PcRelativePatchInfo* info =
+      CodeGeneratorMIPS64::PcRelativePatchInfo* info_high =
           codegen_->NewPcRelativeTypePatch(cls->GetDexFile(), cls->GetTypeIndex());
-      codegen_->EmitPcRelativeAddressPlaceholderHigh(info, AT);
+      CodeGeneratorMIPS64::PcRelativePatchInfo* info_low =
+          codegen_->NewPcRelativeTypePatch(cls->GetDexFile(), cls->GetTypeIndex(), info_high);
+      codegen_->EmitPcRelativeAddressPlaceholderHigh(info_high, AT, info_low);
       __ Daddiu(out, AT, /* placeholder */ 0x5678);
       break;
     }
@@ -5135,10 +5244,15 @@
       break;
     }
     case HLoadClass::LoadKind::kBssEntry: {
-      CodeGeneratorMIPS64::PcRelativePatchInfo* info =
-          codegen_->NewTypeBssEntryPatch(cls->GetDexFile(), cls->GetTypeIndex());
-      codegen_->EmitPcRelativeAddressPlaceholderHigh(info, out);
-      GenerateGcRootFieldLoad(cls, out_loc, out, /* placeholder */ 0x5678, read_barrier_option);
+      bss_info_high = codegen_->NewTypeBssEntryPatch(cls->GetDexFile(), cls->GetTypeIndex());
+      CodeGeneratorMIPS64::PcRelativePatchInfo* info_low =
+          codegen_->NewTypeBssEntryPatch(cls->GetDexFile(), cls->GetTypeIndex(), bss_info_high);
+      constexpr bool non_baker_read_barrier = kUseReadBarrier && !kUseBakerReadBarrier;
+      GpuRegister temp = non_baker_read_barrier
+          ? out
+          : locations->GetTemp(0).AsRegister<GpuRegister>();
+      codegen_->EmitPcRelativeAddressPlaceholderHigh(bss_info_high, temp, info_low);
+      GenerateGcRootFieldLoad(cls, out_loc, temp, /* placeholder */ 0x5678, read_barrier_option);
       generate_null_check = true;
       break;
     }
@@ -5159,7 +5273,7 @@
   if (generate_null_check || cls->MustGenerateClinitCheck()) {
     DCHECK(cls->CanCallRuntime());
     SlowPathCodeMIPS64* slow_path = new (GetGraph()->GetArena()) LoadClassSlowPathMIPS64(
-        cls, cls, cls->GetDexPc(), cls->MustGenerateClinitCheck());
+        cls, cls, cls->GetDexPc(), cls->MustGenerateClinitCheck(), bss_info_high);
     codegen_->AddSlowPath(slow_path);
     if (generate_null_check) {
       __ Beqzc(out, slow_path->GetEntryLabel());
@@ -5207,12 +5321,14 @@
     if (load_kind == HLoadString::LoadKind::kBssEntry) {
       if (!kUseReadBarrier || kUseBakerReadBarrier) {
         // Rely on the pResolveString and marking to save everything we need.
+        // Request a temp to hold the BSS entry location for the slow path.
+        locations->AddTemp(Location::RequiresRegister());
         RegisterSet caller_saves = RegisterSet::Empty();
         InvokeRuntimeCallingConvention calling_convention;
         caller_saves.Add(Location::RegisterLocation(calling_convention.GetRegisterAt(0)));
         locations->SetCustomSlowPathCallerSaves(caller_saves);
       } else {
-        // For non-Baker read barrier we have a temp-clobbering call.
+        // For non-Baker read barriers we have a temp-clobbering call.
       }
     }
   }
@@ -5229,9 +5345,11 @@
   switch (load_kind) {
     case HLoadString::LoadKind::kBootImageLinkTimePcRelative: {
       DCHECK(codegen_->GetCompilerOptions().IsBootImage());
-      CodeGeneratorMIPS64::PcRelativePatchInfo* info =
+      CodeGeneratorMIPS64::PcRelativePatchInfo* info_high =
           codegen_->NewPcRelativeStringPatch(load->GetDexFile(), load->GetStringIndex());
-      codegen_->EmitPcRelativeAddressPlaceholderHigh(info, AT);
+      CodeGeneratorMIPS64::PcRelativePatchInfo* info_low =
+          codegen_->NewPcRelativeStringPatch(load->GetDexFile(), load->GetStringIndex(), info_high);
+      codegen_->EmitPcRelativeAddressPlaceholderHigh(info_high, AT, info_low);
       __ Daddiu(out, AT, /* placeholder */ 0x5678);
       return;  // No dex cache slow path.
     }
@@ -5246,15 +5364,22 @@
     }
     case HLoadString::LoadKind::kBssEntry: {
       DCHECK(!codegen_->GetCompilerOptions().IsBootImage());
-      CodeGeneratorMIPS64::PcRelativePatchInfo* info =
+      CodeGeneratorMIPS64::PcRelativePatchInfo* info_high =
           codegen_->NewPcRelativeStringPatch(load->GetDexFile(), load->GetStringIndex());
-      codegen_->EmitPcRelativeAddressPlaceholderHigh(info, out);
+      CodeGeneratorMIPS64::PcRelativePatchInfo* info_low =
+          codegen_->NewPcRelativeStringPatch(load->GetDexFile(), load->GetStringIndex(), info_high);
+      constexpr bool non_baker_read_barrier = kUseReadBarrier && !kUseBakerReadBarrier;
+      GpuRegister temp = non_baker_read_barrier
+          ? out
+          : locations->GetTemp(0).AsRegister<GpuRegister>();
+      codegen_->EmitPcRelativeAddressPlaceholderHigh(info_high, temp, info_low);
       GenerateGcRootFieldLoad(load,
                               out_loc,
-                              out,
+                              temp,
                               /* placeholder */ 0x5678,
                               kCompilerReadBarrierOption);
-      SlowPathCodeMIPS64* slow_path = new (GetGraph()->GetArena()) LoadStringSlowPathMIPS64(load);
+      SlowPathCodeMIPS64* slow_path =
+          new (GetGraph()->GetArena()) LoadStringSlowPathMIPS64(load, info_high);
       codegen_->AddSlowPath(slow_path);
       __ Beqzc(out, slow_path->GetEntryLabel());
       __ Bind(slow_path->GetExitLabel());
diff --git a/compiler/optimizing/code_generator_mips64.h b/compiler/optimizing/code_generator_mips64.h
index 6260c73..b620973 100644
--- a/compiler/optimizing/code_generator_mips64.h
+++ b/compiler/optimizing/code_generator_mips64.h
@@ -538,29 +538,59 @@
   // The PcRelativePatchInfo is used for PC-relative addressing of dex cache arrays,
   // boot image strings and method calls. The only difference is the interpretation of
   // the offset_or_index.
+  // The 16-bit halves of the 32-bit PC-relative offset are patched separately, necessitating
+  // two patches/infos. There can be more than two patches/infos if the instruction supplying
+  // the high half is shared with e.g. a slow path, while the low half is supplied by separate
+  // instructions, e.g.:
+  //     auipc r1, high       // patch
+  //     lwu   r2, low(r1)    // patch
+  //     beqzc r2, slow_path
+  //   back:
+  //     ...
+  //   slow_path:
+  //     ...
+  //     sw    r2, low(r1)    // patch
+  //     bc    back
   struct PcRelativePatchInfo {
-    PcRelativePatchInfo(const DexFile& dex_file, uint32_t off_or_idx)
-        : target_dex_file(dex_file), offset_or_index(off_or_idx) { }
-    PcRelativePatchInfo(PcRelativePatchInfo&& other) = default;
+    PcRelativePatchInfo(const DexFile& dex_file,
+                        uint32_t off_or_idx,
+                        const PcRelativePatchInfo* info_high)
+        : target_dex_file(dex_file),
+          offset_or_index(off_or_idx),
+          label(),
+          patch_info_high(info_high) { }
 
     const DexFile& target_dex_file;
     // Either the dex cache array element offset or the string/type/method index.
     uint32_t offset_or_index;
-    // Label for the auipc instruction.
-    Mips64Label pc_rel_label;
+    // Label for the instruction to patch.
+    Mips64Label label;
+    // Pointer to the info for the high half patch or nullptr if this is the high half patch info.
+    const PcRelativePatchInfo* patch_info_high;
+
+   private:
+    PcRelativePatchInfo(PcRelativePatchInfo&& other) = delete;
+    DISALLOW_COPY_AND_ASSIGN(PcRelativePatchInfo);
   };
 
-  PcRelativePatchInfo* NewPcRelativeMethodPatch(MethodReference target_method);
-  PcRelativePatchInfo* NewMethodBssEntryPatch(MethodReference target_method);
-  PcRelativePatchInfo* NewPcRelativeTypePatch(const DexFile& dex_file, dex::TypeIndex type_index);
-  PcRelativePatchInfo* NewTypeBssEntryPatch(const DexFile& dex_file, dex::TypeIndex type_index);
+  PcRelativePatchInfo* NewPcRelativeMethodPatch(MethodReference target_method,
+                                                const PcRelativePatchInfo* info_high = nullptr);
+  PcRelativePatchInfo* NewMethodBssEntryPatch(MethodReference target_method,
+                                              const PcRelativePatchInfo* info_high = nullptr);
+  PcRelativePatchInfo* NewPcRelativeTypePatch(const DexFile& dex_file,
+                                              dex::TypeIndex type_index,
+                                              const PcRelativePatchInfo* info_high = nullptr);
+  PcRelativePatchInfo* NewTypeBssEntryPatch(const DexFile& dex_file,
+                                            dex::TypeIndex type_index,
+                                            const PcRelativePatchInfo* info_high = nullptr);
   PcRelativePatchInfo* NewPcRelativeStringPatch(const DexFile& dex_file,
-                                                dex::StringIndex string_index);
-  PcRelativePatchInfo* NewPcRelativeCallPatch(const DexFile& dex_file,
-                                              uint32_t method_index);
+                                                dex::StringIndex string_index,
+                                                const PcRelativePatchInfo* info_high = nullptr);
   Literal* DeduplicateBootImageAddressLiteral(uint64_t address);
 
-  void EmitPcRelativeAddressPlaceholderHigh(PcRelativePatchInfo* info, GpuRegister out);
+  void EmitPcRelativeAddressPlaceholderHigh(PcRelativePatchInfo* info_high,
+                                            GpuRegister out,
+                                            PcRelativePatchInfo* info_low);
 
   void PatchJitRootUse(uint8_t* code,
                        const uint8_t* roots_data,
@@ -588,6 +618,7 @@
 
   PcRelativePatchInfo* NewPcRelativePatch(const DexFile& dex_file,
                                           uint32_t offset_or_index,
+                                          const PcRelativePatchInfo* info_high,
                                           ArenaDeque<PcRelativePatchInfo>* patches);
 
   template <LinkerPatch (*Factory)(size_t, const DexFile*, uint32_t, uint32_t)>
diff --git a/compiler/optimizing/code_generator_vector_arm_vixl.cc b/compiler/optimizing/code_generator_vector_arm_vixl.cc
index 53f314e..527691d 100644
--- a/compiler/optimizing/code_generator_vector_arm_vixl.cc
+++ b/compiler/optimizing/code_generator_vector_arm_vixl.cc
@@ -15,19 +15,62 @@
  */
 
 #include "code_generator_arm_vixl.h"
+#include "mirror/array-inl.h"
+
+namespace vixl32 = vixl::aarch32;
+using namespace vixl32;  // NOLINT(build/namespaces)
 
 namespace art {
 namespace arm {
 
-// NOLINT on __ macro to suppress wrong warning/fix (misc-macro-parentheses) from clang-tidy.
-#define __ reinterpret_cast<ArmVIXLAssembler*>(GetAssembler())->GetVIXLAssembler()->  // NOLINT
+using helpers::DRegisterFrom;
+using helpers::Int64ConstantFrom;
+using helpers::InputDRegisterAt;
+using helpers::InputRegisterAt;
+using helpers::OutputDRegister;
+using helpers::RegisterFrom;
+
+#define __ GetVIXLAssembler()->
 
 void LocationsBuilderARMVIXL::VisitVecReplicateScalar(HVecReplicateScalar* instruction) {
-  LOG(FATAL) << "No SIMD for " << instruction->GetId();
+  LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(instruction);
+  switch (instruction->GetPackedType()) {
+    case Primitive::kPrimBoolean:
+    case Primitive::kPrimByte:
+    case Primitive::kPrimChar:
+    case Primitive::kPrimShort:
+    case Primitive::kPrimInt:
+      locations->SetInAt(0, Location::RequiresRegister());
+      locations->SetOut(Location::RequiresFpuRegister());
+      break;
+    default:
+      LOG(FATAL) << "Unsupported SIMD type";
+      UNREACHABLE();
+  }
 }
 
 void InstructionCodeGeneratorARMVIXL::VisitVecReplicateScalar(HVecReplicateScalar* instruction) {
-  LOG(FATAL) << "No SIMD for " << instruction->GetId();
+  LocationSummary* locations = instruction->GetLocations();
+  vixl32::DRegister dst = DRegisterFrom(locations->Out());
+  switch (instruction->GetPackedType()) {
+    case Primitive::kPrimBoolean:
+    case Primitive::kPrimByte:
+      DCHECK_EQ(8u, instruction->GetVectorLength());
+      __ Vdup(Untyped8, dst, InputRegisterAt(instruction, 0));
+      break;
+    case Primitive::kPrimChar:
+    case Primitive::kPrimShort:
+      DCHECK_EQ(4u, instruction->GetVectorLength());
+      __ Vdup(Untyped16, dst, InputRegisterAt(instruction, 0));
+      break;
+    case Primitive::kPrimInt:
+      DCHECK_EQ(2u, instruction->GetVectorLength());
+      __ Vdup(Untyped32, dst, InputRegisterAt(instruction, 0));
+      break;
+    default:
+      LOG(FATAL) << "Unsupported SIMD type";
+      UNREACHABLE();
+  }
 }
 
 void LocationsBuilderARMVIXL::VisitVecSetScalars(HVecSetScalars* instruction) {
@@ -51,13 +94,17 @@
   LocationSummary* locations = new (arena) LocationSummary(instruction);
   switch (instruction->GetPackedType()) {
     case Primitive::kPrimBoolean:
+      locations->SetInAt(0, Location::RequiresFpuRegister());
+      locations->SetOut(Location::RequiresFpuRegister(),
+                        instruction->IsVecNot() ? Location::kOutputOverlap
+                                                : Location::kNoOutputOverlap);
+      break;
     case Primitive::kPrimByte:
     case Primitive::kPrimChar:
     case Primitive::kPrimShort:
     case Primitive::kPrimInt:
-    case Primitive::kPrimFloat:
-    case Primitive::kPrimDouble:
-      DCHECK(locations);
+      locations->SetInAt(0, Location::RequiresFpuRegister());
+      locations->SetOut(Location::RequiresFpuRegister(), Location::kNoOutputOverlap);
       break;
     default:
       LOG(FATAL) << "Unsupported SIMD type";
@@ -78,7 +125,27 @@
 }
 
 void InstructionCodeGeneratorARMVIXL::VisitVecNeg(HVecNeg* instruction) {
-  LOG(FATAL) << "No SIMD for " << instruction->GetId();
+  LocationSummary* locations = instruction->GetLocations();
+  vixl32::DRegister src = DRegisterFrom(locations->InAt(0));
+  vixl32::DRegister dst = DRegisterFrom(locations->Out());
+  switch (instruction->GetPackedType()) {
+    case Primitive::kPrimByte:
+      DCHECK_EQ(8u, instruction->GetVectorLength());
+      __ Vneg(DataTypeValue::S8, dst, src);
+      break;
+    case Primitive::kPrimChar:
+    case Primitive::kPrimShort:
+      DCHECK_EQ(4u, instruction->GetVectorLength());
+      __ Vneg(DataTypeValue::S16, dst, src);
+      break;
+    case Primitive::kPrimInt:
+      DCHECK_EQ(2u, instruction->GetVectorLength());
+      __ Vneg(DataTypeValue::S32, dst, src);
+      break;
+    default:
+      LOG(FATAL) << "Unsupported SIMD type";
+      UNREACHABLE();
+  }
 }
 
 void LocationsBuilderARMVIXL::VisitVecAbs(HVecAbs* instruction) {
@@ -86,7 +153,27 @@
 }
 
 void InstructionCodeGeneratorARMVIXL::VisitVecAbs(HVecAbs* instruction) {
-  LOG(FATAL) << "No SIMD for " << instruction->GetId();
+  LocationSummary* locations = instruction->GetLocations();
+  vixl32::DRegister src = DRegisterFrom(locations->InAt(0));
+  vixl32::DRegister dst = DRegisterFrom(locations->Out());
+  switch (instruction->GetPackedType()) {
+    case Primitive::kPrimByte:
+      DCHECK_EQ(8u, instruction->GetVectorLength());
+      __ Vabs(DataTypeValue::S8, dst, src);
+      break;
+    case Primitive::kPrimChar:
+    case Primitive::kPrimShort:
+      DCHECK_EQ(4u, instruction->GetVectorLength());
+      __ Vabs(DataTypeValue::S16, dst, src);
+      break;
+    case Primitive::kPrimInt:
+      DCHECK_EQ(2u, instruction->GetVectorLength());
+      __ Vabs(DataTypeValue::S32, dst, src);
+      break;
+    default:
+      LOG(FATAL) << "Unsupported SIMD type";
+      UNREACHABLE();
+  }
 }
 
 void LocationsBuilderARMVIXL::VisitVecNot(HVecNot* instruction) {
@@ -94,7 +181,25 @@
 }
 
 void InstructionCodeGeneratorARMVIXL::VisitVecNot(HVecNot* instruction) {
-  LOG(FATAL) << "No SIMD for " << instruction->GetId();
+  LocationSummary* locations = instruction->GetLocations();
+  vixl32::DRegister src = DRegisterFrom(locations->InAt(0));
+  vixl32::DRegister dst = DRegisterFrom(locations->Out());
+  switch (instruction->GetPackedType()) {
+    case Primitive::kPrimBoolean:  // special case boolean-not
+      DCHECK_EQ(8u, instruction->GetVectorLength());
+      __ Vmov(I8, dst, 1);
+      __ Veor(dst, dst, src);
+      break;
+    case Primitive::kPrimByte:
+    case Primitive::kPrimChar:
+    case Primitive::kPrimShort:
+    case Primitive::kPrimInt:
+      __ Vmvn(I8, dst, src);  // lanes do not matter
+      break;
+    default:
+      LOG(FATAL) << "Unsupported SIMD type";
+      UNREACHABLE();
+  }
 }
 
 // Helper to set up locations for vector binary operations.
@@ -106,9 +211,9 @@
     case Primitive::kPrimChar:
     case Primitive::kPrimShort:
     case Primitive::kPrimInt:
-    case Primitive::kPrimFloat:
-    case Primitive::kPrimDouble:
-      DCHECK(locations);
+      locations->SetInAt(0, Location::RequiresFpuRegister());
+      locations->SetInAt(1, Location::RequiresFpuRegister());
+      locations->SetOut(Location::RequiresFpuRegister(), Location::kNoOutputOverlap);
       break;
     default:
       LOG(FATAL) << "Unsupported SIMD type";
@@ -121,7 +226,28 @@
 }
 
 void InstructionCodeGeneratorARMVIXL::VisitVecAdd(HVecAdd* instruction) {
-  LOG(FATAL) << "No SIMD for " << instruction->GetId();
+  LocationSummary* locations = instruction->GetLocations();
+  vixl32::DRegister lhs = DRegisterFrom(locations->InAt(0));
+  vixl32::DRegister rhs = DRegisterFrom(locations->InAt(1));
+  vixl32::DRegister dst = DRegisterFrom(locations->Out());
+  switch (instruction->GetPackedType()) {
+    case Primitive::kPrimByte:
+      DCHECK_EQ(8u, instruction->GetVectorLength());
+      __ Vadd(I8, dst, lhs, rhs);
+      break;
+    case Primitive::kPrimChar:
+    case Primitive::kPrimShort:
+      DCHECK_EQ(4u, instruction->GetVectorLength());
+      __ Vadd(I16, dst, lhs, rhs);
+      break;
+    case Primitive::kPrimInt:
+      DCHECK_EQ(2u, instruction->GetVectorLength());
+      __ Vadd(I32, dst, lhs, rhs);
+      break;
+    default:
+      LOG(FATAL) << "Unsupported SIMD type";
+      UNREACHABLE();
+  }
 }
 
 void LocationsBuilderARMVIXL::VisitVecHalvingAdd(HVecHalvingAdd* instruction) {
@@ -129,7 +255,40 @@
 }
 
 void InstructionCodeGeneratorARMVIXL::VisitVecHalvingAdd(HVecHalvingAdd* instruction) {
-  LOG(FATAL) << "No SIMD for " << instruction->GetId();
+  LocationSummary* locations = instruction->GetLocations();
+  vixl32::DRegister lhs = DRegisterFrom(locations->InAt(0));
+  vixl32::DRegister rhs = DRegisterFrom(locations->InAt(1));
+  vixl32::DRegister dst = DRegisterFrom(locations->Out());
+  switch (instruction->GetPackedType()) {
+    case Primitive::kPrimByte:
+      DCHECK_EQ(8u, instruction->GetVectorLength());
+      if (instruction->IsUnsigned()) {
+        instruction->IsRounded()
+            ? __ Vrhadd(DataTypeValue::U8, dst, lhs, rhs)
+            : __ Vhadd(DataTypeValue::U8, dst, lhs, rhs);
+      } else {
+        instruction->IsRounded()
+            ? __ Vrhadd(DataTypeValue::S8, dst, lhs, rhs)
+            : __ Vhadd(DataTypeValue::S8, dst, lhs, rhs);
+      }
+      break;
+    case Primitive::kPrimChar:
+    case Primitive::kPrimShort:
+      DCHECK_EQ(4u, instruction->GetVectorLength());
+      if (instruction->IsUnsigned()) {
+        instruction->IsRounded()
+            ? __ Vrhadd(DataTypeValue::U16, dst, lhs, rhs)
+            : __ Vhadd(DataTypeValue::U16, dst, lhs, rhs);
+      } else {
+        instruction->IsRounded()
+            ? __ Vrhadd(DataTypeValue::S16, dst, lhs, rhs)
+            : __ Vhadd(DataTypeValue::S16, dst, lhs, rhs);
+      }
+      break;
+    default:
+      LOG(FATAL) << "Unsupported SIMD type";
+      UNREACHABLE();
+  }
 }
 
 void LocationsBuilderARMVIXL::VisitVecSub(HVecSub* instruction) {
@@ -137,7 +296,28 @@
 }
 
 void InstructionCodeGeneratorARMVIXL::VisitVecSub(HVecSub* instruction) {
-  LOG(FATAL) << "No SIMD for " << instruction->GetId();
+  LocationSummary* locations = instruction->GetLocations();
+  vixl32::DRegister lhs = DRegisterFrom(locations->InAt(0));
+  vixl32::DRegister rhs = DRegisterFrom(locations->InAt(1));
+  vixl32::DRegister dst = DRegisterFrom(locations->Out());
+  switch (instruction->GetPackedType()) {
+    case Primitive::kPrimByte:
+      DCHECK_EQ(8u, instruction->GetVectorLength());
+      __ Vsub(I8, dst, lhs, rhs);
+      break;
+    case Primitive::kPrimChar:
+    case Primitive::kPrimShort:
+      DCHECK_EQ(4u, instruction->GetVectorLength());
+      __ Vsub(I16, dst, lhs, rhs);
+      break;
+    case Primitive::kPrimInt:
+      DCHECK_EQ(2u, instruction->GetVectorLength());
+      __ Vsub(I32, dst, lhs, rhs);
+      break;
+    default:
+      LOG(FATAL) << "Unsupported SIMD type";
+      UNREACHABLE();
+  }
 }
 
 void LocationsBuilderARMVIXL::VisitVecMul(HVecMul* instruction) {
@@ -145,7 +325,28 @@
 }
 
 void InstructionCodeGeneratorARMVIXL::VisitVecMul(HVecMul* instruction) {
-  LOG(FATAL) << "No SIMD for " << instruction->GetId();
+  LocationSummary* locations = instruction->GetLocations();
+  vixl32::DRegister lhs = DRegisterFrom(locations->InAt(0));
+  vixl32::DRegister rhs = DRegisterFrom(locations->InAt(1));
+  vixl32::DRegister dst = DRegisterFrom(locations->Out());
+  switch (instruction->GetPackedType()) {
+    case Primitive::kPrimByte:
+      DCHECK_EQ(8u, instruction->GetVectorLength());
+      __ Vmul(I8, dst, lhs, rhs);
+      break;
+    case Primitive::kPrimChar:
+    case Primitive::kPrimShort:
+      DCHECK_EQ(4u, instruction->GetVectorLength());
+      __ Vmul(I16, dst, lhs, rhs);
+      break;
+    case Primitive::kPrimInt:
+      DCHECK_EQ(2u, instruction->GetVectorLength());
+      __ Vmul(I32, dst, lhs, rhs);
+      break;
+    default:
+      LOG(FATAL) << "Unsupported SIMD type";
+      UNREACHABLE();
+  }
 }
 
 void LocationsBuilderARMVIXL::VisitVecDiv(HVecDiv* instruction) {
@@ -161,7 +362,40 @@
 }
 
 void InstructionCodeGeneratorARMVIXL::VisitVecMin(HVecMin* instruction) {
-  LOG(FATAL) << "No SIMD for " << instruction->GetId();
+  LocationSummary* locations = instruction->GetLocations();
+  vixl32::DRegister lhs = DRegisterFrom(locations->InAt(0));
+  vixl32::DRegister rhs = DRegisterFrom(locations->InAt(1));
+  vixl32::DRegister dst = DRegisterFrom(locations->Out());
+  switch (instruction->GetPackedType()) {
+    case Primitive::kPrimByte:
+      DCHECK_EQ(8u, instruction->GetVectorLength());
+      if (instruction->IsUnsigned()) {
+        __ Vmin(DataTypeValue::U8, dst, lhs, rhs);
+      } else {
+        __ Vmin(DataTypeValue::S8, dst, lhs, rhs);
+      }
+      break;
+    case Primitive::kPrimChar:
+    case Primitive::kPrimShort:
+      DCHECK_EQ(4u, instruction->GetVectorLength());
+      if (instruction->IsUnsigned()) {
+        __ Vmin(DataTypeValue::U16, dst, lhs, rhs);
+      } else {
+        __ Vmin(DataTypeValue::S16, dst, lhs, rhs);
+      }
+      break;
+    case Primitive::kPrimInt:
+      DCHECK_EQ(2u, instruction->GetVectorLength());
+      if (instruction->IsUnsigned()) {
+        __ Vmin(DataTypeValue::U32, dst, lhs, rhs);
+      } else {
+        __ Vmin(DataTypeValue::S32, dst, lhs, rhs);
+      }
+      break;
+    default:
+      LOG(FATAL) << "Unsupported SIMD type";
+      UNREACHABLE();
+  }
 }
 
 void LocationsBuilderARMVIXL::VisitVecMax(HVecMax* instruction) {
@@ -169,7 +403,40 @@
 }
 
 void InstructionCodeGeneratorARMVIXL::VisitVecMax(HVecMax* instruction) {
-  LOG(FATAL) << "No SIMD for " << instruction->GetId();
+  LocationSummary* locations = instruction->GetLocations();
+  vixl32::DRegister lhs = DRegisterFrom(locations->InAt(0));
+  vixl32::DRegister rhs = DRegisterFrom(locations->InAt(1));
+  vixl32::DRegister dst = DRegisterFrom(locations->Out());
+  switch (instruction->GetPackedType()) {
+    case Primitive::kPrimByte:
+      DCHECK_EQ(8u, instruction->GetVectorLength());
+      if (instruction->IsUnsigned()) {
+        __ Vmax(DataTypeValue::U8, dst, lhs, rhs);
+      } else {
+        __ Vmax(DataTypeValue::S8, dst, lhs, rhs);
+      }
+      break;
+    case Primitive::kPrimChar:
+    case Primitive::kPrimShort:
+      DCHECK_EQ(4u, instruction->GetVectorLength());
+      if (instruction->IsUnsigned()) {
+        __ Vmax(DataTypeValue::U16, dst, lhs, rhs);
+      } else {
+        __ Vmax(DataTypeValue::S16, dst, lhs, rhs);
+      }
+      break;
+    case Primitive::kPrimInt:
+      DCHECK_EQ(2u, instruction->GetVectorLength());
+      if (instruction->IsUnsigned()) {
+        __ Vmax(DataTypeValue::U32, dst, lhs, rhs);
+      } else {
+        __ Vmax(DataTypeValue::S32, dst, lhs, rhs);
+      }
+      break;
+    default:
+      LOG(FATAL) << "Unsupported SIMD type";
+      UNREACHABLE();
+  }
 }
 
 void LocationsBuilderARMVIXL::VisitVecAnd(HVecAnd* instruction) {
@@ -177,7 +444,22 @@
 }
 
 void InstructionCodeGeneratorARMVIXL::VisitVecAnd(HVecAnd* instruction) {
-  LOG(FATAL) << "No SIMD for " << instruction->GetId();
+  LocationSummary* locations = instruction->GetLocations();
+  vixl32::DRegister lhs = DRegisterFrom(locations->InAt(0));
+  vixl32::DRegister rhs = DRegisterFrom(locations->InAt(1));
+  vixl32::DRegister dst = DRegisterFrom(locations->Out());
+  switch (instruction->GetPackedType()) {
+    case Primitive::kPrimBoolean:
+    case Primitive::kPrimByte:
+    case Primitive::kPrimChar:
+    case Primitive::kPrimShort:
+    case Primitive::kPrimInt:
+      __ Vand(I8, dst, lhs, rhs);
+      break;
+    default:
+      LOG(FATAL) << "Unsupported SIMD type";
+      UNREACHABLE();
+  }
 }
 
 void LocationsBuilderARMVIXL::VisitVecAndNot(HVecAndNot* instruction) {
@@ -193,7 +475,22 @@
 }
 
 void InstructionCodeGeneratorARMVIXL::VisitVecOr(HVecOr* instruction) {
-  LOG(FATAL) << "No SIMD for " << instruction->GetId();
+  LocationSummary* locations = instruction->GetLocations();
+  vixl32::DRegister lhs = DRegisterFrom(locations->InAt(0));
+  vixl32::DRegister rhs = DRegisterFrom(locations->InAt(1));
+  vixl32::DRegister dst = DRegisterFrom(locations->Out());
+  switch (instruction->GetPackedType()) {
+    case Primitive::kPrimBoolean:
+    case Primitive::kPrimByte:
+    case Primitive::kPrimChar:
+    case Primitive::kPrimShort:
+    case Primitive::kPrimInt:
+      __ Vorr(I8, dst, lhs, rhs);
+      break;
+    default:
+      LOG(FATAL) << "Unsupported SIMD type";
+      UNREACHABLE();
+  }
 }
 
 void LocationsBuilderARMVIXL::VisitVecXor(HVecXor* instruction) {
@@ -201,7 +498,22 @@
 }
 
 void InstructionCodeGeneratorARMVIXL::VisitVecXor(HVecXor* instruction) {
-  LOG(FATAL) << "No SIMD for " << instruction->GetId();
+  LocationSummary* locations = instruction->GetLocations();
+  vixl32::DRegister lhs = DRegisterFrom(locations->InAt(0));
+  vixl32::DRegister rhs = DRegisterFrom(locations->InAt(1));
+  vixl32::DRegister dst = DRegisterFrom(locations->Out());
+  switch (instruction->GetPackedType()) {
+    case Primitive::kPrimBoolean:
+    case Primitive::kPrimByte:
+    case Primitive::kPrimChar:
+    case Primitive::kPrimShort:
+    case Primitive::kPrimInt:
+      __ Veor(I8, dst, lhs, rhs);
+      break;
+    default:
+      LOG(FATAL) << "Unsupported SIMD type";
+      UNREACHABLE();
+  }
 }
 
 // Helper to set up locations for vector shift operations.
@@ -212,8 +524,9 @@
     case Primitive::kPrimChar:
     case Primitive::kPrimShort:
     case Primitive::kPrimInt:
-    case Primitive::kPrimLong:
-      DCHECK(locations);
+      locations->SetInAt(0, Location::RequiresFpuRegister());
+      locations->SetInAt(1, Location::ConstantLocation(instruction->InputAt(1)->AsConstant()));
+      locations->SetOut(Location::RequiresFpuRegister(), Location::kNoOutputOverlap);
       break;
     default:
       LOG(FATAL) << "Unsupported SIMD type";
@@ -226,7 +539,28 @@
 }
 
 void InstructionCodeGeneratorARMVIXL::VisitVecShl(HVecShl* instruction) {
-  LOG(FATAL) << "No SIMD for " << instruction->GetId();
+  LocationSummary* locations = instruction->GetLocations();
+  vixl32::DRegister lhs = DRegisterFrom(locations->InAt(0));
+  vixl32::DRegister dst = DRegisterFrom(locations->Out());
+  int32_t value = locations->InAt(1).GetConstant()->AsIntConstant()->GetValue();
+  switch (instruction->GetPackedType()) {
+    case Primitive::kPrimByte:
+      DCHECK_EQ(8u, instruction->GetVectorLength());
+      __ Vshl(I8, dst, lhs, value);
+      break;
+    case Primitive::kPrimChar:
+    case Primitive::kPrimShort:
+      DCHECK_EQ(4u, instruction->GetVectorLength());
+      __ Vshl(I16, dst, lhs, value);
+      break;
+    case Primitive::kPrimInt:
+      DCHECK_EQ(2u, instruction->GetVectorLength());
+      __ Vshl(I32, dst, lhs, value);
+      break;
+    default:
+      LOG(FATAL) << "Unsupported SIMD type";
+      UNREACHABLE();
+  }
 }
 
 void LocationsBuilderARMVIXL::VisitVecShr(HVecShr* instruction) {
@@ -234,7 +568,28 @@
 }
 
 void InstructionCodeGeneratorARMVIXL::VisitVecShr(HVecShr* instruction) {
-  LOG(FATAL) << "No SIMD for " << instruction->GetId();
+  LocationSummary* locations = instruction->GetLocations();
+  vixl32::DRegister lhs = DRegisterFrom(locations->InAt(0));
+  vixl32::DRegister dst = DRegisterFrom(locations->Out());
+  int32_t value = locations->InAt(1).GetConstant()->AsIntConstant()->GetValue();
+  switch (instruction->GetPackedType()) {
+    case Primitive::kPrimByte:
+      DCHECK_EQ(8u, instruction->GetVectorLength());
+      __ Vshr(DataTypeValue::S8, dst, lhs, value);
+      break;
+    case Primitive::kPrimChar:
+    case Primitive::kPrimShort:
+      DCHECK_EQ(4u, instruction->GetVectorLength());
+      __ Vshr(DataTypeValue::S16, dst, lhs, value);
+      break;
+    case Primitive::kPrimInt:
+      DCHECK_EQ(2u, instruction->GetVectorLength());
+      __ Vshr(DataTypeValue::S32, dst, lhs, value);
+      break;
+    default:
+      LOG(FATAL) << "Unsupported SIMD type";
+      UNREACHABLE();
+  }
 }
 
 void LocationsBuilderARMVIXL::VisitVecUShr(HVecUShr* instruction) {
@@ -242,7 +597,28 @@
 }
 
 void InstructionCodeGeneratorARMVIXL::VisitVecUShr(HVecUShr* instruction) {
-  LOG(FATAL) << "No SIMD for " << instruction->GetId();
+  LocationSummary* locations = instruction->GetLocations();
+  vixl32::DRegister lhs = DRegisterFrom(locations->InAt(0));
+  vixl32::DRegister dst = DRegisterFrom(locations->Out());
+  int32_t value = locations->InAt(1).GetConstant()->AsIntConstant()->GetValue();
+  switch (instruction->GetPackedType()) {
+    case Primitive::kPrimByte:
+      DCHECK_EQ(8u, instruction->GetVectorLength());
+      __ Vshr(DataTypeValue::U8, dst, lhs, value);
+      break;
+    case Primitive::kPrimChar:
+    case Primitive::kPrimShort:
+      DCHECK_EQ(4u, instruction->GetVectorLength());
+      __ Vshr(DataTypeValue::U16, dst, lhs, value);
+      break;
+    case Primitive::kPrimInt:
+      DCHECK_EQ(2u, instruction->GetVectorLength());
+      __ Vshr(DataTypeValue::U32, dst, lhs, value);
+      break;
+    default:
+      LOG(FATAL) << "Unsupported SIMD type";
+      UNREACHABLE();
+  }
 }
 
 void LocationsBuilderARMVIXL::VisitVecMultiplyAccumulate(HVecMultiplyAccumulate* instr) {
@@ -253,20 +629,187 @@
   LOG(FATAL) << "No SIMD for " << instr->GetId();
 }
 
+// Return whether the vector memory access operation is guaranteed to be word-aligned (ARM word
+// size equals to 4).
+static bool IsWordAligned(HVecMemoryOperation* instruction) {
+  return instruction->GetAlignment().IsAlignedAt(4u);
+}
+
+// Helper to set up locations for vector memory operations.
+static void CreateVecMemLocations(ArenaAllocator* arena,
+                                  HVecMemoryOperation* instruction,
+                                  bool is_load) {
+  LocationSummary* locations = new (arena) LocationSummary(instruction);
+  switch (instruction->GetPackedType()) {
+    case Primitive::kPrimBoolean:
+    case Primitive::kPrimByte:
+    case Primitive::kPrimChar:
+    case Primitive::kPrimShort:
+    case Primitive::kPrimInt:
+      locations->SetInAt(0, Location::RequiresRegister());
+      locations->SetInAt(1, Location::RegisterOrConstant(instruction->InputAt(1)));
+      if (is_load) {
+        locations->SetOut(Location::RequiresFpuRegister());
+      } else {
+        locations->SetInAt(2, Location::RequiresFpuRegister());
+      }
+      break;
+    default:
+      LOG(FATAL) << "Unsupported SIMD type";
+      UNREACHABLE();
+  }
+}
+
+// Helper to set up locations for vector memory operations. Returns the memory operand and,
+// if used, sets the output parameter scratch to a temporary register used in this operand,
+// so that the client can release it right after the memory operand use.
+MemOperand InstructionCodeGeneratorARMVIXL::VecAddress(
+        HVecMemoryOperation* instruction,
+        UseScratchRegisterScope* temps_scope,
+        /*out*/ vixl32::Register* scratch) {
+  LocationSummary* locations = instruction->GetLocations();
+  vixl32::Register base = InputRegisterAt(instruction, 0);
+
+  Location index = locations->InAt(1);
+  size_t size = Primitive::ComponentSize(instruction->GetPackedType());
+  uint32_t offset = mirror::Array::DataOffset(size).Uint32Value();
+  size_t shift = ComponentSizeShiftWidth(size);
+
+  // HIntermediateAddress optimization is only applied for scalar ArrayGet and ArraySet.
+  DCHECK(!instruction->InputAt(0)->IsIntermediateAddress());
+
+  if (index.IsConstant()) {
+    offset += Int64ConstantFrom(index) << shift;
+    return MemOperand(base, offset);
+  } else {
+    *scratch = temps_scope->Acquire();
+    __ Add(*scratch, base, Operand(RegisterFrom(index), ShiftType::LSL, shift));
+
+    return MemOperand(*scratch, offset);
+  }
+}
+
+AlignedMemOperand InstructionCodeGeneratorARMVIXL::VecAddressUnaligned(
+        HVecMemoryOperation* instruction,
+        UseScratchRegisterScope* temps_scope,
+        /*out*/ vixl32::Register* scratch) {
+  LocationSummary* locations = instruction->GetLocations();
+  vixl32::Register base = InputRegisterAt(instruction, 0);
+
+  Location index = locations->InAt(1);
+  size_t size = Primitive::ComponentSize(instruction->GetPackedType());
+  uint32_t offset = mirror::Array::DataOffset(size).Uint32Value();
+  size_t shift = ComponentSizeShiftWidth(size);
+
+  // HIntermediateAddress optimization is only applied for scalar ArrayGet and ArraySet.
+  DCHECK(!instruction->InputAt(0)->IsIntermediateAddress());
+
+  if (index.IsConstant()) {
+    offset += Int64ConstantFrom(index) << shift;
+    __ Add(*scratch, base, offset);
+  } else {
+    *scratch = temps_scope->Acquire();
+    __ Add(*scratch, base, offset);
+    __ Add(*scratch, *scratch, Operand(RegisterFrom(index), ShiftType::LSL, shift));
+  }
+  return AlignedMemOperand(*scratch, kNoAlignment);
+}
+
 void LocationsBuilderARMVIXL::VisitVecLoad(HVecLoad* instruction) {
-  LOG(FATAL) << "No SIMD for " << instruction->GetId();
+  CreateVecMemLocations(GetGraph()->GetArena(), instruction, /*is_load*/ true);
 }
 
 void InstructionCodeGeneratorARMVIXL::VisitVecLoad(HVecLoad* instruction) {
-  LOG(FATAL) << "No SIMD for " << instruction->GetId();
+  vixl32::DRegister reg = OutputDRegister(instruction);
+  UseScratchRegisterScope temps(GetVIXLAssembler());
+  vixl32::Register scratch;
+
+  DCHECK(instruction->GetPackedType() != Primitive::kPrimChar || !instruction->IsStringCharAt());
+
+  switch (instruction->GetPackedType()) {
+    case Primitive::kPrimBoolean:
+    case Primitive::kPrimByte:
+      DCHECK_EQ(8u, instruction->GetVectorLength());
+      if (IsWordAligned(instruction)) {
+        __ Vldr(reg, VecAddress(instruction, &temps, &scratch));
+      } else {
+        __ Vld1(Untyped8,
+            NeonRegisterList(reg, kMultipleLanes),
+            VecAddressUnaligned(instruction, &temps, &scratch));
+      }
+      break;
+    case Primitive::kPrimChar:
+    case Primitive::kPrimShort:
+      DCHECK_EQ(4u, instruction->GetVectorLength());
+      if (IsWordAligned(instruction)) {
+        __ Vldr(reg, VecAddress(instruction, &temps, &scratch));
+      } else {
+        __ Vld1(Untyped16,
+            NeonRegisterList(reg, kMultipleLanes),
+            VecAddressUnaligned(instruction, &temps, &scratch));
+      }
+      break;
+    case Primitive::kPrimInt:
+      DCHECK_EQ(2u, instruction->GetVectorLength());
+      if (IsWordAligned(instruction)) {
+        __ Vldr(reg, VecAddress(instruction, &temps, &scratch));
+      } else {
+        __ Vld1(Untyped32,
+            NeonRegisterList(reg, kMultipleLanes),
+            VecAddressUnaligned(instruction, &temps, &scratch));
+      }
+      break;
+    default:
+      LOG(FATAL) << "Unsupported SIMD type";
+      UNREACHABLE();
+  }
 }
 
 void LocationsBuilderARMVIXL::VisitVecStore(HVecStore* instruction) {
-  LOG(FATAL) << "No SIMD for " << instruction->GetId();
+  CreateVecMemLocations(GetGraph()->GetArena(), instruction, /*is_load*/ false);
 }
 
 void InstructionCodeGeneratorARMVIXL::VisitVecStore(HVecStore* instruction) {
-  LOG(FATAL) << "No SIMD for " << instruction->GetId();
+  vixl32::DRegister reg = InputDRegisterAt(instruction, 2);
+  UseScratchRegisterScope temps(GetVIXLAssembler());
+  vixl32::Register scratch;
+  switch (instruction->GetPackedType()) {
+    case Primitive::kPrimBoolean:
+    case Primitive::kPrimByte:
+      DCHECK_EQ(8u, instruction->GetVectorLength());
+      if (IsWordAligned(instruction)) {
+        __ Vstr(reg, VecAddress(instruction, &temps, &scratch));
+      } else {
+        __ Vst1(Untyped8,
+                NeonRegisterList(reg, kMultipleLanes),
+                VecAddressUnaligned(instruction, &temps, &scratch));
+      }
+      break;
+    case Primitive::kPrimChar:
+    case Primitive::kPrimShort:
+      DCHECK_EQ(4u, instruction->GetVectorLength());
+      if (IsWordAligned(instruction)) {
+        __ Vstr(reg, VecAddress(instruction, &temps, &scratch));
+      } else {
+        __ Vst1(Untyped16,
+                NeonRegisterList(reg, kMultipleLanes),
+                VecAddressUnaligned(instruction, &temps, &scratch));
+      }
+      break;
+    case Primitive::kPrimInt:
+      DCHECK_EQ(2u, instruction->GetVectorLength());
+      if (IsWordAligned(instruction)) {
+        __ Vstr(reg, VecAddress(instruction, &temps, &scratch));
+      } else {
+        __ Vst1(Untyped32,
+                NeonRegisterList(reg, kMultipleLanes),
+                VecAddressUnaligned(instruction, &temps, &scratch));
+      }
+      break;
+    default:
+      LOG(FATAL) << "Unsupported SIMD type";
+      UNREACHABLE();
+  }
 }
 
 #undef __
diff --git a/compiler/optimizing/loop_optimization.cc b/compiler/optimizing/loop_optimization.cc
index b61d7b8..83f31c7 100644
--- a/compiler/optimizing/loop_optimization.cc
+++ b/compiler/optimizing/loop_optimization.cc
@@ -1097,6 +1097,23 @@
   switch (compiler_driver_->GetInstructionSet()) {
     case kArm:
     case kThumb2:
+      // Allow vectorization for all ARM devices, because Android assumes that
+      // ARM 32-bit always supports advanced SIMD.
+      switch (type) {
+        case Primitive::kPrimBoolean:
+        case Primitive::kPrimByte:
+          *restrictions |= kNoDiv;
+          return TrySetVectorLength(8);
+        case Primitive::kPrimChar:
+        case Primitive::kPrimShort:
+          *restrictions |= kNoDiv | kNoStringCharAt;
+          return TrySetVectorLength(4);
+        case Primitive::kPrimInt:
+          *restrictions |= kNoDiv;
+          return TrySetVectorLength(2);
+        default:
+          break;
+      }
       return false;
     case kArm64:
       // Allow vectorization for all ARM devices, because Android assumes that
diff --git a/compiler/optimizing/scheduler.cc b/compiler/optimizing/scheduler.cc
index 147fa1c..5ad011d 100644
--- a/compiler/optimizing/scheduler.cc
+++ b/compiler/optimizing/scheduler.cc
@@ -66,28 +66,215 @@
   return false;
 }
 
+size_t SchedulingGraph::ArrayAccessHeapLocation(HInstruction* array, HInstruction* index) const {
+  DCHECK(heap_location_collector_ != nullptr);
+  size_t heap_loc = heap_location_collector_->GetArrayAccessHeapLocation(array, index);
+  // This array access should be analyzed and added to HeapLocationCollector before.
+  DCHECK(heap_loc != HeapLocationCollector::kHeapLocationNotFound);
+  return heap_loc;
+}
 
-// Check whether `node` depends on `other`, taking into account `SideEffect`
-// information and `CanThrow` information.
-static bool HasSideEffectDependency(const HInstruction* node, const HInstruction* other) {
-  if (MayHaveReorderingDependency(node->GetSideEffects(), other->GetSideEffects())) {
+bool SchedulingGraph::ArrayAccessMayAlias(const HInstruction* node,
+                                          const HInstruction* other) const {
+  DCHECK(heap_location_collector_ != nullptr);
+  size_t node_heap_loc = ArrayAccessHeapLocation(node->InputAt(0), node->InputAt(1));
+  size_t other_heap_loc = ArrayAccessHeapLocation(other->InputAt(0), other->InputAt(1));
+
+  // For example: arr[0] and arr[0]
+  if (node_heap_loc == other_heap_loc) {
     return true;
   }
 
+  // For example: arr[0] and arr[i]
+  if (heap_location_collector_->MayAlias(node_heap_loc, other_heap_loc)) {
+    return true;
+  }
+
+  return false;
+}
+
+static bool IsArrayAccess(const HInstruction* instruction) {
+  return instruction->IsArrayGet() || instruction->IsArraySet();
+}
+
+static bool IsInstanceFieldAccess(const HInstruction* instruction) {
+  return instruction->IsInstanceFieldGet() ||
+         instruction->IsInstanceFieldSet() ||
+         instruction->IsUnresolvedInstanceFieldGet() ||
+         instruction->IsUnresolvedInstanceFieldSet();
+}
+
+static bool IsStaticFieldAccess(const HInstruction* instruction) {
+  return instruction->IsStaticFieldGet() ||
+         instruction->IsStaticFieldSet() ||
+         instruction->IsUnresolvedStaticFieldGet() ||
+         instruction->IsUnresolvedStaticFieldSet();
+}
+
+static bool IsResolvedFieldAccess(const HInstruction* instruction) {
+  return instruction->IsInstanceFieldGet() ||
+         instruction->IsInstanceFieldSet() ||
+         instruction->IsStaticFieldGet() ||
+         instruction->IsStaticFieldSet();
+}
+
+static bool IsUnresolvedFieldAccess(const HInstruction* instruction) {
+  return instruction->IsUnresolvedInstanceFieldGet() ||
+         instruction->IsUnresolvedInstanceFieldSet() ||
+         instruction->IsUnresolvedStaticFieldGet() ||
+         instruction->IsUnresolvedStaticFieldSet();
+}
+
+static bool IsFieldAccess(const HInstruction* instruction) {
+  return IsResolvedFieldAccess(instruction) || IsUnresolvedFieldAccess(instruction);
+}
+
+static const FieldInfo* GetFieldInfo(const HInstruction* instruction) {
+  if (instruction->IsInstanceFieldGet()) {
+    return &instruction->AsInstanceFieldGet()->GetFieldInfo();
+  } else if (instruction->IsInstanceFieldSet()) {
+    return &instruction->AsInstanceFieldSet()->GetFieldInfo();
+  } else if (instruction->IsStaticFieldGet()) {
+    return &instruction->AsStaticFieldGet()->GetFieldInfo();
+  } else if (instruction->IsStaticFieldSet()) {
+    return &instruction->AsStaticFieldSet()->GetFieldInfo();
+  } else {
+    LOG(FATAL) << "Unexpected field access type";
+    UNREACHABLE();
+  }
+}
+
+size_t SchedulingGraph::FieldAccessHeapLocation(HInstruction* obj, const FieldInfo* field) const {
+  DCHECK(obj != nullptr);
+  DCHECK(field != nullptr);
+  DCHECK(heap_location_collector_ != nullptr);
+
+  size_t heap_loc = heap_location_collector_->FindHeapLocationIndex(
+     heap_location_collector_->FindReferenceInfoOf(
+         heap_location_collector_->HuntForOriginalReference(obj)),
+     field->GetFieldOffset().SizeValue(),
+     nullptr,
+     field->GetDeclaringClassDefIndex());
+  // This field access should be analyzed and added to HeapLocationCollector before.
+  DCHECK(heap_loc != HeapLocationCollector::kHeapLocationNotFound);
+
+  return heap_loc;
+}
+
+bool SchedulingGraph::FieldAccessMayAlias(const HInstruction* node,
+                                          const HInstruction* other) const {
+  DCHECK(heap_location_collector_ != nullptr);
+
+  // Static and instance field accesses should not alias.
+  if ((IsInstanceFieldAccess(node) && IsStaticFieldAccess(other)) ||
+      (IsStaticFieldAccess(node) && IsInstanceFieldAccess(other))) {
+    return false;
+  }
+
+  // If either of the field accesses is unresolved.
+  if (IsUnresolvedFieldAccess(node) || IsUnresolvedFieldAccess(other)) {
+    // Conservatively treat these two accesses may alias.
+    return true;
+  }
+
+  // If both fields accesses are resolved.
+  const FieldInfo* node_field = GetFieldInfo(node);
+  const FieldInfo* other_field = GetFieldInfo(other);
+
+  size_t node_loc = FieldAccessHeapLocation(node->InputAt(0), node_field);
+  size_t other_loc = FieldAccessHeapLocation(other->InputAt(0), other_field);
+
+  if (node_loc == other_loc) {
+    return true;
+  }
+
+  if (!heap_location_collector_->MayAlias(node_loc, other_loc)) {
+    return false;
+  }
+
+  return true;
+}
+
+bool SchedulingGraph::HasMemoryDependency(const HInstruction* node,
+                                          const HInstruction* other) const {
+  if (!MayHaveReorderingDependency(node->GetSideEffects(), other->GetSideEffects())) {
+    return false;
+  }
+
+  if (heap_location_collector_ == nullptr ||
+      heap_location_collector_->GetNumberOfHeapLocations() == 0) {
+    // Without HeapLocation information from load store analysis,
+    // we cannot do further disambiguation analysis on these two instructions.
+    // Just simply say that those two instructions have memory dependency.
+    return true;
+  }
+
+  if (IsArrayAccess(node) && IsArrayAccess(other)) {
+    return ArrayAccessMayAlias(node, other);
+  }
+  if (IsFieldAccess(node) && IsFieldAccess(other)) {
+    return FieldAccessMayAlias(node, other);
+  }
+
+  // TODO(xueliang): LSA to support alias analysis among HVecLoad, HVecStore and ArrayAccess
+  if (node->IsVecMemoryOperation() && other->IsVecMemoryOperation()) {
+    return true;
+  }
+  if (node->IsVecMemoryOperation() && IsArrayAccess(other)) {
+    return true;
+  }
+  if (IsArrayAccess(node) && other->IsVecMemoryOperation()) {
+    return true;
+  }
+
+  // Heap accesses of different kinds should not alias.
+  if (IsArrayAccess(node) && IsFieldAccess(other)) {
+    return false;
+  }
+  if (IsFieldAccess(node) && IsArrayAccess(other)) {
+    return false;
+  }
+  if (node->IsVecMemoryOperation() && IsFieldAccess(other)) {
+    return false;
+  }
+  if (IsFieldAccess(node) && other->IsVecMemoryOperation()) {
+    return false;
+  }
+
+  // We conservatively treat all other cases having dependency,
+  // for example, Invoke and ArrayGet.
+  return true;
+}
+
+bool SchedulingGraph::HasExceptionDependency(const HInstruction* node,
+                                             const HInstruction* other) const {
   if (other->CanThrow() && node->GetSideEffects().DoesAnyWrite()) {
     return true;
   }
-
   if (other->GetSideEffects().DoesAnyWrite() && node->CanThrow()) {
     return true;
   }
-
   if (other->CanThrow() && node->CanThrow()) {
     return true;
   }
 
-  // Check side-effect dependency between ArrayGet and BoundsCheck.
-  if (node->IsArrayGet() && other->IsBoundsCheck() && node->InputAt(1) == other) {
+  // Above checks should cover all cases where we cannot reorder two
+  // instructions which may throw exception.
+  return false;
+}
+
+// Check whether `node` depends on `other`, taking into account `SideEffect`
+// information and `CanThrow` information.
+bool SchedulingGraph::HasSideEffectDependency(const HInstruction* node,
+                                              const HInstruction* other) const {
+  if (HasMemoryDependency(node, other)) {
+    return true;
+  }
+
+  // Even if above memory dependency check has passed, it is still necessary to
+  // check dependencies between instructions that can throw and instructions
+  // that write to memory.
+  if (HasExceptionDependency(node, other)) {
     return true;
   }
 
@@ -379,6 +566,14 @@
 
   // Build the scheduling graph.
   scheduling_graph_.Clear();
+
+  // Only perform LSA/HeapLocation analysis on the basic block that
+  // is going to get instruction scheduled.
+  HeapLocationCollector heap_location_collector(block->GetGraph());
+  heap_location_collector.VisitBasicBlock(block);
+  heap_location_collector.BuildAliasingMatrix();
+  scheduling_graph_.SetHeapLocationCollector(heap_location_collector);
+
   for (HBackwardInstructionIterator it(block->GetInstructions()); !it.Done(); it.Advance()) {
     HInstruction* instruction = it.Current();
     CHECK_EQ(instruction->GetBlock(), block)
@@ -606,7 +801,9 @@
   // Avoid compilation error when compiling for unsupported instruction set.
   UNUSED(only_optimize_loop_blocks);
   UNUSED(schedule_randomly);
+  UNUSED(codegen_);
 #endif
+
   switch (instruction_set_) {
 #ifdef ART_ENABLE_CODEGEN_arm64
     case kArm64: {
diff --git a/compiler/optimizing/scheduler.h b/compiler/optimizing/scheduler.h
index 73e8087..930a2c8 100644
--- a/compiler/optimizing/scheduler.h
+++ b/compiler/optimizing/scheduler.h
@@ -21,6 +21,7 @@
 
 #include "base/time_utils.h"
 #include "driver/compiler_driver.h"
+#include "load_store_analysis.h"
 #include "nodes.h"
 #include "optimization.h"
 #include "code_generator.h"
@@ -246,7 +247,8 @@
       : scheduler_(scheduler),
         arena_(arena),
         contains_scheduling_barrier_(false),
-        nodes_map_(arena_->Adapter(kArenaAllocScheduler)) {}
+        nodes_map_(arena_->Adapter(kArenaAllocScheduler)),
+        heap_location_collector_(nullptr) {}
 
   SchedulingNode* AddNode(HInstruction* instr, bool is_scheduling_barrier = false) {
     SchedulingNode* node = new (arena_) SchedulingNode(instr, arena_, is_scheduling_barrier);
@@ -261,6 +263,10 @@
     contains_scheduling_barrier_ = false;
   }
 
+  void SetHeapLocationCollector(const HeapLocationCollector& heap_location_collector) {
+    heap_location_collector_ = &heap_location_collector;
+  }
+
   SchedulingNode* GetNode(const HInstruction* instr) const {
     auto it = nodes_map_.Find(instr);
     if (it == nodes_map_.end()) {
@@ -294,6 +300,13 @@
   void AddOtherDependency(SchedulingNode* node, SchedulingNode* dependency) {
     AddDependency(node, dependency, /*is_data_dependency*/false);
   }
+  bool HasMemoryDependency(const HInstruction* node, const HInstruction* other) const;
+  bool HasExceptionDependency(const HInstruction* node, const HInstruction* other) const;
+  bool HasSideEffectDependency(const HInstruction* node, const HInstruction* other) const;
+  bool ArrayAccessMayAlias(const HInstruction* node, const HInstruction* other) const;
+  bool FieldAccessMayAlias(const HInstruction* node, const HInstruction* other) const;
+  size_t ArrayAccessHeapLocation(HInstruction* array, HInstruction* index) const;
+  size_t FieldAccessHeapLocation(HInstruction* obj, const FieldInfo* field) const;
 
   // Add dependencies nodes for the given `HInstruction`: inputs, environments, and side-effects.
   void AddDependencies(HInstruction* instruction, bool is_scheduling_barrier = false);
@@ -305,6 +318,8 @@
   bool contains_scheduling_barrier_;
 
   ArenaHashMap<const HInstruction*, SchedulingNode*> nodes_map_;
+
+  const HeapLocationCollector* heap_location_collector_;
 };
 
 /*
@@ -482,10 +497,9 @@
 
   static constexpr const char* kInstructionScheduling = "scheduler";
 
+ private:
   CodeGenerator* const codegen_;
   const InstructionSet instruction_set_;
-
- private:
   DISALLOW_COPY_AND_ASSIGN(HInstructionScheduling);
 };
 
diff --git a/compiler/optimizing/scheduler_test.cc b/compiler/optimizing/scheduler_test.cc
index d87600a..cc7222d 100644
--- a/compiler/optimizing/scheduler_test.cc
+++ b/compiler/optimizing/scheduler_test.cc
@@ -18,6 +18,7 @@
 #include "builder.h"
 #include "codegen_test_utils.h"
 #include "common_compiler_test.h"
+#include "load_store_analysis.h"
 #include "nodes.h"
 #include "optimizing_unit_test.h"
 #include "pc_relative_fixups_x86.h"
@@ -193,6 +194,147 @@
     }
   }
 
+  void TestDependencyGraphOnAliasingArrayAccesses(HScheduler* scheduler) {
+    HBasicBlock* entry = new (&allocator_) HBasicBlock(graph_);
+    graph_->AddBlock(entry);
+    graph_->SetEntryBlock(entry);
+    graph_->BuildDominatorTree();
+
+    HInstruction* arr = new (&allocator_) HParameterValue(graph_->GetDexFile(),
+                                                          dex::TypeIndex(0),
+                                                          0,
+                                                          Primitive::kPrimNot);
+    HInstruction* i = new (&allocator_) HParameterValue(graph_->GetDexFile(),
+                                                        dex::TypeIndex(1),
+                                                        1,
+                                                        Primitive::kPrimInt);
+    HInstruction* j = new (&allocator_) HParameterValue(graph_->GetDexFile(),
+                                                        dex::TypeIndex(1),
+                                                        1,
+                                                        Primitive::kPrimInt);
+    HInstruction* object = new (&allocator_) HParameterValue(graph_->GetDexFile(),
+                                                             dex::TypeIndex(0),
+                                                             0,
+                                                             Primitive::kPrimNot);
+    HInstruction* c0 = graph_->GetIntConstant(0);
+    HInstruction* c1 = graph_->GetIntConstant(1);
+    HInstruction* add0 = new (&allocator_) HAdd(Primitive::kPrimInt, i, c0);
+    HInstruction* add1 = new (&allocator_) HAdd(Primitive::kPrimInt, i, c1);
+    HInstruction* sub0 = new (&allocator_) HSub(Primitive::kPrimInt, i, c0);
+    HInstruction* sub1 = new (&allocator_) HSub(Primitive::kPrimInt, i, c1);
+    HInstruction* arr_set_0 = new (&allocator_) HArraySet(arr, c0, c0, Primitive::kPrimInt, 0);
+    HInstruction* arr_set_1 = new (&allocator_) HArraySet(arr, c1, c0, Primitive::kPrimInt, 0);
+    HInstruction* arr_set_i = new (&allocator_) HArraySet(arr, i, c0, Primitive::kPrimInt, 0);
+    HInstruction* arr_set_add0 = new (&allocator_) HArraySet(arr, add0, c0, Primitive::kPrimInt, 0);
+    HInstruction* arr_set_add1 = new (&allocator_) HArraySet(arr, add1, c0, Primitive::kPrimInt, 0);
+    HInstruction* arr_set_sub0 = new (&allocator_) HArraySet(arr, sub0, c0, Primitive::kPrimInt, 0);
+    HInstruction* arr_set_sub1 = new (&allocator_) HArraySet(arr, sub1, c0, Primitive::kPrimInt, 0);
+    HInstruction* arr_set_j = new (&allocator_) HArraySet(arr, j, c0, Primitive::kPrimInt, 0);
+    HInstanceFieldSet* set_field10 = new (&allocator_) HInstanceFieldSet(object,
+                                                                         c1,
+                                                                         nullptr,
+                                                                         Primitive::kPrimInt,
+                                                                         MemberOffset(10),
+                                                                         false,
+                                                                         kUnknownFieldIndex,
+                                                                         kUnknownClassDefIndex,
+                                                                         graph_->GetDexFile(),
+                                                                         0);
+
+    HInstruction* block_instructions[] = {arr,
+                                          i,
+                                          j,
+                                          object,
+                                          add0,
+                                          add1,
+                                          sub0,
+                                          sub1,
+                                          arr_set_0,
+                                          arr_set_1,
+                                          arr_set_i,
+                                          arr_set_add0,
+                                          arr_set_add1,
+                                          arr_set_sub0,
+                                          arr_set_sub1,
+                                          arr_set_j,
+                                          set_field10};
+
+    for (HInstruction* instr : block_instructions) {
+      entry->AddInstruction(instr);
+    }
+
+    SchedulingGraph scheduling_graph(scheduler, graph_->GetArena());
+    HeapLocationCollector heap_location_collector(graph_);
+    heap_location_collector.VisitBasicBlock(entry);
+    heap_location_collector.BuildAliasingMatrix();
+    scheduling_graph.SetHeapLocationCollector(heap_location_collector);
+
+    for (HInstruction* instr : ReverseRange(block_instructions)) {
+      // Build scheduling graph with memory access aliasing information
+      // from LSA/heap_location_collector.
+      scheduling_graph.AddNode(instr);
+    }
+
+    // LSA/HeapLocationCollector should see those ArraySet instructions.
+    ASSERT_EQ(heap_location_collector.GetNumberOfHeapLocations(), 9U);
+    ASSERT_TRUE(heap_location_collector.HasHeapStores());
+
+    // Test queries on HeapLocationCollector's aliasing matrix after load store analysis.
+    // HeapLocationCollector and SchedulingGraph should report consistent relationships.
+    size_t loc1 = HeapLocationCollector::kHeapLocationNotFound;
+    size_t loc2 = HeapLocationCollector::kHeapLocationNotFound;
+
+    // Test side effect dependency: array[0] and array[1]
+    loc1 = heap_location_collector.GetArrayAccessHeapLocation(arr, c0);
+    loc2 = heap_location_collector.GetArrayAccessHeapLocation(arr, c1);
+    ASSERT_FALSE(heap_location_collector.MayAlias(loc1, loc2));
+    ASSERT_FALSE(scheduling_graph.HasImmediateOtherDependency(arr_set_1, arr_set_0));
+
+    // Test side effect dependency based on LSA analysis: array[i] and array[j]
+    loc1 = heap_location_collector.GetArrayAccessHeapLocation(arr, i);
+    loc2 = heap_location_collector.GetArrayAccessHeapLocation(arr, j);
+    ASSERT_TRUE(heap_location_collector.MayAlias(loc1, loc2));
+    ASSERT_TRUE(scheduling_graph.HasImmediateOtherDependency(arr_set_j, arr_set_i));
+
+    // Test side effect dependency based on LSA analysis: array[i] and array[i+0]
+    loc1 = heap_location_collector.GetArrayAccessHeapLocation(arr, i);
+    loc2 = heap_location_collector.GetArrayAccessHeapLocation(arr, add0);
+    ASSERT_TRUE(heap_location_collector.MayAlias(loc1, loc2));
+    ASSERT_TRUE(scheduling_graph.HasImmediateOtherDependency(arr_set_add0, arr_set_i));
+
+    // Test side effect dependency based on LSA analysis: array[i] and array[i-0]
+    loc1 = heap_location_collector.GetArrayAccessHeapLocation(arr, i);
+    loc2 = heap_location_collector.GetArrayAccessHeapLocation(arr, sub0);
+    ASSERT_TRUE(heap_location_collector.MayAlias(loc1, loc2));
+    ASSERT_TRUE(scheduling_graph.HasImmediateOtherDependency(arr_set_sub0, arr_set_i));
+
+    // Test side effect dependency based on LSA analysis: array[i] and array[i+1]
+    loc1 = heap_location_collector.GetArrayAccessHeapLocation(arr, i);
+    loc2 = heap_location_collector.GetArrayAccessHeapLocation(arr, add1);
+    ASSERT_FALSE(heap_location_collector.MayAlias(loc1, loc2));
+    ASSERT_FALSE(scheduling_graph.HasImmediateOtherDependency(arr_set_add1, arr_set_i));
+
+    // Test side effect dependency based on LSA analysis: array[i+1] and array[i-1]
+    loc1 = heap_location_collector.GetArrayAccessHeapLocation(arr, add1);
+    loc2 = heap_location_collector.GetArrayAccessHeapLocation(arr, sub1);
+    ASSERT_FALSE(heap_location_collector.MayAlias(loc1, loc2));
+    ASSERT_FALSE(scheduling_graph.HasImmediateOtherDependency(arr_set_sub1, arr_set_add1));
+
+    // Test side effect dependency based on LSA analysis: array[j] and all others array accesses
+    ASSERT_TRUE(scheduling_graph.HasImmediateOtherDependency(arr_set_j, arr_set_i));
+    ASSERT_TRUE(scheduling_graph.HasImmediateOtherDependency(arr_set_j, arr_set_add0));
+    ASSERT_TRUE(scheduling_graph.HasImmediateOtherDependency(arr_set_j, arr_set_sub0));
+    ASSERT_TRUE(scheduling_graph.HasImmediateOtherDependency(arr_set_j, arr_set_add1));
+    ASSERT_TRUE(scheduling_graph.HasImmediateOtherDependency(arr_set_j, arr_set_sub1));
+
+    // Test that ArraySet and FieldSet should not have side effect dependency
+    ASSERT_FALSE(scheduling_graph.HasImmediateOtherDependency(arr_set_i, set_field10));
+    ASSERT_FALSE(scheduling_graph.HasImmediateOtherDependency(arr_set_j, set_field10));
+
+    // Exercise target specific scheduler and SchedulingLatencyVisitor.
+    scheduler->Schedule(graph_);
+  }
+
   ArenaPool pool_;
   ArenaAllocator allocator_;
   HGraph* graph_;
@@ -204,15 +346,28 @@
   arm64::HSchedulerARM64 scheduler(&allocator_, &critical_path_selector);
   TestBuildDependencyGraphAndSchedule(&scheduler);
 }
+
+TEST_F(SchedulerTest, ArrayAccessAliasingARM64) {
+  CriticalPathSchedulingNodeSelector critical_path_selector;
+  arm64::HSchedulerARM64 scheduler(&allocator_, &critical_path_selector);
+  TestDependencyGraphOnAliasingArrayAccesses(&scheduler);
+}
 #endif
 
 #if defined(ART_ENABLE_CODEGEN_arm)
-TEST_F(SchedulerTest, DependencyGrapAndSchedulerARM) {
+TEST_F(SchedulerTest, DependencyGraphAndSchedulerARM) {
   CriticalPathSchedulingNodeSelector critical_path_selector;
   arm::SchedulingLatencyVisitorARM arm_latency_visitor(/*CodeGenerator*/ nullptr);
   arm::HSchedulerARM scheduler(&allocator_, &critical_path_selector, &arm_latency_visitor);
   TestBuildDependencyGraphAndSchedule(&scheduler);
 }
+
+TEST_F(SchedulerTest, ArrayAccessAliasingARM) {
+  CriticalPathSchedulingNodeSelector critical_path_selector;
+  arm::SchedulingLatencyVisitorARM arm_latency_visitor(/*CodeGenerator*/ nullptr);
+  arm::HSchedulerARM scheduler(&allocator_, &critical_path_selector, &arm_latency_visitor);
+  TestDependencyGraphOnAliasingArrayAccesses(&scheduler);
+}
 #endif
 
 TEST_F(SchedulerTest, RandomScheduling) {
diff --git a/dexdump/dexdump.cc b/dexdump/dexdump.cc
index df0169f..8437ea5 100644
--- a/dexdump/dexdump.cc
+++ b/dexdump/dexdump.cc
@@ -1582,31 +1582,53 @@
 
 static void dumpMethodHandle(const DexFile* pDexFile, u4 idx) {
   const DexFile::MethodHandleItem& mh = pDexFile->GetMethodHandle(idx);
+  const char* type = nullptr;
+  bool is_instance = false;
   bool is_invoke = false;
-  const char* type;
   switch (static_cast<DexFile::MethodHandleType>(mh.method_handle_type_)) {
     case DexFile::MethodHandleType::kStaticPut:
       type = "put-static";
+      is_instance = false;
+      is_invoke = false;
       break;
     case DexFile::MethodHandleType::kStaticGet:
       type = "get-static";
+      is_instance = false;
+      is_invoke = false;
       break;
     case DexFile::MethodHandleType::kInstancePut:
       type = "put-instance";
+      is_instance = true;
+      is_invoke = false;
       break;
     case DexFile::MethodHandleType::kInstanceGet:
       type = "get-instance";
+      is_instance = true;
+      is_invoke = false;
       break;
     case DexFile::MethodHandleType::kInvokeStatic:
       type = "invoke-static";
+      is_instance = false;
       is_invoke = true;
       break;
     case DexFile::MethodHandleType::kInvokeInstance:
       type = "invoke-instance";
+      is_instance = true;
       is_invoke = true;
       break;
     case DexFile::MethodHandleType::kInvokeConstructor:
       type = "invoke-constructor";
+      is_instance = true;
+      is_invoke = true;
+      break;
+    case DexFile::MethodHandleType::kInvokeDirect:
+      type = "invoke-direct";
+      is_instance = true;
+      is_invoke = true;
+      break;
+    case DexFile::MethodHandleType::kInvokeInterface:
+      type = "invoke-interface";
+      is_instance = true;
       is_invoke = true;
       break;
   }
@@ -1614,16 +1636,26 @@
   const char* declaring_class;
   const char* member;
   std::string member_type;
-  if (is_invoke) {
-    const DexFile::MethodId& method_id = pDexFile->GetMethodId(mh.field_or_method_idx_);
-    declaring_class = pDexFile->GetMethodDeclaringClassDescriptor(method_id);
-    member = pDexFile->GetMethodName(method_id);
-    member_type = pDexFile->GetMethodSignature(method_id).ToString();
+  if (type != nullptr) {
+    if (is_invoke) {
+      const DexFile::MethodId& method_id = pDexFile->GetMethodId(mh.field_or_method_idx_);
+      declaring_class = pDexFile->GetMethodDeclaringClassDescriptor(method_id);
+      member = pDexFile->GetMethodName(method_id);
+      member_type = pDexFile->GetMethodSignature(method_id).ToString();
+    } else {
+      const DexFile::FieldId& field_id = pDexFile->GetFieldId(mh.field_or_method_idx_);
+      declaring_class = pDexFile->GetFieldDeclaringClassDescriptor(field_id);
+      member = pDexFile->GetFieldName(field_id);
+      member_type = pDexFile->GetFieldTypeDescriptor(field_id);
+    }
+    if (is_instance) {
+      member_type = android::base::StringPrintf("(%s%s", declaring_class, member_type.c_str() + 1);
+    }
   } else {
-    const DexFile::FieldId& field_id = pDexFile->GetFieldId(mh.field_or_method_idx_);
-    declaring_class = pDexFile->GetFieldDeclaringClassDescriptor(field_id);
-    member = pDexFile->GetFieldName(field_id);
-    member_type = pDexFile->GetFieldTypeDescriptor(field_id);
+    type = "?";
+    declaring_class = "?";
+    member = "?";
+    member_type = "?";
   }
 
   if (gOptions.outputFormat == OUTPUT_PLAIN) {
@@ -1661,12 +1693,12 @@
   it.Next();
 
   if (gOptions.outputFormat == OUTPUT_PLAIN) {
-    fprintf(gOutFile, "Call site #%u:\n", idx);
+    fprintf(gOutFile, "Call site #%u: // offset %u\n", idx, call_site_id.data_off_);
     fprintf(gOutFile, "  link_argument[0] : %u (MethodHandle)\n", method_handle_idx);
     fprintf(gOutFile, "  link_argument[1] : %s (String)\n", method_name);
     fprintf(gOutFile, "  link_argument[2] : %s (MethodType)\n", method_type.c_str());
   } else {
-    fprintf(gOutFile, "<call_site index=\"%u\">\n", idx);
+    fprintf(gOutFile, "<call_site index=\"%u\" offset=\"%u\">\n", idx, call_site_id.data_off_);
     fprintf(gOutFile,
             "<link_argument index=\"0\" type=\"MethodHandle\" value=\"%u\"/>\n",
             method_handle_idx);
diff --git a/dexlayout/dex_ir.cc b/dexlayout/dex_ir.cc
index a200d8d..5913832 100644
--- a/dexlayout/dex_ir.cc
+++ b/dexlayout/dex_ir.cc
@@ -793,8 +793,10 @@
       static_cast<DexFile::MethodHandleType>(disk_method_handle.method_handle_type_);
   bool is_invoke = type == DexFile::MethodHandleType::kInvokeStatic ||
                    type == DexFile::MethodHandleType::kInvokeInstance ||
-                   type == DexFile::MethodHandleType::kInvokeConstructor;
-  static_assert(DexFile::MethodHandleType::kLast == DexFile::MethodHandleType::kInvokeConstructor,
+                   type == DexFile::MethodHandleType::kInvokeConstructor ||
+                   type == DexFile::MethodHandleType::kInvokeDirect ||
+                   type == DexFile::MethodHandleType::kInvokeInterface;
+  static_assert(DexFile::MethodHandleType::kLast == DexFile::MethodHandleType::kInvokeInterface,
                 "Unexpected method handle types.");
   IndexedItem* field_or_method_id;
   if (is_invoke) {
diff --git a/runtime/Android.bp b/runtime/Android.bp
index 46307dd..0dfc60d 100644
--- a/runtime/Android.bp
+++ b/runtime/Android.bp
@@ -461,6 +461,7 @@
         "object_callbacks.h",
         "process_state.h",
         "stack.h",
+        "suspend_reason.h",
         "thread.h",
         "thread_state.h",
         "ti/agent.h",
diff --git a/runtime/arch/arm64/quick_entrypoints_arm64.S b/runtime/arch/arm64/quick_entrypoints_arm64.S
index ee91277..138dbf9 100644
--- a/runtime/arch/arm64/quick_entrypoints_arm64.S
+++ b/runtime/arch/arm64/quick_entrypoints_arm64.S
@@ -2669,19 +2669,19 @@
     RESTORE_TWO_REGS x14, x15, 112
     RESTORE_TWO_REGS x18, x19, 128    // Skip x16, x17, i.e. IP0, IP1.
     RESTORE_REG      xLR,      144    // Restore return address.
-    // Save all potentially live caller-save floating-point registers.
-    stp   d0, d1,   [sp, #160]
-    stp   d2, d3,   [sp, #176]
-    stp   d4, d5,   [sp, #192]
-    stp   d6, d7,   [sp, #208]
-    stp   d16, d17, [sp, #224]
-    stp   d18, d19, [sp, #240]
-    stp   d20, d21, [sp, #256]
-    stp   d22, d23, [sp, #272]
-    stp   d24, d25, [sp, #288]
-    stp   d26, d27, [sp, #304]
-    stp   d28, d29, [sp, #320]
-    stp   d30, d31, [sp, #336]
+    // Restore caller-save floating-point registers.
+    ldp   d0, d1,   [sp, #160]
+    ldp   d2, d3,   [sp, #176]
+    ldp   d4, d5,   [sp, #192]
+    ldp   d6, d7,   [sp, #208]
+    ldp   d16, d17, [sp, #224]
+    ldp   d18, d19, [sp, #240]
+    ldp   d20, d21, [sp, #256]
+    ldp   d22, d23, [sp, #272]
+    ldp   d24, d25, [sp, #288]
+    ldp   d26, d27, [sp, #304]
+    ldp   d28, d29, [sp, #320]
+    ldp   d30, d31, [sp, #336]
 
     ldr   x0, [lr, #\ldr_offset]      // Load the instruction.
     adr   xIP1, .Lmark_introspection_return_switch
diff --git a/runtime/class_linker.cc b/runtime/class_linker.cc
index 10e0bd2..7aab9de 100644
--- a/runtime/class_linker.cc
+++ b/runtime/class_linker.cc
@@ -8256,65 +8256,139 @@
   const DexFile* const dex_file = referrer->GetDexFile();
   const DexFile::MethodHandleItem& mh = dex_file->GetMethodHandle(method_handle_idx);
 
-  union {
-    ArtField* field;
-    ArtMethod* method;
-    uintptr_t field_or_method;
-  } target;
-  uint32_t num_params;
-  mirror::MethodHandle::Kind kind;
+  ArtField* target_field = nullptr;
+  ArtMethod* target_method = nullptr;
+
   DexFile::MethodHandleType handle_type =
       static_cast<DexFile::MethodHandleType>(mh.method_handle_type_);
   switch (handle_type) {
     case DexFile::MethodHandleType::kStaticPut: {
+      target_field = ResolveField(mh.field_or_method_idx_, referrer, true /* is_static */);
+      break;
+    }
+    case DexFile::MethodHandleType::kStaticGet: {
+      target_field = ResolveField(mh.field_or_method_idx_, referrer, true /* is_static */);
+      break;
+    }
+    case DexFile::MethodHandleType::kInstancePut: {
+      target_field = ResolveField(mh.field_or_method_idx_, referrer, false /* is_static */);
+      break;
+    }
+    case DexFile::MethodHandleType::kInstanceGet: {
+      target_field = ResolveField(mh.field_or_method_idx_, referrer, false /* is_static */);
+      break;
+    }
+    case DexFile::MethodHandleType::kInvokeStatic: {
+      target_method = ResolveMethod<kNoICCECheckForCache>(self,
+                                                          mh.field_or_method_idx_,
+                                                          referrer,
+                                                          InvokeType::kStatic);
+      break;
+    }
+    case DexFile::MethodHandleType::kInvokeInstance: {
+      target_method = ResolveMethod<kNoICCECheckForCache>(self,
+                                                          mh.field_or_method_idx_,
+                                                          referrer,
+                                                          InvokeType::kVirtual);
+      break;
+    }
+    case DexFile::MethodHandleType::kInvokeConstructor: {
+      UNIMPLEMENTED(FATAL) << "Invoke constructor is implemented as a transform.";
+      break;
+    }
+    case DexFile::MethodHandleType::kInvokeDirect: {
+      target_method = ResolveMethod<kNoICCECheckForCache>(self,
+                                                          mh.field_or_method_idx_,
+                                                          referrer,
+                                                          InvokeType::kDirect);
+      break;
+    }
+    case DexFile::MethodHandleType::kInvokeInterface: {
+      target_method = ResolveMethod<kNoICCECheckForCache>(self,
+                                                          mh.field_or_method_idx_,
+                                                          referrer,
+                                                          InvokeType::kInterface);
+      break;
+    }
+  }
+
+  if (target_field != nullptr) {
+    ObjPtr<mirror::Class> target_class = target_field->GetDeclaringClass();
+    ObjPtr<mirror::Class> referring_class = referrer->GetDeclaringClass();
+    if (!referring_class->CanAccessMember(target_class, target_field->GetAccessFlags())) {
+      ThrowIllegalAccessErrorField(referring_class, target_field);
+      return nullptr;
+    }
+  } else if (target_method != nullptr) {
+    ObjPtr<mirror::Class> target_class = target_method->GetDeclaringClass();
+    ObjPtr<mirror::Class> referring_class = referrer->GetDeclaringClass();
+    if (!referring_class->CanAccessMember(target_class, target_method->GetAccessFlags())) {
+      ThrowIllegalAccessErrorMethod(referring_class, target_method);
+      return nullptr;
+    }
+  } else {
+    // Common check for resolution failure.
+    DCHECK(Thread::Current()->IsExceptionPending());
+    return nullptr;
+  }
+
+  // Determine the kind and number of parameters after it's safe to
+  // follow the field or method pointer.
+  mirror::MethodHandle::Kind kind;
+  uint32_t num_params;
+  switch (handle_type) {
+    case DexFile::MethodHandleType::kStaticPut: {
       kind = mirror::MethodHandle::Kind::kStaticPut;
-      target.field = ResolveField(mh.field_or_method_idx_, referrer, true /* is_static */);
       num_params = 1;
       break;
     }
     case DexFile::MethodHandleType::kStaticGet: {
       kind = mirror::MethodHandle::Kind::kStaticGet;
-      target.field = ResolveField(mh.field_or_method_idx_, referrer, true /* is_static */);
       num_params = 0;
       break;
     }
     case DexFile::MethodHandleType::kInstancePut: {
       kind = mirror::MethodHandle::Kind::kInstancePut;
-      target.field = ResolveField(mh.field_or_method_idx_, referrer, false /* is_static */);
       num_params = 2;
       break;
     }
     case DexFile::MethodHandleType::kInstanceGet: {
       kind = mirror::MethodHandle::Kind::kInstanceGet;
-      target.field = ResolveField(mh.field_or_method_idx_, referrer, false /* is_static */);
       num_params = 1;
       break;
     }
     case DexFile::MethodHandleType::kInvokeStatic: {
       kind = mirror::MethodHandle::Kind::kInvokeStatic;
-      target.method = ResolveMethod<kNoICCECheckForCache>(self,
-                                                          mh.field_or_method_idx_,
-                                                          referrer,
-                                                          InvokeType::kStatic);
       uint32_t shorty_length;
-      target.method->GetShorty(&shorty_length);
-      num_params = shorty_length - 1;  // Remove 1 for return value.
+      target_method->GetShorty(&shorty_length);
+      num_params = shorty_length - 1;  // Remove 1 for the return value.
       break;
     }
     case DexFile::MethodHandleType::kInvokeInstance: {
       kind = mirror::MethodHandle::Kind::kInvokeVirtual;
-      target.method = ResolveMethod<kNoICCECheckForCache>(self,
-                                                          mh.field_or_method_idx_,
-                                                          referrer,
-                                                          InvokeType::kVirtual);
       uint32_t shorty_length;
-      target.method->GetShorty(&shorty_length);
-      num_params = shorty_length - 1;  // Remove 1 for return value.
+      target_method->GetShorty(&shorty_length);
+      num_params = shorty_length;  // Add 1 for the receiver, remove 1 for the return value.
       break;
     }
     case DexFile::MethodHandleType::kInvokeConstructor: {
       UNIMPLEMENTED(FATAL) << "Invoke constructor is implemented as a transform.";
       num_params = 0;
+      break;
+    }
+    case DexFile::MethodHandleType::kInvokeDirect: {
+      kind = mirror::MethodHandle::Kind::kInvokeDirect;
+      uint32_t shorty_length;
+      target_method->GetShorty(&shorty_length);
+      num_params = shorty_length;  // Add 1 for the receiver, remove 1 for the return value.
+      break;
+    }
+    case DexFile::MethodHandleType::kInvokeInterface: {
+      kind = mirror::MethodHandle::Kind::kInvokeInterface;
+      uint32_t shorty_length;
+      target_method->GetShorty(&shorty_length);
+      num_params = shorty_length;  // Add 1 for the receiver, remove 1 for the return value.
+      break;
     }
   }
 
@@ -8331,44 +8405,51 @@
   Handle<mirror::Class> return_type;
   switch (handle_type) {
     case DexFile::MethodHandleType::kStaticPut: {
-      method_params->Set(0, target.field->GetType<true>());
+      method_params->Set(0, target_field->GetType<true>());
       return_type = hs.NewHandle(FindPrimitiveClass('V'));
       break;
     }
     case DexFile::MethodHandleType::kStaticGet: {
-      return_type = hs.NewHandle(target.field->GetType<true>());
+      return_type = hs.NewHandle(target_field->GetType<true>());
       break;
     }
     case DexFile::MethodHandleType::kInstancePut: {
-      method_params->Set(0, target.field->GetDeclaringClass());
-      method_params->Set(1, target.field->GetType<true>());
+      method_params->Set(0, target_field->GetDeclaringClass());
+      method_params->Set(1, target_field->GetType<true>());
       return_type = hs.NewHandle(FindPrimitiveClass('V'));
       break;
     }
     case DexFile::MethodHandleType::kInstanceGet: {
-      method_params->Set(0, target.field->GetDeclaringClass());
-      return_type = hs.NewHandle(target.field->GetType<true>());
+      method_params->Set(0, target_field->GetDeclaringClass());
+      return_type = hs.NewHandle(target_field->GetType<true>());
       break;
     }
-    case DexFile::MethodHandleType::kInvokeStatic:
-    case DexFile::MethodHandleType::kInvokeInstance: {
+    case DexFile::MethodHandleType::kInvokeDirect:
+    case DexFile::MethodHandleType::kInvokeInstance:
+    case DexFile::MethodHandleType::kInvokeInterface:
+    case DexFile::MethodHandleType::kInvokeStatic: {
       // TODO(oth): This will not work for varargs methods as this
       // requires instantiating a Transformer. This resolution step
       // would be best done in managed code rather than in the run
       // time (b/35235705)
       Handle<mirror::DexCache> dex_cache(hs.NewHandle(referrer->GetDexCache()));
       Handle<mirror::ClassLoader> class_loader(hs.NewHandle(referrer->GetClassLoader()));
-      DexFileParameterIterator it(*dex_file, target.method->GetPrototype());
-      for (int32_t i = 0; it.HasNext(); i++, it.Next()) {
+      DexFileParameterIterator it(*dex_file, target_method->GetPrototype());
+      int32_t index = 0;
+      if (handle_type != DexFile::MethodHandleType::kInvokeStatic) {
+        method_params->Set(index++, target_method->GetDeclaringClass());
+      }
+      while (it.HasNext()) {
         const dex::TypeIndex type_idx = it.GetTypeIdx();
         mirror::Class* klass = ResolveType(*dex_file, type_idx, dex_cache, class_loader);
         if (nullptr == klass) {
           DCHECK(self->IsExceptionPending());
           return nullptr;
         }
-        method_params->Set(i, klass);
+        method_params->Set(index++, klass);
+        it.Next();
       }
-      return_type = hs.NewHandle(target.method->GetReturnType(true));
+      return_type = hs.NewHandle(target_method->GetReturnType(true));
       break;
     }
     case DexFile::MethodHandleType::kInvokeConstructor: {
@@ -8388,7 +8469,14 @@
     DCHECK(self->IsExceptionPending());
     return nullptr;
   }
-  return mirror::MethodHandleImpl::Create(self, target.field_or_method, kind, mt);
+
+  uintptr_t target;
+  if (target_field != nullptr) {
+    target = reinterpret_cast<uintptr_t>(target_field);
+  } else {
+    target = reinterpret_cast<uintptr_t>(target_method);
+  }
+  return mirror::MethodHandleImpl::Create(self, target, kind, mt);
 }
 
 bool ClassLinker::IsQuickResolutionStub(const void* entry_point) const {
diff --git a/runtime/debugger.cc b/runtime/debugger.cc
index cc12439..c94a8e0 100644
--- a/runtime/debugger.cc
+++ b/runtime/debugger.cc
@@ -2446,7 +2446,7 @@
   ThreadList* thread_list = Runtime::Current()->GetThreadList();
   Thread* thread = thread_list->SuspendThreadByPeer(peer.get(),
                                                     request_suspension,
-                                                    /* debug_suspension */ true,
+                                                    SuspendReason::kForDebugger,
                                                     &timed_out);
   if (thread != nullptr) {
     return JDWP::ERR_NONE;
@@ -2477,7 +2477,7 @@
     needs_resume = thread->GetDebugSuspendCount() > 0;
   }
   if (needs_resume) {
-    Runtime::Current()->GetThreadList()->Resume(thread, true);
+    Runtime::Current()->GetThreadList()->Resume(thread, SuspendReason::kForDebugger);
   }
 }
 
@@ -3694,7 +3694,7 @@
           ThreadList* const thread_list = Runtime::Current()->GetThreadList();
           suspended_thread = thread_list->SuspendThreadByPeer(thread_peer,
                                                               /* request_suspension */ true,
-                                                              /* debug_suspension */ true,
+                                                              SuspendReason::kForDebugger,
                                                               &timed_out);
         }
         if (suspended_thread == nullptr) {
@@ -3718,7 +3718,7 @@
 
   ~ScopedDebuggerThreadSuspension() {
     if (other_suspend_) {
-      Runtime::Current()->GetThreadList()->Resume(thread_, true);
+      Runtime::Current()->GetThreadList()->Resume(thread_, SuspendReason::kForDebugger);
     }
   }
 
@@ -4040,7 +4040,7 @@
     thread_list->UndoDebuggerSuspensions();
   } else {
     VLOG(jdwp) << "      Resuming event thread only";
-    thread_list->Resume(targetThread, true);
+    thread_list->Resume(targetThread, SuspendReason::kForDebugger);
   }
 
   return JDWP::ERR_NONE;
diff --git a/runtime/dex_file.h b/runtime/dex_file.h
index 81a39af..eb3b210 100644
--- a/runtime/dex_file.h
+++ b/runtime/dex_file.h
@@ -272,7 +272,9 @@
                                   // can be any non-static method on any class (or interface) except
                                   // for “<init>”.
     kInvokeConstructor = 0x0006,  // an invoker for a given constructor.
-    kLast = kInvokeConstructor
+    kInvokeDirect      = 0x0007,  // an invoker for a direct (special) method.
+    kInvokeInterface   = 0x0008,  // an invoker for an interface method.
+    kLast = kInvokeInterface
   };
 
   // raw method_handle_item
diff --git a/runtime/dex_file_verifier.cc b/runtime/dex_file_verifier.cc
index c18ab47..c5c4eda 100644
--- a/runtime/dex_file_verifier.cc
+++ b/runtime/dex_file_verifier.cc
@@ -2483,7 +2483,9 @@
     }
     case DexFile::MethodHandleType::kInvokeStatic:
     case DexFile::MethodHandleType::kInvokeInstance:
-    case DexFile::MethodHandleType::kInvokeConstructor: {
+    case DexFile::MethodHandleType::kInvokeConstructor:
+    case DexFile::MethodHandleType::kInvokeDirect:
+    case DexFile::MethodHandleType::kInvokeInterface: {
       LOAD_METHOD(method, index, "method_handle_item method_idx", return false);
       break;
     }
diff --git a/runtime/gc/space/region_space-inl.h b/runtime/gc/space/region_space-inl.h
index 82e8f20..2e67f34 100644
--- a/runtime/gc/space/region_space-inl.h
+++ b/runtime/gc/space/region_space-inl.h
@@ -66,13 +66,15 @@
     }
     Region* r = AllocateRegion(kForEvac);
     if (LIKELY(r != nullptr)) {
+      obj = r->Alloc(num_bytes, bytes_allocated, usable_size, bytes_tl_bulk_allocated);
+      CHECK(obj != nullptr);
+      // Do our allocation before setting the region, this makes sure no threads race ahead
+      // and fill in the region before we allocate the object. b/63153464
       if (kForEvac) {
         evac_region_ = r;
       } else {
         current_region_ = r;
       }
-      obj = r->Alloc(num_bytes, bytes_allocated, usable_size, bytes_tl_bulk_allocated);
-      CHECK(obj != nullptr);
       return obj;
     }
   } else {
diff --git a/runtime/gc/space/region_space.cc b/runtime/gc/space/region_space.cc
index 1f7bd09..b8f1e8f 100644
--- a/runtime/gc/space/region_space.cc
+++ b/runtime/gc/space/region_space.cc
@@ -251,6 +251,13 @@
   evac_region_ = &full_region_;
 }
 
+static void ZeroAndProtectRegion(uint8_t* begin, uint8_t* end) {
+  ZeroAndReleasePages(begin, end - begin);
+  if (kProtectClearedRegions) {
+    mprotect(begin, end - begin, PROT_NONE);
+  }
+}
+
 void RegionSpace::ClearFromSpace(uint64_t* cleared_bytes, uint64_t* cleared_objects) {
   DCHECK(cleared_bytes != nullptr);
   DCHECK(cleared_objects != nullptr);
@@ -269,7 +276,7 @@
   auto clear_region = [&clear_block_begin, &clear_block_end](Region* r) {
     r->Clear(/*zero_and_release_pages*/false);
     if (clear_block_end != r->Begin()) {
-      ZeroAndReleasePages(clear_block_begin, clear_block_end - clear_block_begin);
+      ZeroAndProtectRegion(clear_block_begin, clear_block_end);
       clear_block_begin = r->Begin();
     }
     clear_block_end = r->End();
@@ -548,10 +555,7 @@
   alloc_time_ = 0;
   live_bytes_ = static_cast<size_t>(-1);
   if (zero_and_release_pages) {
-    ZeroAndReleasePages(begin_, end_ - begin_);
-  }
-  if (kProtectClearedRegions) {
-    mprotect(begin_, end_ - begin_, PROT_NONE);
+    ZeroAndProtectRegion(begin_, end_);
   }
   is_newly_allocated_ = false;
   is_a_tlab_ = false;
diff --git a/runtime/interpreter/interpreter_common.cc b/runtime/interpreter/interpreter_common.cc
index 1b36c3f..b57e2b2 100644
--- a/runtime/interpreter/interpreter_common.cc
+++ b/runtime/interpreter/interpreter_common.cc
@@ -640,7 +640,7 @@
   const DexFile* dex_file = referrer->GetDexFile();
   const DexFile::CallSiteIdItem& csi = dex_file->GetCallSiteId(call_site_idx);
 
-  StackHandleScope<9> hs(self);
+  StackHandleScope<10> hs(self);
   Handle<mirror::ClassLoader> class_loader(hs.NewHandle(referrer->GetClassLoader()));
   Handle<mirror::DexCache> dex_cache(hs.NewHandle(referrer->GetDexCache()));
 
@@ -836,9 +836,13 @@
     return nullptr;
   }
 
-  // Check the target method type matches the method type requested.
-  if (UNLIKELY(!target->GetMethodType()->IsExactMatch(method_type.Get()))) {
-    ThrowWrongMethodTypeException(target->GetMethodType(), method_type.Get());
+  // Check the target method type matches the method type requested modulo the receiver
+  // needs to be compatible rather than exact.
+  Handle<mirror::MethodType> target_method_type = hs.NewHandle(target->GetMethodType());
+  if (UNLIKELY(!target_method_type->IsExactMatch(method_type.Get()) &&
+               !IsParameterTypeConvertible(target_method_type->GetPTypes()->GetWithoutChecks(0),
+                                           method_type->GetPTypes()->GetWithoutChecks(0)))) {
+    ThrowWrongMethodTypeException(target_method_type.Get(), method_type.Get());
     return nullptr;
   }
 
diff --git a/runtime/monitor.cc b/runtime/monitor.cc
index 940afc8..3e3eaae 100644
--- a/runtime/monitor.cc
+++ b/runtime/monitor.cc
@@ -898,7 +898,9 @@
     Thread* owner;
     {
       ScopedThreadSuspension sts(self, kBlocked);
-      owner = thread_list->SuspendThreadByThreadId(owner_thread_id, false, &timed_out);
+      owner = thread_list->SuspendThreadByThreadId(owner_thread_id,
+                                                   SuspendReason::kInternal,
+                                                   &timed_out);
     }
     if (owner != nullptr) {
       // We succeeded in suspending the thread, check the lock's status didn't change.
@@ -908,7 +910,7 @@
         // Go ahead and inflate the lock.
         Inflate(self, owner, obj.Get(), hash_code);
       }
-      thread_list->Resume(owner, false);
+      thread_list->Resume(owner, SuspendReason::kInternal);
     }
     self->SetMonitorEnterObject(nullptr);
   }
diff --git a/runtime/native/dalvik_system_VMStack.cc b/runtime/native/dalvik_system_VMStack.cc
index e86e64e..7d2d0e5 100644
--- a/runtime/native/dalvik_system_VMStack.cc
+++ b/runtime/native/dalvik_system_VMStack.cc
@@ -51,7 +51,10 @@
     ScopedThreadSuspension sts(soa.Self(), kNative);
     ThreadList* thread_list = Runtime::Current()->GetThreadList();
     bool timed_out;
-    Thread* thread = thread_list->SuspendThreadByPeer(peer, true, false, &timed_out);
+    Thread* thread = thread_list->SuspendThreadByPeer(peer,
+                                                      /* request_suspension */ true,
+                                                      SuspendReason::kInternal,
+                                                      &timed_out);
     if (thread != nullptr) {
       // Must be runnable to create returned array.
       {
@@ -59,7 +62,7 @@
         trace = thread->CreateInternalStackTrace<false>(soa);
       }
       // Restart suspended thread.
-      thread_list->Resume(thread, false);
+      thread_list->Resume(thread, SuspendReason::kInternal);
     } else if (timed_out) {
       LOG(ERROR) << "Trying to get thread's stack failed as the thread failed to suspend within a "
           "generous timeout.";
diff --git a/runtime/native/java_lang_Thread.cc b/runtime/native/java_lang_Thread.cc
index e4d1705..8b76327 100644
--- a/runtime/native/java_lang_Thread.cc
+++ b/runtime/native/java_lang_Thread.cc
@@ -146,13 +146,16 @@
   ThreadList* thread_list = Runtime::Current()->GetThreadList();
   bool timed_out;
   // Take suspend thread lock to avoid races with threads trying to suspend this one.
-  Thread* thread = thread_list->SuspendThreadByPeer(peer, true, false, &timed_out);
+  Thread* thread = thread_list->SuspendThreadByPeer(peer,
+                                                    /* request_suspension */ true,
+                                                    SuspendReason::kInternal,
+                                                    &timed_out);
   if (thread != nullptr) {
     {
       ScopedObjectAccess soa(env);
       thread->SetThreadName(name.c_str());
     }
-    thread_list->Resume(thread, false);
+    thread_list->Resume(thread, SuspendReason::kInternal);
   } else if (timed_out) {
     LOG(ERROR) << "Trying to set thread name to '" << name.c_str() << "' failed as the thread "
         "failed to suspend within a generous timeout.";
diff --git a/runtime/native/org_apache_harmony_dalvik_ddmc_DdmVmInternal.cc b/runtime/native/org_apache_harmony_dalvik_ddmc_DdmVmInternal.cc
index 0a254ac..c516b66 100644
--- a/runtime/native/org_apache_harmony_dalvik_ddmc_DdmVmInternal.cc
+++ b/runtime/native/org_apache_harmony_dalvik_ddmc_DdmVmInternal.cc
@@ -66,7 +66,9 @@
     }
 
     // Suspend thread to build stack trace.
-    Thread* thread = thread_list->SuspendThreadByThreadId(thin_lock_id, false, &timed_out);
+    Thread* thread = thread_list->SuspendThreadByThreadId(thin_lock_id,
+                                                          SuspendReason::kInternal,
+                                                          &timed_out);
     if (thread != nullptr) {
       {
         ScopedObjectAccess soa(env);
@@ -74,7 +76,7 @@
         trace = Thread::InternalStackTraceToStackTraceElementArray(soa, internal_trace);
       }
       // Restart suspended thread.
-      thread_list->Resume(thread, false);
+      thread_list->Resume(thread, SuspendReason::kInternal);
     } else {
       if (timed_out) {
         LOG(ERROR) << "Trying to get thread's stack by id failed as the thread failed to suspend "
diff --git a/runtime/openjdkjvm/OpenjdkJvm.cc b/runtime/openjdkjvm/OpenjdkJvm.cc
index 0b93b07..4560dda 100644
--- a/runtime/openjdkjvm/OpenjdkJvm.cc
+++ b/runtime/openjdkjvm/OpenjdkJvm.cc
@@ -422,14 +422,17 @@
   // Take suspend thread lock to avoid races with threads trying to suspend this one.
   art::Thread* thread;
   {
-    thread = thread_list->SuspendThreadByPeer(jthread, true, false, &timed_out);
+    thread = thread_list->SuspendThreadByPeer(jthread,
+                                              true,
+                                              art::SuspendReason::kInternal,
+                                              &timed_out);
   }
   if (thread != NULL) {
     {
       art::ScopedObjectAccess soa(env);
       thread->SetThreadName(name.c_str());
     }
-    thread_list->Resume(thread, false);
+    thread_list->Resume(thread, art::SuspendReason::kInternal);
   } else if (timed_out) {
     LOG(ERROR) << "Trying to set thread name to '" << name.c_str() << "' failed as the thread "
         "failed to suspend within a generous timeout.";
diff --git a/runtime/openjdkjvmti/ti_class.cc b/runtime/openjdkjvmti/ti_class.cc
index 0ac08d9..b8e7955 100644
--- a/runtime/openjdkjvmti/ti_class.cc
+++ b/runtime/openjdkjvmti/ti_class.cc
@@ -598,6 +598,13 @@
     return ERR(INVALID_CLASS);
   }
 
+  // Check if this class is a temporary class object used for loading. Since we are seeing it the
+  // class must not have been prepared yet since otherwise the fixup would have gotten the jobject
+  // to point to the final class object.
+  if (klass->IsTemp() || klass->IsRetired()) {
+    return ERR(CLASS_NOT_PREPARED);
+  }
+
   if (field_count_ptr == nullptr || fields_ptr == nullptr) {
     return ERR(NULL_POINTER);
   }
@@ -639,6 +646,13 @@
     return ERR(INVALID_CLASS);
   }
 
+  // Check if this class is a temporary class object used for loading. Since we are seeing it the
+  // class must not have been prepared yet since otherwise the fixup would have gotten the jobject
+  // to point to the final class object.
+  if (klass->IsTemp() || klass->IsRetired()) {
+    return ERR(CLASS_NOT_PREPARED);
+  }
+
   if (method_count_ptr == nullptr || methods_ptr == nullptr) {
     return ERR(NULL_POINTER);
   }
diff --git a/runtime/suspend_reason.h b/runtime/suspend_reason.h
new file mode 100644
index 0000000..27c4d32
--- /dev/null
+++ b/runtime/suspend_reason.h
@@ -0,0 +1,37 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef ART_RUNTIME_SUSPEND_REASON_H_
+#define ART_RUNTIME_SUSPEND_REASON_H_
+
+#include <ostream>
+
+namespace art {
+
+// The various reasons that we might be suspending a thread.
+enum class SuspendReason {
+  // Suspending for internal reasons (e.g. GC, stack trace, etc.).
+  // TODO Split this into more descriptive sections.
+  kInternal,
+  // Suspending for debugger (code in Dbg::*, runtime/jdwp/, etc.).
+  kForDebugger,
+};
+
+std::ostream& operator<<(std::ostream& os, const SuspendReason& thread);
+
+}  // namespace art
+
+#endif  // ART_RUNTIME_SUSPEND_REASON_H_
diff --git a/runtime/thread-inl.h b/runtime/thread-inl.h
index 7da15d9..95608b5 100644
--- a/runtime/thread-inl.h
+++ b/runtime/thread-inl.h
@@ -330,12 +330,12 @@
 inline bool Thread::ModifySuspendCount(Thread* self,
                                        int delta,
                                        AtomicInteger* suspend_barrier,
-                                       bool for_debugger) {
+                                       SuspendReason reason) {
   if (delta > 0 && ((kUseReadBarrier && this != self) || suspend_barrier != nullptr)) {
     // When delta > 0 (requesting a suspend), ModifySuspendCountInternal() may fail either if
     // active_suspend_barriers is full or we are in the middle of a thread flip. Retry in a loop.
     while (true) {
-      if (LIKELY(ModifySuspendCountInternal(self, delta, suspend_barrier, for_debugger))) {
+      if (LIKELY(ModifySuspendCountInternal(self, delta, suspend_barrier, reason))) {
         return true;
       } else {
         // Failure means the list of active_suspend_barriers is full or we are in the middle of a
@@ -354,7 +354,7 @@
       }
     }
   } else {
-    return ModifySuspendCountInternal(self, delta, suspend_barrier, for_debugger);
+    return ModifySuspendCountInternal(self, delta, suspend_barrier, reason);
   }
 }
 
diff --git a/runtime/thread.cc b/runtime/thread.cc
index 5edd071..4669e16 100644
--- a/runtime/thread.cc
+++ b/runtime/thread.cc
@@ -1191,10 +1191,10 @@
 bool Thread::ModifySuspendCountInternal(Thread* self,
                                         int delta,
                                         AtomicInteger* suspend_barrier,
-                                        bool for_debugger) {
+                                        SuspendReason reason) {
   if (kIsDebugBuild) {
     DCHECK(delta == -1 || delta == +1 || delta == -tls32_.debug_suspend_count)
-          << delta << " " << tls32_.debug_suspend_count << " " << this;
+          << reason << " " << delta << " " << tls32_.debug_suspend_count << " " << this;
     DCHECK_GE(tls32_.suspend_count, tls32_.debug_suspend_count) << this;
     Locks::thread_suspend_count_lock_->AssertHeld(self);
     if (this != self && !IsSuspended()) {
@@ -1230,8 +1230,12 @@
   }
 
   tls32_.suspend_count += delta;
-  if (for_debugger) {
-    tls32_.debug_suspend_count += delta;
+  switch (reason) {
+    case SuspendReason::kForDebugger:
+      tls32_.debug_suspend_count += delta;
+      break;
+    case SuspendReason::kInternal:
+      break;
   }
 
   if (tls32_.suspend_count == 0) {
@@ -1471,7 +1475,7 @@
     {
       MutexLock mu2(self, *Locks::thread_suspend_count_lock_);
 
-      if (!ModifySuspendCount(self, +1, nullptr, false)) {
+      if (!ModifySuspendCount(self, +1, nullptr, SuspendReason::kInternal)) {
         // Just retry the loop.
         sched_yield();
         continue;
@@ -1496,7 +1500,7 @@
       MutexLock mu2(self, *Locks::thread_suspend_count_lock_);
 
       DCHECK_NE(GetState(), ThreadState::kRunnable);
-      bool updated = ModifySuspendCount(self, -1, nullptr, false);
+      bool updated = ModifySuspendCount(self, -1, nullptr, SuspendReason::kInternal);
       DCHECK(updated);
     }
 
diff --git a/runtime/thread.h b/runtime/thread.h
index 770173e..e785ddc 100644
--- a/runtime/thread.h
+++ b/runtime/thread.h
@@ -40,6 +40,7 @@
 #include "managed_stack.h"
 #include "offsets.h"
 #include "runtime_stats.h"
+#include "suspend_reason.h"
 #include "thread_state.h"
 
 class BacktraceMap;
@@ -244,7 +245,7 @@
   bool ModifySuspendCount(Thread* self,
                           int delta,
                           AtomicInteger* suspend_barrier,
-                          bool for_debugger)
+                          SuspendReason reason)
       WARN_UNUSED
       REQUIRES(Locks::thread_suspend_count_lock_);
 
@@ -1300,7 +1301,7 @@
   bool ModifySuspendCountInternal(Thread* self,
                                   int delta,
                                   AtomicInteger* suspend_barrier,
-                                  bool for_debugger)
+                                  SuspendReason reason)
       WARN_UNUSED
       REQUIRES(Locks::thread_suspend_count_lock_);
 
diff --git a/runtime/thread_list.cc b/runtime/thread_list.cc
index 95aba79..fc767ed 100644
--- a/runtime/thread_list.cc
+++ b/runtime/thread_list.cc
@@ -332,7 +332,7 @@
               // Spurious fail, try again.
               continue;
             }
-            bool updated = thread->ModifySuspendCount(self, +1, nullptr, false);
+            bool updated = thread->ModifySuspendCount(self, +1, nullptr, SuspendReason::kInternal);
             DCHECK(updated);
             suspended_count_modified_threads.push_back(thread);
             break;
@@ -375,7 +375,7 @@
     checkpoint_function->Run(thread);
     {
       MutexLock mu2(self, *Locks::thread_suspend_count_lock_);
-      bool updated = thread->ModifySuspendCount(self, -1, nullptr, false);
+      bool updated = thread->ModifySuspendCount(self, -1, nullptr, SuspendReason::kInternal);
       DCHECK(updated);
     }
   }
@@ -583,7 +583,7 @@
       if ((state == kWaitingForGcThreadFlip || thread->IsTransitioningToRunnable()) &&
           thread->GetSuspendCount() == 1) {
         // The thread will resume right after the broadcast.
-        bool updated = thread->ModifySuspendCount(self, -1, nullptr, false);
+        bool updated = thread->ModifySuspendCount(self, -1, nullptr, SuspendReason::kInternal);
         DCHECK(updated);
         ++runnable_thread_count;
       } else {
@@ -617,7 +617,7 @@
     TimingLogger::ScopedTiming split4("ResumeOtherThreads", collector->GetTimings());
     MutexLock mu2(self, *Locks::thread_suspend_count_lock_);
     for (const auto& thread : other_threads) {
-      bool updated = thread->ModifySuspendCount(self, -1, nullptr, false);
+      bool updated = thread->ModifySuspendCount(self, -1, nullptr, SuspendReason::kInternal);
       DCHECK(updated);
     }
     Thread::resume_cond_->Broadcast(self);
@@ -688,7 +688,7 @@
 void ThreadList::SuspendAllInternal(Thread* self,
                                     Thread* ignore1,
                                     Thread* ignore2,
-                                    bool debug_suspend) {
+                                    SuspendReason reason) {
   Locks::mutator_lock_->AssertNotExclusiveHeld(self);
   Locks::thread_list_lock_->AssertNotHeld(self);
   Locks::thread_suspend_count_lock_->AssertNotHeld(self);
@@ -718,7 +718,7 @@
     MutexLock mu2(self, *Locks::thread_suspend_count_lock_);
     // Update global suspend all state for attaching threads.
     ++suspend_all_count_;
-    if (debug_suspend) {
+    if (reason == SuspendReason::kForDebugger) {
       ++debug_suspend_all_count_;
     }
     pending_threads.StoreRelaxed(list_.size() - num_ignored);
@@ -728,7 +728,7 @@
         continue;
       }
       VLOG(threads) << "requesting thread suspend: " << *thread;
-      bool updated = thread->ModifySuspendCount(self, +1, &pending_threads, debug_suspend);
+      bool updated = thread->ModifySuspendCount(self, +1, &pending_threads, reason);
       DCHECK(updated);
 
       // Must install the pending_threads counter first, then check thread->IsSuspend() and clear
@@ -807,7 +807,7 @@
       if (thread == self) {
         continue;
       }
-      bool updated = thread->ModifySuspendCount(self, -1, nullptr, false);
+      bool updated = thread->ModifySuspendCount(self, -1, nullptr, SuspendReason::kInternal);
       DCHECK(updated);
     }
 
@@ -828,14 +828,13 @@
   }
 }
 
-void ThreadList::Resume(Thread* thread, bool for_debugger) {
+void ThreadList::Resume(Thread* thread, SuspendReason reason) {
   // This assumes there was an ATRACE_BEGIN when we suspended the thread.
   ATRACE_END();
 
   Thread* self = Thread::Current();
   DCHECK_NE(thread, self);
-  VLOG(threads) << "Resume(" << reinterpret_cast<void*>(thread) << ") starting..."
-      << (for_debugger ? " (debugger)" : "");
+  VLOG(threads) << "Resume(" << reinterpret_cast<void*>(thread) << ") starting..." << reason;
 
   {
     // To check Contains.
@@ -850,7 +849,7 @@
           << ") thread not within thread list";
       return;
     }
-    bool updated = thread->ModifySuspendCount(self, -1, nullptr, for_debugger);
+    bool updated = thread->ModifySuspendCount(self, -1, nullptr, reason);
     DCHECK(updated);
   }
 
@@ -882,7 +881,7 @@
 
 Thread* ThreadList::SuspendThreadByPeer(jobject peer,
                                         bool request_suspension,
-                                        bool debug_suspension,
+                                        SuspendReason reason,
                                         bool* timed_out) {
   const uint64_t start_time = NanoTime();
   useconds_t sleep_us = kThreadSuspendInitialSleepUs;
@@ -910,7 +909,7 @@
           bool updated = suspended_thread->ModifySuspendCount(soa.Self(),
                                                               -1,
                                                               nullptr,
-                                                              debug_suspension);
+                                                              reason);
           DCHECK(updated);
         }
         ThreadSuspendByPeerWarning(self,
@@ -937,7 +936,7 @@
           }
           CHECK(suspended_thread == nullptr);
           suspended_thread = thread;
-          bool updated = suspended_thread->ModifySuspendCount(self, +1, nullptr, debug_suspension);
+          bool updated = suspended_thread->ModifySuspendCount(self, +1, nullptr, reason);
           DCHECK(updated);
           request_suspension = false;
         } else {
@@ -973,7 +972,7 @@
             bool updated = suspended_thread->ModifySuspendCount(soa.Self(),
                                                                 -1,
                                                                 nullptr,
-                                                                debug_suspension);
+                                                                reason);
             DCHECK(updated);
           }
           *timed_out = true;
@@ -1002,7 +1001,7 @@
 }
 
 Thread* ThreadList::SuspendThreadByThreadId(uint32_t thread_id,
-                                            bool debug_suspension,
+                                            SuspendReason reason,
                                             bool* timed_out) {
   const uint64_t start_time = NanoTime();
   useconds_t sleep_us = kThreadSuspendInitialSleepUs;
@@ -1047,7 +1046,7 @@
             // which will allow this thread to be suspended.
             continue;
           }
-          bool updated = thread->ModifySuspendCount(self, +1, nullptr, debug_suspension);
+          bool updated = thread->ModifySuspendCount(self, +1, nullptr, reason);
           DCHECK(updated);
           suspended_thread = thread;
         } else {
@@ -1079,7 +1078,7 @@
                                          "Thread suspension timed out",
                                          thread_id);
           if (suspended_thread != nullptr) {
-            bool updated = thread->ModifySuspendCount(soa.Self(), -1, nullptr, debug_suspension);
+            bool updated = thread->ModifySuspendCount(soa.Self(), -1, nullptr, reason);
             DCHECK(updated);
           }
           *timed_out = true;
@@ -1114,7 +1113,7 @@
 
   VLOG(threads) << *self << " SuspendAllForDebugger starting...";
 
-  SuspendAllInternal(self, self, debug_thread, true);
+  SuspendAllInternal(self, self, debug_thread, SuspendReason::kForDebugger);
   // Block on the mutator lock until all Runnable threads release their share of access then
   // immediately unlock again.
 #if HAVE_TIMED_RWLOCK
@@ -1157,7 +1156,7 @@
     // to ensure that we're the only one fiddling with the suspend count
     // though.
     MutexLock mu(self, *Locks::thread_suspend_count_lock_);
-    bool updated = self->ModifySuspendCount(self, +1, nullptr, true);
+    bool updated = self->ModifySuspendCount(self, +1, nullptr, SuspendReason::kForDebugger);
     DCHECK(updated);
     CHECK_GT(self->GetSuspendCount(), 0);
 
@@ -1242,7 +1241,7 @@
           continue;
         }
         VLOG(threads) << "requesting thread resume: " << *thread;
-        bool updated = thread->ModifySuspendCount(self, -1, nullptr, true);
+        bool updated = thread->ModifySuspendCount(self, -1, nullptr, SuspendReason::kForDebugger);
         DCHECK(updated);
       }
     }
@@ -1275,7 +1274,7 @@
       bool suspended = thread->ModifySuspendCount(self,
                                                   -thread->GetDebugSuspendCount(),
                                                   nullptr,
-                                                  true);
+                                                  SuspendReason::kForDebugger);
       DCHECK(suspended);
     }
   }
@@ -1333,7 +1332,7 @@
       // daemons.
       CHECK(thread->IsDaemon()) << *thread;
       if (thread != self) {
-        bool updated = thread->ModifySuspendCount(self, +1, nullptr, false);
+        bool updated = thread->ModifySuspendCount(self, +1, nullptr, SuspendReason::kInternal);
         DCHECK(updated);
         ++daemons_left;
       }
@@ -1394,11 +1393,11 @@
   // Modify suspend count in increments of 1 to maintain invariants in ModifySuspendCount. While
   // this isn't particularly efficient the suspend counts are most commonly 0 or 1.
   for (int delta = debug_suspend_all_count_; delta > 0; delta--) {
-    bool updated = self->ModifySuspendCount(self, +1, nullptr, true);
+    bool updated = self->ModifySuspendCount(self, +1, nullptr, SuspendReason::kForDebugger);
     DCHECK(updated);
   }
   for (int delta = suspend_all_count_ - debug_suspend_all_count_; delta > 0; delta--) {
-    bool updated = self->ModifySuspendCount(self, +1, nullptr, false);
+    bool updated = self->ModifySuspendCount(self, +1, nullptr, SuspendReason::kInternal);
     DCHECK(updated);
   }
   CHECK(!Contains(self));
@@ -1495,12 +1494,12 @@
     MutexLock mu(self, *Locks::thread_list_lock_);
     MutexLock mu2(self, *Locks::thread_suspend_count_lock_);
     for (Thread* thread : list_) {
-      bool suspended = thread->ModifySuspendCount(self, +1, nullptr, false);
+      bool suspended = thread->ModifySuspendCount(self, +1, nullptr, SuspendReason::kInternal);
       DCHECK(suspended);
       if (thread == self || thread->IsSuspended()) {
         threads_to_visit.push_back(thread);
       } else {
-        bool resumed = thread->ModifySuspendCount(self, -1, nullptr, false);
+        bool resumed = thread->ModifySuspendCount(self, -1, nullptr, SuspendReason::kInternal);
         DCHECK(resumed);
       }
     }
@@ -1516,7 +1515,7 @@
   {
     MutexLock mu2(self, *Locks::thread_suspend_count_lock_);
     for (Thread* thread : threads_to_visit) {
-      bool updated = thread->ModifySuspendCount(self, -1, nullptr, false);
+      bool updated = thread->ModifySuspendCount(self, -1, nullptr, SuspendReason::kInternal);
       DCHECK(updated);
     }
   }
diff --git a/runtime/thread_list.h b/runtime/thread_list.h
index 92702c6..41c5e32 100644
--- a/runtime/thread_list.h
+++ b/runtime/thread_list.h
@@ -23,6 +23,7 @@
 #include "base/time_utils.h"
 #include "base/value_object.h"
 #include "jni.h"
+#include "suspend_reason.h"
 
 #include <bitset>
 #include <list>
@@ -64,7 +65,7 @@
   void ResumeAll()
       REQUIRES(!Locks::thread_list_lock_, !Locks::thread_suspend_count_lock_)
       UNLOCK_FUNCTION(Locks::mutator_lock_);
-  void Resume(Thread* thread, bool for_debugger = false)
+  void Resume(Thread* thread, SuspendReason reason = SuspendReason::kInternal)
       REQUIRES(!Locks::thread_suspend_count_lock_);
 
   // Suspends all threads and gets exclusive access to the mutator_lock_.
@@ -81,7 +82,9 @@
   // If the thread should be suspended then value of request_suspension should be true otherwise
   // the routine will wait for a previous suspend request. If the suspension times out then *timeout
   // is set to true.
-  Thread* SuspendThreadByPeer(jobject peer, bool request_suspension, bool debug_suspension,
+  Thread* SuspendThreadByPeer(jobject peer,
+                              bool request_suspension,
+                              SuspendReason reason,
                               bool* timed_out)
       REQUIRES(!Locks::mutator_lock_,
                !Locks::thread_list_lock_,
@@ -91,7 +94,7 @@
   // thread on success else null. The thread id is used to identify the thread to avoid races with
   // the thread terminating. Note that as thread ids are recycled this may not suspend the expected
   // thread, that may be terminating. If the suspension times out then *timeout is set to true.
-  Thread* SuspendThreadByThreadId(uint32_t thread_id, bool debug_suspension, bool* timed_out)
+  Thread* SuspendThreadByThreadId(uint32_t thread_id, SuspendReason reason, bool* timed_out)
       REQUIRES(!Locks::mutator_lock_,
                !Locks::thread_list_lock_,
                !Locks::thread_suspend_count_lock_);
@@ -198,7 +201,7 @@
   void SuspendAllInternal(Thread* self,
                           Thread* ignore1,
                           Thread* ignore2 = nullptr,
-                          bool debug_suspend = false)
+                          SuspendReason reason = SuspendReason::kInternal)
       REQUIRES(!Locks::thread_list_lock_, !Locks::thread_suspend_count_lock_);
 
   void AssertThreadsAreSuspended(Thread* self, Thread* ignore1, Thread* ignore2 = nullptr)
diff --git a/runtime/verifier/method_verifier.cc b/runtime/verifier/method_verifier.cc
index 9b65255..efb02f6 100644
--- a/runtime/verifier/method_verifier.cc
+++ b/runtime/verifier/method_verifier.cc
@@ -4159,7 +4159,8 @@
   const DexFile::MethodHandleItem& mh = dex_file_->GetMethodHandle(method_handle_idx);
   if (mh.method_handle_type_ != static_cast<uint16_t>(DexFile::MethodHandleType::kInvokeStatic)) {
     Fail(VERIFY_ERROR_BAD_CLASS_HARD) << "Call site #" << call_site_idx
-                                      << " argument 0 method handle type is not InvokeStatic";
+                                      << " argument 0 method handle type is not InvokeStatic: "
+                                      << mh.method_handle_type_;
     return false;
   }
 
diff --git a/runtime/zip_archive.cc b/runtime/zip_archive.cc
index df1012e..f3d4d77 100644
--- a/runtime/zip_archive.cc
+++ b/runtime/zip_archive.cc
@@ -25,6 +25,8 @@
 #include <vector>
 
 #include "android-base/stringprintf.h"
+#include "ziparchive/zip_archive.h"
+
 #include "base/bit_utils.h"
 #include "base/unix_file/fd_file.h"
 
diff --git a/runtime/zip_archive.h b/runtime/zip_archive.h
index 1858444..821cc5c 100644
--- a/runtime/zip_archive.h
+++ b/runtime/zip_archive.h
@@ -18,7 +18,6 @@
 #define ART_RUNTIME_ZIP_ARCHIVE_H_
 
 #include <stdint.h>
-#include <ziparchive/zip_archive.h>
 #include <memory>
 #include <string>
 
@@ -29,6 +28,10 @@
 #include "os.h"
 #include "safe_map.h"
 
+// system/core/zip_archive definitions.
+struct ZipEntry;
+typedef void* ZipArchiveHandle;
+
 namespace art {
 
 class ZipArchive;
diff --git a/test/163-app-image-methods/expected.txt b/test/163-app-image-methods/expected.txt
new file mode 100644
index 0000000..f63e8e3
--- /dev/null
+++ b/test/163-app-image-methods/expected.txt
@@ -0,0 +1,3 @@
+Eating all memory.
+memoryWasAllocated = true
+match: true
diff --git a/test/163-app-image-methods/info.txt b/test/163-app-image-methods/info.txt
new file mode 100644
index 0000000..7b42ebc
--- /dev/null
+++ b/test/163-app-image-methods/info.txt
@@ -0,0 +1,3 @@
+Regression test for erroneously storing an ArtMethod* in the app image DexCache
+when the class from the corresponding MethodId is not in the app image, only the
+declaring class is.
diff --git a/test/163-app-image-methods/profile b/test/163-app-image-methods/profile
new file mode 100644
index 0000000..6585b94
--- /dev/null
+++ b/test/163-app-image-methods/profile
@@ -0,0 +1,2 @@
+LAAA/Base;
+LMain;
diff --git a/test/163-app-image-methods/run b/test/163-app-image-methods/run
new file mode 100644
index 0000000..7cc107a
--- /dev/null
+++ b/test/163-app-image-methods/run
@@ -0,0 +1,20 @@
+#!/bin/bash
+#
+# Copyright (C) 2017 The Android Open Source Project
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#     http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+# Use a profile to put specific classes in the app image.
+# Also run the compiler with -j1 to ensure specific class verification order.
+exec ${RUN} $@ --profile -Xcompiler-option --compiler-filter=speed-profile \
+    -Xcompiler-option -j1
diff --git a/test/163-app-image-methods/src/AAA/Base.java b/test/163-app-image-methods/src/AAA/Base.java
new file mode 100644
index 0000000..7ba71ad
--- /dev/null
+++ b/test/163-app-image-methods/src/AAA/Base.java
@@ -0,0 +1,22 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package AAA;
+
+class Base {
+    // The method is public but the class is package-private.
+    public static int foo() { return 42; }
+}
diff --git a/test/163-app-image-methods/src/AAA/Derived.java b/test/163-app-image-methods/src/AAA/Derived.java
new file mode 100644
index 0000000..66e156f
--- /dev/null
+++ b/test/163-app-image-methods/src/AAA/Derived.java
@@ -0,0 +1,21 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package AAA;
+
+public class Derived extends Base {
+    // Allows public access to Base.foo() (Base is package-private) referenced as Derived.foo().
+}
diff --git a/test/163-app-image-methods/src/Main.java b/test/163-app-image-methods/src/Main.java
new file mode 100644
index 0000000..a995bb8
--- /dev/null
+++ b/test/163-app-image-methods/src/Main.java
@@ -0,0 +1,85 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+import AAA.Derived;
+
+public class Main {
+    public static void main(String[] args) {
+        try {
+            // Allocate memory for the "AAA.Derived" class name before eating memory.
+            String aaaDerivedName = "AAA.Derived";
+            System.out.println("Eating all memory.");
+            Object memory = eatAllMemory();
+
+            // This test assumes that Derived is not yet resolved. In some configurations
+            // (notably interp-ac), Derived is already resolved by verifying Main at run
+            // time. Therefore we cannot assume that we get a certain `value` and need to
+            // simply check for consistency, i.e. `value == another_value`.
+            int value = 0;
+            try {
+                // If the ArtMethod* is erroneously left in the DexCache, this
+                // shall succeed despite the class Derived being unresolved so
+                // far. Otherwise, we shall throw OOME trying to resolve it.
+                value = Derived.foo();
+            } catch (OutOfMemoryError e) {
+                value = -1;
+            }
+            int another_value = 0;
+            try {
+                // For comparison, try to resolve the class Derived directly.
+                Class.forName(aaaDerivedName, false, Main.class.getClassLoader());
+                another_value = 42;
+            } catch (OutOfMemoryError e) {
+                another_value = -1;
+            }
+            boolean memoryWasAllocated = (memory != null);
+            memory = null;
+            System.out.println("memoryWasAllocated = " + memoryWasAllocated);
+            System.out.println("match: " + (value == another_value));
+            if (value != another_value || (value != -1 && value != 42)) {
+                // Mismatch or unexpected value, print additional debugging information.
+                System.out.println("value: " + value);
+                System.out.println("another_value: " + another_value);
+            }
+        } catch (Throwable t) {
+            t.printStackTrace(System.out);
+        }
+    }
+
+    public static Object eatAllMemory() {
+      Object[] result = null;
+      int size = 1000000;
+      while (result == null && size != 0) {
+          try {
+              result = new Object[size];
+          } catch (OutOfMemoryError oome) {
+              size /= 2;
+          }
+      }
+      if (result != null) {
+          int index = 0;
+          while (index != result.length && size != 0) {
+              try {
+                  result[index] = new byte[size];
+                  ++index;
+              } catch (OutOfMemoryError oome) {
+                  size /= 2;
+              }
+          }
+      }
+      return result;
+  }
+}
diff --git a/test/623-checker-loop-regressions/src/Main.java b/test/623-checker-loop-regressions/src/Main.java
index af205b0..aca997e 100644
--- a/test/623-checker-loop-regressions/src/Main.java
+++ b/test/623-checker-loop-regressions/src/Main.java
@@ -285,6 +285,9 @@
   /// CHECK-DAG: ArrayGet loop:<<Loop>>      outer_loop:none
   /// CHECK-DAG: ArraySet loop:<<Loop>>      outer_loop:none
   //
+  /// CHECK-START-ARM: void Main.string2Bytes(char[], java.lang.String) loop_optimization (after)
+  /// CHECK-NOT: VecLoad
+  //
   /// CHECK-START-ARM64: void Main.string2Bytes(char[], java.lang.String) loop_optimization (after)
   /// CHECK-DAG: Phi      loop:<<Loop:B\d+>> outer_loop:none
   /// CHECK-DAG: VecLoad  loop:<<Loop>>      outer_loop:none
@@ -329,6 +332,13 @@
   /// CHECK-DAG:               ArraySet [{{l\d+}},<<Phi>>,<<One>>] loop:<<Loop>>      outer_loop:none
   /// CHECK-DAG:               ArraySet [{{l\d+}},<<Phi>>,<<One>>] loop:<<Loop>>      outer_loop:none
   //
+  /// CHECK-START-ARM: void Main.oneBoth(short[], char[]) loop_optimization (after)
+  /// CHECK-DAG: <<One:i\d+>>  IntConstant 1                        loop:none
+  /// CHECK-DAG: <<Repl:d\d+>> VecReplicateScalar [<<One>>]         loop:none
+  /// CHECK-DAG: <<Phi:i\d+>>  Phi                                  loop:<<Loop:B\d+>> outer_loop:none
+  /// CHECK-DAG:               VecStore [{{l\d+}},<<Phi>>,<<Repl>>] loop:<<Loop>>      outer_loop:none
+  /// CHECK-DAG:               VecStore [{{l\d+}},<<Phi>>,<<Repl>>] loop:<<Loop>>      outer_loop:none
+  //
   /// CHECK-START-ARM64: void Main.oneBoth(short[], char[]) loop_optimization (after)
   /// CHECK-DAG: <<One:i\d+>>  IntConstant 1                        loop:none
   /// CHECK-DAG: <<Repl:d\d+>> VecReplicateScalar [<<One>>]         loop:none
@@ -369,6 +379,19 @@
   /// CHECK-DAG: <<Cnv:b\d+>>  TypeConversion [<<Add>>]            loop:<<Loop>>      outer_loop:none
   /// CHECK-DAG:               ArraySet [{{l\d+}},<<Phi>>,<<Cnv>>] loop:<<Loop>>      outer_loop:none
   //
+  /// CHECK-START-ARM: void Main.typeConv(byte[], byte[]) loop_optimization (after)
+  /// CHECK-DAG: <<One:i\d+>>  IntConstant 1                         loop:none
+  /// CHECK-DAG: <<Repl:d\d+>> VecReplicateScalar [<<One>>]          loop:none
+  /// CHECK-DAG: <<Phi1:i\d+>> Phi                                   loop:<<Loop1:B\d+>> outer_loop:none
+  /// CHECK-DAG: <<Load:d\d+>> VecLoad [{{l\d+}},<<Phi1>>]           loop:<<Loop1>>      outer_loop:none
+  /// CHECK-DAG: <<Vadd:d\d+>> VecAdd [<<Load>>,<<Repl>>]            loop:<<Loop1>>      outer_loop:none
+  /// CHECK-DAG:               VecStore [{{l\d+}},<<Phi1>>,<<Vadd>>] loop:<<Loop1>>      outer_loop:none
+  /// CHECK-DAG: <<Phi2:i\d+>> Phi                                   loop:<<Loop2:B\d+>> outer_loop:none
+  /// CHECK-DAG: <<Get:b\d+>>  ArrayGet [{{l\d+}},<<Phi2>>]          loop:<<Loop2>>      outer_loop:none
+  /// CHECK-DAG: <<Add:i\d+>>  Add [<<Get>>,<<One>>]                 loop:<<Loop2>>      outer_loop:none
+  /// CHECK-DAG: <<Cnv:b\d+>>  TypeConversion [<<Add>>]              loop:<<Loop2>>      outer_loop:none
+  /// CHECK-DAG:               ArraySet [{{l\d+}},<<Phi2>>,<<Cnv>>]  loop:<<Loop2>>      outer_loop:none
+  //
   /// CHECK-START-ARM64: void Main.typeConv(byte[], byte[]) loop_optimization (after)
   /// CHECK-DAG: <<One:i\d+>>  IntConstant 1                         loop:none
   /// CHECK-DAG: <<Repl:d\d+>> VecReplicateScalar [<<One>>]          loop:none
diff --git a/test/640-checker-boolean-simd/src/Main.java b/test/640-checker-boolean-simd/src/Main.java
index 64b76f8..c337ef4 100644
--- a/test/640-checker-boolean-simd/src/Main.java
+++ b/test/640-checker-boolean-simd/src/Main.java
@@ -30,6 +30,12 @@
   /// CHECK-DAG: ArrayGet loop:<<Loop>>      outer_loop:none
   /// CHECK-DAG: ArraySet loop:<<Loop>>      outer_loop:none
   //
+  /// CHECK-START-ARM: void Main.and(boolean) loop_optimization (after)
+  /// CHECK-DAG: Phi      loop:<<Loop:B\d+>> outer_loop:none
+  /// CHECK-DAG: VecLoad  loop:<<Loop>>      outer_loop:none
+  /// CHECK-DAG: VecAnd   loop:<<Loop>>      outer_loop:none
+  /// CHECK-DAG: VecStore loop:<<Loop>>      outer_loop:none
+  //
   /// CHECK-START-ARM64: void Main.and(boolean) loop_optimization (after)
   /// CHECK-DAG: Phi      loop:<<Loop:B\d+>> outer_loop:none
   /// CHECK-DAG: VecLoad  loop:<<Loop>>      outer_loop:none
@@ -51,6 +57,12 @@
   /// CHECK-DAG: ArrayGet loop:<<Loop>>      outer_loop:none
   /// CHECK-DAG: ArraySet loop:<<Loop>>      outer_loop:none
   //
+  /// CHECK-START-ARM: void Main.or(boolean) loop_optimization (after)
+  /// CHECK-DAG: Phi      loop:<<Loop:B\d+>> outer_loop:none
+  /// CHECK-DAG: VecLoad  loop:<<Loop>>      outer_loop:none
+  /// CHECK-DAG: VecOr    loop:<<Loop>>      outer_loop:none
+  /// CHECK-DAG: VecStore loop:<<Loop>>      outer_loop:none
+  //
   /// CHECK-START-ARM64: void Main.or(boolean) loop_optimization (after)
   /// CHECK-DAG: Phi      loop:<<Loop:B\d+>> outer_loop:none
   /// CHECK-DAG: VecLoad  loop:<<Loop>>      outer_loop:none
@@ -72,6 +84,12 @@
   /// CHECK-DAG: ArrayGet loop:<<Loop>>      outer_loop:none
   /// CHECK-DAG: ArraySet loop:<<Loop>>      outer_loop:none
   //
+  /// CHECK-START-ARM: void Main.xor(boolean) loop_optimization (after)
+  /// CHECK-DAG: Phi      loop:<<Loop:B\d+>> outer_loop:none
+  /// CHECK-DAG: VecLoad  loop:<<Loop>>      outer_loop:none
+  /// CHECK-DAG: VecXor   loop:<<Loop>>      outer_loop:none
+  /// CHECK-DAG: VecStore loop:<<Loop>>      outer_loop:none
+  //
   /// CHECK-START-ARM64: void Main.xor(boolean) loop_optimization (after)
   /// CHECK-DAG: Phi      loop:<<Loop:B\d+>> outer_loop:none
   /// CHECK-DAG: VecLoad  loop:<<Loop>>      outer_loop:none
@@ -93,6 +111,12 @@
   /// CHECK-DAG: ArrayGet loop:<<Loop>>      outer_loop:none
   /// CHECK-DAG: ArraySet loop:<<Loop>>      outer_loop:none
   //
+  /// CHECK-START-ARM: void Main.not() loop_optimization (after)
+  /// CHECK-DAG: Phi      loop:<<Loop:B\d+>> outer_loop:none
+  /// CHECK-DAG: VecLoad  loop:<<Loop>>      outer_loop:none
+  /// CHECK-DAG: VecNot   loop:<<Loop>>      outer_loop:none
+  /// CHECK-DAG: VecStore loop:<<Loop>>      outer_loop:none
+  //
   /// CHECK-START-ARM64: void Main.not() loop_optimization (after)
   /// CHECK-DAG: Phi      loop:<<Loop:B\d+>> outer_loop:none
   /// CHECK-DAG: VecLoad  loop:<<Loop>>      outer_loop:none
diff --git a/test/640-checker-byte-simd/src/Main.java b/test/640-checker-byte-simd/src/Main.java
index 283c2c9..dc7aaf7 100644
--- a/test/640-checker-byte-simd/src/Main.java
+++ b/test/640-checker-byte-simd/src/Main.java
@@ -30,6 +30,12 @@
   /// CHECK-DAG: ArrayGet loop:<<Loop>>      outer_loop:none
   /// CHECK-DAG: ArraySet loop:<<Loop>>      outer_loop:none
   //
+  /// CHECK-START-ARM: void Main.add(int) loop_optimization (after)
+  /// CHECK-DAG: Phi      loop:<<Loop:B\d+>> outer_loop:none
+  /// CHECK-DAG: VecLoad  loop:<<Loop>>      outer_loop:none
+  /// CHECK-DAG: VecAdd   loop:<<Loop>>      outer_loop:none
+  /// CHECK-DAG: VecStore loop:<<Loop>>      outer_loop:none
+  //
   /// CHECK-START-ARM64: void Main.add(int) loop_optimization (after)
   /// CHECK-DAG: Phi      loop:<<Loop:B\d+>> outer_loop:none
   /// CHECK-DAG: VecLoad  loop:<<Loop>>      outer_loop:none
@@ -51,6 +57,12 @@
   /// CHECK-DAG: ArrayGet loop:<<Loop>>      outer_loop:none
   /// CHECK-DAG: ArraySet loop:<<Loop>>      outer_loop:none
   //
+  /// CHECK-START-ARM: void Main.sub(int) loop_optimization (after)
+  /// CHECK-DAG: Phi      loop:<<Loop:B\d+>> outer_loop:none
+  /// CHECK-DAG: VecLoad  loop:<<Loop>>      outer_loop:none
+  /// CHECK-DAG: VecSub   loop:<<Loop>>      outer_loop:none
+  /// CHECK-DAG: VecStore loop:<<Loop>>      outer_loop:none
+  //
   /// CHECK-START-ARM64: void Main.sub(int) loop_optimization (after)
   /// CHECK-DAG: Phi      loop:<<Loop:B\d+>> outer_loop:none
   /// CHECK-DAG: VecLoad  loop:<<Loop>>      outer_loop:none
@@ -72,6 +84,12 @@
   /// CHECK-DAG: ArrayGet loop:<<Loop>>      outer_loop:none
   /// CHECK-DAG: ArraySet loop:<<Loop>>      outer_loop:none
   //
+  /// CHECK-START-ARM: void Main.mul(int) loop_optimization (after)
+  /// CHECK-DAG: Phi      loop:<<Loop:B\d+>> outer_loop:none
+  /// CHECK-DAG: VecLoad  loop:<<Loop>>      outer_loop:none
+  /// CHECK-DAG: VecMul   loop:<<Loop>>      outer_loop:none
+  /// CHECK-DAG: VecStore loop:<<Loop>>      outer_loop:none
+  //
   /// CHECK-START-ARM64: void Main.mul(int) loop_optimization (after)
   /// CHECK-DAG: Phi      loop:<<Loop:B\d+>> outer_loop:none
   /// CHECK-DAG: VecLoad  loop:<<Loop>>      outer_loop:none
@@ -107,6 +125,12 @@
   /// CHECK-DAG: ArrayGet loop:<<Loop>>      outer_loop:none
   /// CHECK-DAG: ArraySet loop:<<Loop>>      outer_loop:none
   //
+  /// CHECK-START-ARM: void Main.neg() loop_optimization (after)
+  /// CHECK-DAG: Phi      loop:<<Loop:B\d+>> outer_loop:none
+  /// CHECK-DAG: VecLoad  loop:<<Loop>>      outer_loop:none
+  /// CHECK-DAG: VecNeg   loop:<<Loop>>      outer_loop:none
+  /// CHECK-DAG: VecStore loop:<<Loop>>      outer_loop:none
+  //
   /// CHECK-START-ARM64: void Main.neg() loop_optimization (after)
   /// CHECK-DAG: Phi      loop:<<Loop:B\d+>> outer_loop:none
   /// CHECK-DAG: VecLoad  loop:<<Loop>>      outer_loop:none
@@ -128,6 +152,12 @@
   /// CHECK-DAG: ArrayGet loop:<<Loop>>      outer_loop:none
   /// CHECK-DAG: ArraySet loop:<<Loop>>      outer_loop:none
   //
+  /// CHECK-START-ARM: void Main.not() loop_optimization (after)
+  /// CHECK-DAG: Phi      loop:<<Loop:B\d+>> outer_loop:none
+  /// CHECK-DAG: VecLoad  loop:<<Loop>>      outer_loop:none
+  /// CHECK-DAG: VecNot   loop:<<Loop>>      outer_loop:none
+  /// CHECK-DAG: VecStore loop:<<Loop>>      outer_loop:none
+  //
   /// CHECK-START-ARM64: void Main.not() loop_optimization (after)
   /// CHECK-DAG: Phi      loop:<<Loop:B\d+>> outer_loop:none
   /// CHECK-DAG: VecLoad  loop:<<Loop>>      outer_loop:none
@@ -149,6 +179,12 @@
   /// CHECK-DAG: ArrayGet loop:<<Loop>>      outer_loop:none
   /// CHECK-DAG: ArraySet loop:<<Loop>>      outer_loop:none
   //
+  /// CHECK-START-ARM: void Main.shl4() loop_optimization (after)
+  /// CHECK-DAG: Phi      loop:<<Loop:B\d+>> outer_loop:none
+  /// CHECK-DAG: VecLoad  loop:<<Loop>>      outer_loop:none
+  /// CHECK-DAG: VecShl   loop:<<Loop>>      outer_loop:none
+  /// CHECK-DAG: VecStore loop:<<Loop>>      outer_loop:none
+  //
   /// CHECK-START-ARM64: void Main.shl4() loop_optimization (after)
   /// CHECK-DAG: Phi      loop:<<Loop:B\d+>> outer_loop:none
   /// CHECK-DAG: VecLoad  loop:<<Loop>>      outer_loop:none
@@ -170,6 +206,12 @@
   /// CHECK-DAG: ArrayGet loop:<<Loop>>      outer_loop:none
   /// CHECK-DAG: ArraySet loop:<<Loop>>      outer_loop:none
   //
+  /// CHECK-START-ARM: void Main.sar2() loop_optimization (after)
+  /// CHECK-DAG: Phi      loop:<<Loop:B\d+>> outer_loop:none
+  /// CHECK-DAG: VecLoad  loop:<<Loop>>      outer_loop:none
+  /// CHECK-DAG: VecShr   loop:<<Loop>>      outer_loop:none
+  /// CHECK-DAG: VecStore loop:<<Loop>>      outer_loop:none
+  //
   /// CHECK-START-ARM64: void Main.sar2() loop_optimization (after)
   /// CHECK-DAG: Phi      loop:<<Loop:B\d+>> outer_loop:none
   /// CHECK-DAG: VecLoad  loop:<<Loop>>      outer_loop:none
diff --git a/test/640-checker-char-simd/src/Main.java b/test/640-checker-char-simd/src/Main.java
index dd879b4..0ba5963 100644
--- a/test/640-checker-char-simd/src/Main.java
+++ b/test/640-checker-char-simd/src/Main.java
@@ -30,6 +30,12 @@
   /// CHECK-DAG: ArrayGet loop:<<Loop>>      outer_loop:none
   /// CHECK-DAG: ArraySet loop:<<Loop>>      outer_loop:none
   //
+  /// CHECK-START-ARM: void Main.add(int) loop_optimization (after)
+  /// CHECK-DAG: Phi      loop:<<Loop:B\d+>> outer_loop:none
+  /// CHECK-DAG: VecLoad  loop:<<Loop>>      outer_loop:none
+  /// CHECK-DAG: VecAdd   loop:<<Loop>>      outer_loop:none
+  /// CHECK-DAG: VecStore loop:<<Loop>>      outer_loop:none
+  //
   /// CHECK-START-ARM64: void Main.add(int) loop_optimization (after)
   /// CHECK-DAG: Phi      loop:<<Loop:B\d+>> outer_loop:none
   /// CHECK-DAG: VecLoad  loop:<<Loop>>      outer_loop:none
@@ -51,6 +57,12 @@
   /// CHECK-DAG: ArrayGet loop:<<Loop>>      outer_loop:none
   /// CHECK-DAG: ArraySet loop:<<Loop>>      outer_loop:none
   //
+  /// CHECK-START-ARM: void Main.sub(int) loop_optimization (after)
+  /// CHECK-DAG: Phi      loop:<<Loop:B\d+>> outer_loop:none
+  /// CHECK-DAG: VecLoad  loop:<<Loop>>      outer_loop:none
+  /// CHECK-DAG: VecSub   loop:<<Loop>>      outer_loop:none
+  /// CHECK-DAG: VecStore loop:<<Loop>>      outer_loop:none
+  //
   /// CHECK-START-ARM64: void Main.sub(int) loop_optimization (after)
   /// CHECK-DAG: Phi      loop:<<Loop:B\d+>> outer_loop:none
   /// CHECK-DAG: VecLoad  loop:<<Loop>>      outer_loop:none
@@ -72,6 +84,12 @@
   /// CHECK-DAG: ArrayGet loop:<<Loop>>      outer_loop:none
   /// CHECK-DAG: ArraySet loop:<<Loop>>      outer_loop:none
   //
+  /// CHECK-START-ARM: void Main.mul(int) loop_optimization (after)
+  /// CHECK-DAG: Phi      loop:<<Loop:B\d+>> outer_loop:none
+  /// CHECK-DAG: VecLoad  loop:<<Loop>>      outer_loop:none
+  /// CHECK-DAG: VecMul   loop:<<Loop>>      outer_loop:none
+  /// CHECK-DAG: VecStore loop:<<Loop>>      outer_loop:none
+  //
   /// CHECK-START-ARM64: void Main.mul(int) loop_optimization (after)
   /// CHECK-DAG: Phi      loop:<<Loop:B\d+>> outer_loop:none
   /// CHECK-DAG: VecLoad  loop:<<Loop>>      outer_loop:none
@@ -107,6 +125,12 @@
   /// CHECK-DAG: ArrayGet loop:<<Loop>>      outer_loop:none
   /// CHECK-DAG: ArraySet loop:<<Loop>>      outer_loop:none
   //
+  /// CHECK-START-ARM: void Main.neg() loop_optimization (after)
+  /// CHECK-DAG: Phi      loop:<<Loop:B\d+>> outer_loop:none
+  /// CHECK-DAG: VecLoad  loop:<<Loop>>      outer_loop:none
+  /// CHECK-DAG: VecNeg   loop:<<Loop>>      outer_loop:none
+  /// CHECK-DAG: VecStore loop:<<Loop>>      outer_loop:none
+  //
   /// CHECK-START-ARM64: void Main.neg() loop_optimization (after)
   /// CHECK-DAG: Phi      loop:<<Loop:B\d+>> outer_loop:none
   /// CHECK-DAG: VecLoad  loop:<<Loop>>      outer_loop:none
@@ -128,6 +152,12 @@
   /// CHECK-DAG: ArrayGet loop:<<Loop>>      outer_loop:none
   /// CHECK-DAG: ArraySet loop:<<Loop>>      outer_loop:none
   //
+  /// CHECK-START-ARM: void Main.not() loop_optimization (after)
+  /// CHECK-DAG: Phi      loop:<<Loop:B\d+>> outer_loop:none
+  /// CHECK-DAG: VecLoad  loop:<<Loop>>      outer_loop:none
+  /// CHECK-DAG: VecNot   loop:<<Loop>>      outer_loop:none
+  /// CHECK-DAG: VecStore loop:<<Loop>>      outer_loop:none
+  //
   /// CHECK-START-ARM64: void Main.not() loop_optimization (after)
   /// CHECK-DAG: Phi      loop:<<Loop:B\d+>> outer_loop:none
   /// CHECK-DAG: VecLoad  loop:<<Loop>>      outer_loop:none
@@ -149,6 +179,12 @@
   /// CHECK-DAG: ArrayGet loop:<<Loop>>      outer_loop:none
   /// CHECK-DAG: ArraySet loop:<<Loop>>      outer_loop:none
   //
+  /// CHECK-START-ARM: void Main.shl4() loop_optimization (after)
+  /// CHECK-DAG: Phi      loop:<<Loop:B\d+>> outer_loop:none
+  /// CHECK-DAG: VecLoad  loop:<<Loop>>      outer_loop:none
+  /// CHECK-DAG: VecShl   loop:<<Loop>>      outer_loop:none
+  /// CHECK-DAG: VecStore loop:<<Loop>>      outer_loop:none
+  //
   /// CHECK-START-ARM64: void Main.shl4() loop_optimization (after)
   /// CHECK-DAG: Phi      loop:<<Loop:B\d+>> outer_loop:none
   /// CHECK-DAG: VecLoad  loop:<<Loop>>      outer_loop:none
@@ -183,6 +219,12 @@
   /// CHECK-DAG: ArrayGet loop:<<Loop>>      outer_loop:none
   /// CHECK-DAG: ArraySet loop:<<Loop>>      outer_loop:none
   //
+  /// CHECK-START-ARM: void Main.shr2() loop_optimization (after)
+  /// CHECK-DAG: Phi      loop:<<Loop:B\d+>> outer_loop:none
+  /// CHECK-DAG: VecLoad  loop:<<Loop>>      outer_loop:none
+  /// CHECK-DAG: VecUShr  loop:<<Loop>>      outer_loop:none
+  /// CHECK-DAG: VecStore loop:<<Loop>>      outer_loop:none
+  //
   /// CHECK-START-ARM64: void Main.shr2() loop_optimization (after)
   /// CHECK-DAG: Phi      loop:<<Loop:B\d+>> outer_loop:none
   /// CHECK-DAG: VecLoad  loop:<<Loop>>      outer_loop:none
diff --git a/test/640-checker-int-simd/src/Main.java b/test/640-checker-int-simd/src/Main.java
index 9abf60d..10dd340 100644
--- a/test/640-checker-int-simd/src/Main.java
+++ b/test/640-checker-int-simd/src/Main.java
@@ -30,6 +30,12 @@
   /// CHECK-DAG: ArrayGet loop:<<Loop>>      outer_loop:none
   /// CHECK-DAG: ArraySet loop:<<Loop>>      outer_loop:none
   //
+  /// CHECK-START-ARM: void Main.add(int) loop_optimization (after)
+  /// CHECK-DAG: Phi      loop:<<Loop:B\d+>> outer_loop:none
+  /// CHECK-DAG: VecLoad  loop:<<Loop>>      outer_loop:none
+  /// CHECK-DAG: VecAdd   loop:<<Loop>>      outer_loop:none
+  /// CHECK-DAG: VecStore loop:<<Loop>>      outer_loop:none
+  //
   /// CHECK-START-ARM64: void Main.add(int) loop_optimization (after)
   /// CHECK-DAG: Phi      loop:<<Loop:B\d+>> outer_loop:none
   /// CHECK-DAG: VecLoad  loop:<<Loop>>      outer_loop:none
@@ -51,6 +57,12 @@
   /// CHECK-DAG: ArrayGet loop:<<Loop>>      outer_loop:none
   /// CHECK-DAG: ArraySet loop:<<Loop>>      outer_loop:none
   //
+  /// CHECK-START-ARM: void Main.sub(int) loop_optimization (after)
+  /// CHECK-DAG: Phi      loop:<<Loop:B\d+>> outer_loop:none
+  /// CHECK-DAG: VecLoad  loop:<<Loop>>      outer_loop:none
+  /// CHECK-DAG: VecSub   loop:<<Loop>>      outer_loop:none
+  /// CHECK-DAG: VecStore loop:<<Loop>>      outer_loop:none
+  //
   /// CHECK-START-ARM64: void Main.sub(int) loop_optimization (after)
   /// CHECK-DAG: Phi      loop:<<Loop:B\d+>> outer_loop:none
   /// CHECK-DAG: VecLoad  loop:<<Loop>>      outer_loop:none
@@ -72,6 +84,12 @@
   /// CHECK-DAG: ArrayGet loop:<<Loop>>      outer_loop:none
   /// CHECK-DAG: ArraySet loop:<<Loop>>      outer_loop:none
   //
+  /// CHECK-START-ARM: void Main.mul(int) loop_optimization (after)
+  /// CHECK-DAG: Phi      loop:<<Loop:B\d+>> outer_loop:none
+  /// CHECK-DAG: VecLoad  loop:<<Loop>>      outer_loop:none
+  /// CHECK-DAG: VecMul   loop:<<Loop>>      outer_loop:none
+  /// CHECK-DAG: VecStore loop:<<Loop>>      outer_loop:none
+  //
   /// CHECK-START-ARM64: void Main.mul(int) loop_optimization (after)
   /// CHECK-DAG: Phi      loop:<<Loop:B\d+>> outer_loop:none
   /// CHECK-DAG: VecLoad  loop:<<Loop>>      outer_loop:none
@@ -108,6 +126,12 @@
   /// CHECK-DAG: ArrayGet loop:<<Loop>>      outer_loop:none
   /// CHECK-DAG: ArraySet loop:<<Loop>>      outer_loop:none
   //
+  /// CHECK-START-ARM: void Main.neg() loop_optimization (after)
+  /// CHECK-DAG: Phi      loop:<<Loop:B\d+>> outer_loop:none
+  /// CHECK-DAG: VecLoad  loop:<<Loop>>      outer_loop:none
+  /// CHECK-DAG: VecNeg   loop:<<Loop>>      outer_loop:none
+  /// CHECK-DAG: VecStore loop:<<Loop>>      outer_loop:none
+  //
   /// CHECK-START-ARM64: void Main.neg() loop_optimization (after)
   /// CHECK-DAG: Phi      loop:<<Loop:B\d+>> outer_loop:none
   /// CHECK-DAG: VecLoad  loop:<<Loop>>      outer_loop:none
@@ -129,6 +153,12 @@
   /// CHECK-DAG: ArrayGet loop:<<Loop>>      outer_loop:none
   /// CHECK-DAG: ArraySet loop:<<Loop>>      outer_loop:none
   //
+  /// CHECK-START-ARM: void Main.not() loop_optimization (after)
+  /// CHECK-DAG: Phi      loop:<<Loop:B\d+>> outer_loop:none
+  /// CHECK-DAG: VecLoad  loop:<<Loop>>      outer_loop:none
+  /// CHECK-DAG: VecNot   loop:<<Loop>>      outer_loop:none
+  /// CHECK-DAG: VecStore loop:<<Loop>>      outer_loop:none
+  //
   /// CHECK-START-ARM64: void Main.not() loop_optimization (after)
   /// CHECK-DAG: Phi      loop:<<Loop:B\d+>> outer_loop:none
   /// CHECK-DAG: VecLoad  loop:<<Loop>>      outer_loop:none
@@ -150,6 +180,12 @@
   /// CHECK-DAG: ArrayGet loop:<<Loop>>      outer_loop:none
   /// CHECK-DAG: ArraySet loop:<<Loop>>      outer_loop:none
   //
+  /// CHECK-START-ARM: void Main.shl4() loop_optimization (after)
+  /// CHECK-DAG: Phi      loop:<<Loop:B\d+>> outer_loop:none
+  /// CHECK-DAG: VecLoad  loop:<<Loop>>      outer_loop:none
+  /// CHECK-DAG: VecShl   loop:<<Loop>>      outer_loop:none
+  /// CHECK-DAG: VecStore loop:<<Loop>>      outer_loop:none
+  //
   /// CHECK-START-ARM64: void Main.shl4() loop_optimization (after)
   /// CHECK-DAG: Phi      loop:<<Loop:B\d+>> outer_loop:none
   /// CHECK-DAG: VecLoad  loop:<<Loop>>      outer_loop:none
@@ -170,7 +206,13 @@
   /// CHECK-DAG: Phi      loop:<<Loop:B\d+>> outer_loop:none
   /// CHECK-DAG: ArrayGet loop:<<Loop>>      outer_loop:none
   /// CHECK-DAG: ArraySet loop:<<Loop>>      outer_loop:none
-   //
+  //
+  /// CHECK-START-ARM: void Main.sar2() loop_optimization (after)
+  /// CHECK-DAG: Phi      loop:<<Loop:B\d+>> outer_loop:none
+  /// CHECK-DAG: VecLoad  loop:<<Loop>>      outer_loop:none
+  /// CHECK-DAG: VecShr   loop:<<Loop>>      outer_loop:none
+  /// CHECK-DAG: VecStore loop:<<Loop>>      outer_loop:none
+  //
   /// CHECK-START-ARM64: void Main.sar2() loop_optimization (after)
   /// CHECK-DAG: Phi      loop:<<Loop:B\d+>> outer_loop:none
   /// CHECK-DAG: VecLoad  loop:<<Loop>>      outer_loop:none
@@ -192,6 +234,12 @@
   /// CHECK-DAG: ArrayGet loop:<<Loop>>      outer_loop:none
   /// CHECK-DAG: ArraySet loop:<<Loop>>      outer_loop:none
   //
+  /// CHECK-START-ARM: void Main.shr2() loop_optimization (after)
+  /// CHECK-DAG: Phi      loop:<<Loop:B\d+>> outer_loop:none
+  /// CHECK-DAG: VecLoad  loop:<<Loop>>      outer_loop:none
+  /// CHECK-DAG: VecUShr  loop:<<Loop>>      outer_loop:none
+  /// CHECK-DAG: VecStore loop:<<Loop>>      outer_loop:none
+  //
   /// CHECK-START-ARM64: void Main.shr2() loop_optimization (after)
   /// CHECK-DAG: Phi      loop:<<Loop:B\d+>> outer_loop:none
   /// CHECK-DAG: VecLoad  loop:<<Loop>>      outer_loop:none
@@ -229,6 +277,11 @@
   /// CHECK-DAG: <<Get:i\d+>> ArrayGet                             loop:<<Loop>>      outer_loop:none
   /// CHECK-DAG:              ArraySet [{{l\d+}},{{i\d+}},<<Get>>] loop:<<Loop>>      outer_loop:none
   //
+  /// CHECK-START-ARM: void Main.shr32() loop_optimization (after)
+  /// CHECK-DAG: <<Phi:i\d+>> Phi                                 loop:<<Loop:B\d+>> outer_loop:none
+  /// CHECK-DAG: <<Get:d\d+>> VecLoad                             loop:<<Loop>>      outer_loop:none
+  /// CHECK-DAG:              VecStore [{{l\d+}},<<Phi>>,<<Get>>] loop:<<Loop>>      outer_loop:none
+  //
   /// CHECK-START-ARM64: void Main.shr32() loop_optimization (after)
   /// CHECK-DAG: <<Phi:i\d+>> Phi                                 loop:<<Loop:B\d+>> outer_loop:none
   /// CHECK-DAG: <<Get:d\d+>> VecLoad                             loop:<<Loop>>      outer_loop:none
@@ -258,6 +311,13 @@
   /// CHECK-DAG: <<UShr:i\d+>> UShr [<<Get>>,<<Dist>>]               loop:<<Loop>>      outer_loop:none
   /// CHECK-DAG:               ArraySet [{{l\d+}},{{i\d+}},<<UShr>>] loop:<<Loop>>      outer_loop:none
   //
+  /// CHECK-START-ARM: void Main.shr33() loop_optimization (after)
+  /// CHECK-DAG: <<Dist:i\d+>> IntConstant 1                        loop:none
+  /// CHECK-DAG: <<Phi:i\d+>>  Phi                                  loop:<<Loop:B\d+>> outer_loop:none
+  /// CHECK-DAG: <<Get:d\d+>>  VecLoad                              loop:<<Loop>>      outer_loop:none
+  /// CHECK-DAG: <<UShr:d\d+>> VecUShr [<<Get>>,<<Dist>>]           loop:<<Loop>>      outer_loop:none
+  /// CHECK-DAG:               VecStore [{{l\d+}},<<Phi>>,<<UShr>>] loop:<<Loop>>      outer_loop:none
+  //
   /// CHECK-START-ARM64: void Main.shr33() loop_optimization (after)
   /// CHECK-DAG: <<Dist:i\d+>> IntConstant 1                        loop:none
   /// CHECK-DAG: <<Phi:i\d+>>  Phi                                  loop:<<Loop:B\d+>> outer_loop:none
@@ -290,6 +350,13 @@
   /// CHECK-DAG: <<UShr:i\d+>> UShr [<<Get>>,<<Dist>>]               loop:<<Loop>>      outer_loop:none
   /// CHECK-DAG:               ArraySet [{{l\d+}},{{i\d+}},<<UShr>>] loop:<<Loop>>      outer_loop:none
   //
+  /// CHECK-START-ARM: void Main.shrMinus254() loop_optimization (after)
+  /// CHECK-DAG: <<Dist:i\d+>> IntConstant 2                         loop:none
+  /// CHECK-DAG: <<Phi:i\d+>>  Phi                                  loop:<<Loop:B\d+>> outer_loop:none
+  /// CHECK-DAG: <<Get:d\d+>>  VecLoad                              loop:<<Loop>>      outer_loop:none
+  /// CHECK-DAG: <<UShr:d\d+>> VecUShr [<<Get>>,<<Dist>>]           loop:<<Loop>>      outer_loop:none
+  /// CHECK-DAG:               VecStore [{{l\d+}},<<Phi>>,<<UShr>>] loop:<<Loop>>      outer_loop:none
+  //
   /// CHECK-START-ARM64: void Main.shrMinus254() loop_optimization (after)
   /// CHECK-DAG: <<Dist:i\d+>> IntConstant 2                         loop:none
   /// CHECK-DAG: <<Phi:i\d+>>  Phi                                  loop:<<Loop:B\d+>> outer_loop:none
diff --git a/test/640-checker-short-simd/src/Main.java b/test/640-checker-short-simd/src/Main.java
index 4cca837..9dc084d 100644
--- a/test/640-checker-short-simd/src/Main.java
+++ b/test/640-checker-short-simd/src/Main.java
@@ -30,6 +30,12 @@
   /// CHECK-DAG: ArrayGet loop:<<Loop>>      outer_loop:none
   /// CHECK-DAG: ArraySet loop:<<Loop>>      outer_loop:none
   //
+  /// CHECK-START-ARM: void Main.add(int) loop_optimization (after)
+  /// CHECK-DAG: Phi      loop:<<Loop:B\d+>> outer_loop:none
+  /// CHECK-DAG: VecLoad  loop:<<Loop>>      outer_loop:none
+  /// CHECK-DAG: VecAdd   loop:<<Loop>>      outer_loop:none
+  /// CHECK-DAG: VecStore loop:<<Loop>>      outer_loop:none
+  //
   /// CHECK-START-ARM64: void Main.add(int) loop_optimization (after)
   /// CHECK-DAG: Phi      loop:<<Loop:B\d+>> outer_loop:none
   /// CHECK-DAG: VecLoad  loop:<<Loop>>      outer_loop:none
@@ -51,6 +57,12 @@
   /// CHECK-DAG: ArrayGet loop:<<Loop>>      outer_loop:none
   /// CHECK-DAG: ArraySet loop:<<Loop>>      outer_loop:none
   //
+  /// CHECK-START-ARM: void Main.sub(int) loop_optimization (after)
+  /// CHECK-DAG: Phi      loop:<<Loop:B\d+>> outer_loop:none
+  /// CHECK-DAG: VecLoad  loop:<<Loop>>      outer_loop:none
+  /// CHECK-DAG: VecSub   loop:<<Loop>>      outer_loop:none
+  /// CHECK-DAG: VecStore loop:<<Loop>>      outer_loop:none
+  //
   /// CHECK-START-ARM64: void Main.sub(int) loop_optimization (after)
   /// CHECK-DAG: Phi      loop:<<Loop:B\d+>> outer_loop:none
   /// CHECK-DAG: VecLoad  loop:<<Loop>>      outer_loop:none
@@ -72,6 +84,12 @@
   /// CHECK-DAG: ArrayGet loop:<<Loop>>      outer_loop:none
   /// CHECK-DAG: ArraySet loop:<<Loop>>      outer_loop:none
   //
+  /// CHECK-START-ARM: void Main.mul(int) loop_optimization (after)
+  /// CHECK-DAG: Phi      loop:<<Loop:B\d+>> outer_loop:none
+  /// CHECK-DAG: VecLoad  loop:<<Loop>>      outer_loop:none
+  /// CHECK-DAG: VecMul   loop:<<Loop>>      outer_loop:none
+  /// CHECK-DAG: VecStore loop:<<Loop>>      outer_loop:none
+  //
   /// CHECK-START-ARM64: void Main.mul(int) loop_optimization (after)
   /// CHECK-DAG: Phi      loop:<<Loop:B\d+>> outer_loop:none
   /// CHECK-DAG: VecLoad  loop:<<Loop>>      outer_loop:none
@@ -107,6 +125,12 @@
   /// CHECK-DAG: ArrayGet loop:<<Loop>>      outer_loop:none
   /// CHECK-DAG: ArraySet loop:<<Loop>>      outer_loop:none
   //
+  /// CHECK-START-ARM: void Main.neg() loop_optimization (after)
+  /// CHECK-DAG: Phi      loop:<<Loop:B\d+>> outer_loop:none
+  /// CHECK-DAG: VecLoad  loop:<<Loop>>      outer_loop:none
+  /// CHECK-DAG: VecNeg   loop:<<Loop>>      outer_loop:none
+  /// CHECK-DAG: VecStore loop:<<Loop>>      outer_loop:none
+  //
   /// CHECK-START-ARM64: void Main.neg() loop_optimization (after)
   /// CHECK-DAG: Phi      loop:<<Loop:B\d+>> outer_loop:none
   /// CHECK-DAG: VecLoad  loop:<<Loop>>      outer_loop:none
@@ -128,6 +152,12 @@
   /// CHECK-DAG: ArrayGet loop:<<Loop>>      outer_loop:none
   /// CHECK-DAG: ArraySet loop:<<Loop>>      outer_loop:none
   //
+  /// CHECK-START-ARM: void Main.not() loop_optimization (after)
+  /// CHECK-DAG: Phi      loop:<<Loop:B\d+>> outer_loop:none
+  /// CHECK-DAG: VecLoad  loop:<<Loop>>      outer_loop:none
+  /// CHECK-DAG: VecNot   loop:<<Loop>>      outer_loop:none
+  /// CHECK-DAG: VecStore loop:<<Loop>>      outer_loop:none
+  //
   /// CHECK-START-ARM64: void Main.not() loop_optimization (after)
   /// CHECK-DAG: Phi      loop:<<Loop:B\d+>> outer_loop:none
   /// CHECK-DAG: VecLoad  loop:<<Loop>>      outer_loop:none
@@ -149,6 +179,12 @@
   /// CHECK-DAG: ArrayGet loop:<<Loop>>      outer_loop:none
   /// CHECK-DAG: ArraySet loop:<<Loop>>      outer_loop:none
   //
+  /// CHECK-START-ARM: void Main.shl4() loop_optimization (after)
+  /// CHECK-DAG: Phi      loop:<<Loop:B\d+>> outer_loop:none
+  /// CHECK-DAG: VecLoad  loop:<<Loop>>      outer_loop:none
+  /// CHECK-DAG: VecShl   loop:<<Loop>>      outer_loop:none
+  /// CHECK-DAG: VecStore loop:<<Loop>>      outer_loop:none
+  //
   /// CHECK-START-ARM64: void Main.shl4() loop_optimization (after)
   /// CHECK-DAG: Phi      loop:<<Loop:B\d+>> outer_loop:none
   /// CHECK-DAG: VecLoad  loop:<<Loop>>      outer_loop:none
@@ -170,6 +206,12 @@
   /// CHECK-DAG: ArrayGet loop:<<Loop>>      outer_loop:none
   /// CHECK-DAG: ArraySet loop:<<Loop>>      outer_loop:none
   //
+  /// CHECK-START-ARM: void Main.sar2() loop_optimization (after)
+  /// CHECK-DAG: Phi      loop:<<Loop:B\d+>> outer_loop:none
+  /// CHECK-DAG: VecLoad  loop:<<Loop>>      outer_loop:none
+  /// CHECK-DAG: VecShr   loop:<<Loop>>      outer_loop:none
+  /// CHECK-DAG: VecStore loop:<<Loop>>      outer_loop:none
+  //
   /// CHECK-START-ARM64: void Main.sar2() loop_optimization (after)
   /// CHECK-DAG: Phi      loop:<<Loop:B\d+>> outer_loop:none
   /// CHECK-DAG: VecLoad  loop:<<Loop>>      outer_loop:none
diff --git a/test/645-checker-abs-simd/src/Main.java b/test/645-checker-abs-simd/src/Main.java
index 9714a46..c49d85d 100644
--- a/test/645-checker-abs-simd/src/Main.java
+++ b/test/645-checker-abs-simd/src/Main.java
@@ -28,6 +28,18 @@
   /// CHECK-DAG: InvokeStaticOrDirect intrinsic:MathAbsInt loop:<<Loop>>      outer_loop:none
   /// CHECK-DAG: ArraySet                                  loop:<<Loop>>      outer_loop:none
   //
+  /// CHECK-START-ARM: void Main.doitByte(byte[]) loop_optimization (after)
+  /// CHECK-DAG: Phi                                       loop:<<Loop1:B\d+>> outer_loop:none
+  /// CHECK-DAG: VecLoad                                   loop:<<Loop1>>      outer_loop:none
+  /// CHECK-DAG: VecAbs                                    loop:<<Loop1>>      outer_loop:none
+  /// CHECK-DAG: VecStore                                  loop:<<Loop1>>      outer_loop:none
+  /// CHECK-DAG: Phi                                       loop:<<Loop2:B\d+>> outer_loop:none
+  /// CHECK-DAG: ArrayGet                                  loop:<<Loop2>>      outer_loop:none
+  /// CHECK-DAG: InvokeStaticOrDirect intrinsic:MathAbsInt loop:<<Loop2>>      outer_loop:none
+  /// CHECK-DAG: ArraySet                                  loop:<<Loop2>>      outer_loop:none
+  //
+  /// CHECK-EVAL: "<<Loop1>>" != "<<Loop2>>"
+  //
   /// CHECK-START-ARM64: void Main.doitByte(byte[]) loop_optimization (after)
   /// CHECK-DAG: Phi                                       loop:<<Loop1:B\d+>> outer_loop:none
   /// CHECK-DAG: VecLoad                                   loop:<<Loop1>>      outer_loop:none
@@ -78,6 +90,18 @@
   /// CHECK-DAG: InvokeStaticOrDirect intrinsic:MathAbsInt loop:<<Loop>>      outer_loop:none
   /// CHECK-DAG: ArraySet                                  loop:<<Loop>>      outer_loop:none
   //
+  /// CHECK-START-ARM: void Main.doitShort(short[]) loop_optimization (after)
+  /// CHECK-DAG: Phi                                       loop:<<Loop1:B\d+>> outer_loop:none
+  /// CHECK-DAG: VecLoad                                   loop:<<Loop1>>      outer_loop:none
+  /// CHECK-DAG: VecAbs                                    loop:<<Loop1>>      outer_loop:none
+  /// CHECK-DAG: VecStore                                  loop:<<Loop1>>      outer_loop:none
+  /// CHECK-DAG: Phi                                       loop:<<Loop2:B\d+>> outer_loop:none
+  /// CHECK-DAG: ArrayGet                                  loop:<<Loop2>>      outer_loop:none
+  /// CHECK-DAG: InvokeStaticOrDirect intrinsic:MathAbsInt loop:<<Loop2>>      outer_loop:none
+  /// CHECK-DAG: ArraySet                                  loop:<<Loop2>>      outer_loop:none
+  //
+  /// CHECK-EVAL: "<<Loop1>>" != "<<Loop2>>"
+  //
   /// CHECK-START-ARM64: void Main.doitShort(short[]) loop_optimization (after)
   /// CHECK-DAG: Phi                                       loop:<<Loop1:B\d+>> outer_loop:none
   /// CHECK-DAG: VecLoad                                   loop:<<Loop1>>      outer_loop:none
@@ -113,6 +137,18 @@
   /// CHECK-DAG: InvokeStaticOrDirect intrinsic:MathAbsInt loop:<<Loop>>      outer_loop:none
   /// CHECK-DAG: ArraySet                                  loop:<<Loop>>      outer_loop:none
   //
+  /// CHECK-START-ARM: void Main.doitInt(int[]) loop_optimization (after)
+  /// CHECK-DAG: Phi                                       loop:<<Loop1:B\d+>> outer_loop:none
+  /// CHECK-DAG: VecLoad                                   loop:<<Loop1>>      outer_loop:none
+  /// CHECK-DAG: VecAbs                                    loop:<<Loop1>>      outer_loop:none
+  /// CHECK-DAG: VecStore                                  loop:<<Loop1>>      outer_loop:none
+  /// CHECK-DAG: Phi                                       loop:<<Loop2:B\d+>> outer_loop:none
+  /// CHECK-DAG: ArrayGet                                  loop:<<Loop2>>      outer_loop:none
+  /// CHECK-DAG: InvokeStaticOrDirect intrinsic:MathAbsInt loop:<<Loop2>>      outer_loop:none
+  /// CHECK-DAG: ArraySet                                  loop:<<Loop2>>      outer_loop:none
+  //
+  /// CHECK-EVAL: "<<Loop1>>" != "<<Loop2>>"
+  //
   /// CHECK-START-ARM64: void Main.doitInt(int[]) loop_optimization (after)
   /// CHECK-DAG: Phi                                       loop:<<Loop1:B\d+>> outer_loop:none
   /// CHECK-DAG: VecLoad                                   loop:<<Loop1>>      outer_loop:none
diff --git a/test/646-checker-hadd-alt-byte/src/Main.java b/test/646-checker-hadd-alt-byte/src/Main.java
index 9cc6828..7be3151 100644
--- a/test/646-checker-hadd-alt-byte/src/Main.java
+++ b/test/646-checker-hadd-alt-byte/src/Main.java
@@ -39,6 +39,13 @@
   /// CHECK-DAG: <<Cnv:b\d+>>  TypeConversion [<<UShr>>]           loop:<<Loop>>      outer_loop:none
   /// CHECK-DAG:               ArraySet [{{l\d+}},<<Phi>>,<<Cnv>>] loop:<<Loop>>      outer_loop:none
   //
+  /// CHECK-START-ARM: void Main.halving_add_signed(byte[], byte[], byte[]) loop_optimization (after)
+  /// CHECK-DAG: <<Phi:i\d+>>  Phi                                  loop:<<Loop:B\d+>> outer_loop:none
+  /// CHECK-DAG: <<Get1:d\d+>> VecLoad                              loop:<<Loop>>      outer_loop:none
+  /// CHECK-DAG: <<Get2:d\d+>> VecLoad                              loop:<<Loop>>      outer_loop:none
+  /// CHECK-DAG: <<HAdd:d\d+>> VecHalvingAdd [<<Get1>>,<<Get2>>] unsigned:false rounded:false loop:<<Loop>> outer_loop:none
+  /// CHECK-DAG:               VecStore [{{l\d+}},<<Phi>>,<<HAdd>>] loop:<<Loop>>      outer_loop:none
+  //
   /// CHECK-START-ARM64: void Main.halving_add_signed(byte[], byte[], byte[]) loop_optimization (after)
   /// CHECK-DAG: <<Phi:i\d+>>  Phi                                  loop:<<Loop:B\d+>> outer_loop:none
   /// CHECK-DAG: <<Get1:d\d+>> VecLoad                              loop:<<Loop>>      outer_loop:none
@@ -72,6 +79,13 @@
   /// CHECK-DAG: <<Cnv:b\d+>>  TypeConversion [<<UShr>>]           loop:<<Loop>>      outer_loop:none
   /// CHECK-DAG:               ArraySet [{{l\d+}},<<Phi>>,<<Cnv>>] loop:<<Loop>>      outer_loop:none
   //
+  /// CHECK-START-ARM: void Main.halving_add_unsigned(byte[], byte[], byte[]) loop_optimization (after)
+  /// CHECK-DAG: <<Phi:i\d+>>  Phi                                  loop:<<Loop:B\d+>> outer_loop:none
+  /// CHECK-DAG: <<Get1:d\d+>> VecLoad                              loop:<<Loop>>      outer_loop:none
+  /// CHECK-DAG: <<Get2:d\d+>> VecLoad                              loop:<<Loop>>      outer_loop:none
+  /// CHECK-DAG: <<HAdd:d\d+>> VecHalvingAdd [<<Get1>>,<<Get2>>] unsigned:true rounded:false loop:<<Loop>> outer_loop:none
+  /// CHECK-DAG:               VecStore [{{l\d+}},<<Phi>>,<<HAdd>>] loop:<<Loop>>      outer_loop:none
+  //
   /// CHECK-START-ARM64: void Main.halving_add_unsigned(byte[], byte[], byte[]) loop_optimization (after)
   /// CHECK-DAG: <<Phi:i\d+>>  Phi                                  loop:<<Loop:B\d+>> outer_loop:none
   /// CHECK-DAG: <<Get1:d\d+>> VecLoad                              loop:<<Loop>>      outer_loop:none
@@ -103,6 +117,13 @@
   /// CHECK-DAG: <<Cnv:b\d+>>  TypeConversion [<<UShr>>]           loop:<<Loop>>      outer_loop:none
   /// CHECK-DAG:               ArraySet [{{l\d+}},<<Phi>>,<<Cnv>>] loop:<<Loop>>      outer_loop:none
   //
+  /// CHECK-START-ARM: void Main.rounding_halving_add_signed(byte[], byte[], byte[]) loop_optimization (after)
+  /// CHECK-DAG: <<Phi:i\d+>>  Phi                                  loop:<<Loop:B\d+>> outer_loop:none
+  /// CHECK-DAG: <<Get1:d\d+>> VecLoad                              loop:<<Loop>>      outer_loop:none
+  /// CHECK-DAG: <<Get2:d\d+>> VecLoad                              loop:<<Loop>>      outer_loop:none
+  /// CHECK-DAG: <<HAdd:d\d+>> VecHalvingAdd [<<Get1>>,<<Get2>>] unsigned:false rounded:true loop:<<Loop>> outer_loop:none
+  /// CHECK-DAG:               VecStore [{{l\d+}},<<Phi>>,<<HAdd>>] loop:<<Loop>>      outer_loop:none
+  //
   /// CHECK-START-ARM64: void Main.rounding_halving_add_signed(byte[], byte[], byte[]) loop_optimization (after)
   /// CHECK-DAG: <<Phi:i\d+>>  Phi                                  loop:<<Loop:B\d+>> outer_loop:none
   /// CHECK-DAG: <<Get1:d\d+>> VecLoad                              loop:<<Loop>>      outer_loop:none
@@ -137,6 +158,13 @@
   /// CHECK-DAG: <<Cnv:b\d+>>  TypeConversion [<<UShr>>]           loop:<<Loop>>      outer_loop:none
   /// CHECK-DAG:               ArraySet [{{l\d+}},<<Phi>>,<<Cnv>>] loop:<<Loop>>      outer_loop:none
   //
+  /// CHECK-START-ARM: void Main.rounding_halving_add_unsigned(byte[], byte[], byte[]) loop_optimization (after)
+  /// CHECK-DAG: <<Phi:i\d+>>  Phi                                  loop:<<Loop:B\d+>> outer_loop:none
+  /// CHECK-DAG: <<Get1:d\d+>> VecLoad                              loop:<<Loop>>      outer_loop:none
+  /// CHECK-DAG: <<Get2:d\d+>> VecLoad                              loop:<<Loop>>      outer_loop:none
+  /// CHECK-DAG: <<HAdd:d\d+>> VecHalvingAdd [<<Get1>>,<<Get2>>]  unsigned:true rounded:true loop:<<Loop>> outer_loop:none
+  /// CHECK-DAG:               VecStore [{{l\d+}},<<Phi>>,<<HAdd>>] loop:<<Loop>>      outer_loop:none
+  //
   /// CHECK-START-ARM64: void Main.rounding_halving_add_unsigned(byte[], byte[], byte[]) loop_optimization (after)
   /// CHECK-DAG: <<Phi:i\d+>>  Phi                                  loop:<<Loop:B\d+>> outer_loop:none
   /// CHECK-DAG: <<Get1:d\d+>> VecLoad                              loop:<<Loop>>      outer_loop:none
@@ -167,6 +195,14 @@
   /// CHECK-DAG: <<Cnv:b\d+>>  TypeConversion [<<UShr>>]           loop:<<Loop>>      outer_loop:none
   /// CHECK-DAG:               ArraySet [{{l\d+}},<<Phi>>,<<Cnv>>] loop:<<Loop>>      outer_loop:none
   //
+  /// CHECK-START-ARM: void Main.halving_add_signed_constant(byte[], byte[]) loop_optimization (after)
+  /// CHECK-DAG: <<I127:i\d+>> IntConstant 127                      loop:none
+  /// CHECK-DAG: <<Repl:d\d+>> VecReplicateScalar [<<I127>>]        loop:none
+  /// CHECK-DAG: <<Phi:i\d+>>  Phi                                  loop:<<Loop:B\d+>> outer_loop:none
+  /// CHECK-DAG: <<Get:d\d+>>  VecLoad                              loop:<<Loop>>      outer_loop:none
+  /// CHECK-DAG: <<HAdd:d\d+>> VecHalvingAdd [<<Get>>,<<Repl>>] unsigned:false rounded:false loop:<<Loop>> outer_loop:none
+  /// CHECK-DAG:               VecStore [{{l\d+}},<<Phi>>,<<HAdd>>] loop:<<Loop>>      outer_loop:none
+  //
   /// CHECK-START-ARM64: void Main.halving_add_signed_constant(byte[], byte[]) loop_optimization (after)
   /// CHECK-DAG: <<I127:i\d+>> IntConstant 127                      loop:none
   /// CHECK-DAG: <<Repl:d\d+>> VecReplicateScalar [<<I127>>]        loop:none
@@ -200,6 +236,14 @@
   /// CHECK-DAG: <<Cnv:b\d+>>  TypeConversion [<<UShr>>]           loop:<<Loop>>      outer_loop:none
   /// CHECK-DAG:               ArraySet [{{l\d+}},<<Phi>>,<<Cnv>>] loop:<<Loop>>      outer_loop:none
   //
+  /// CHECK-START-ARM: void Main.halving_add_unsigned_constant(byte[], byte[]) loop_optimization (after)
+  /// CHECK-DAG: <<I255:i\d+>> IntConstant 255                      loop:none
+  /// CHECK-DAG: <<Repl:d\d+>> VecReplicateScalar [<<I255>>]        loop:none
+  /// CHECK-DAG: <<Phi:i\d+>>  Phi                                  loop:<<Loop:B\d+>> outer_loop:none
+  /// CHECK-DAG: <<Get:d\d+>>  VecLoad                              loop:<<Loop>>      outer_loop:none
+  /// CHECK-DAG: <<HAdd:d\d+>> VecHalvingAdd [<<Get>>,<<Repl>>] unsigned:true rounded:false loop:<<Loop>> outer_loop:none
+  /// CHECK-DAG:               VecStore [{{l\d+}},<<Phi>>,<<HAdd>>] loop:<<Loop>>      outer_loop:none
+  //
   /// CHECK-START-ARM64: void Main.halving_add_unsigned_constant(byte[], byte[]) loop_optimization (after)
   /// CHECK-DAG: <<I255:i\d+>> IntConstant 255                      loop:none
   /// CHECK-DAG: <<Repl:d\d+>> VecReplicateScalar [<<I255>>]        loop:none
diff --git a/test/646-checker-hadd-alt-char/src/Main.java b/test/646-checker-hadd-alt-char/src/Main.java
index 3f81299..2799ea7 100644
--- a/test/646-checker-hadd-alt-char/src/Main.java
+++ b/test/646-checker-hadd-alt-char/src/Main.java
@@ -39,6 +39,13 @@
   /// CHECK-DAG: <<Cnv:c\d+>>  TypeConversion [<<UShr>>]           loop:<<Loop>>      outer_loop:none
   /// CHECK-DAG:               ArraySet [{{l\d+}},<<Phi>>,<<Cnv>>] loop:<<Loop>>      outer_loop:none
   //
+  /// CHECK-START-ARM: void Main.halving_add_unsigned(char[], char[], char[]) loop_optimization (after)
+  /// CHECK-DAG: <<Phi:i\d+>>  Phi                                  loop:<<Loop:B\d+>> outer_loop:none
+  /// CHECK-DAG: <<Get1:d\d+>> VecLoad                              loop:<<Loop>>      outer_loop:none
+  /// CHECK-DAG: <<Get2:d\d+>> VecLoad                              loop:<<Loop>>      outer_loop:none
+  /// CHECK-DAG: <<HAdd:d\d+>> VecHalvingAdd [<<Get1>>,<<Get2>>] unsigned:true rounded:false loop:<<Loop>> outer_loop:none
+  /// CHECK-DAG:               VecStore [{{l\d+}},<<Phi>>,<<HAdd>>] loop:<<Loop>>      outer_loop:none
+  //
   /// CHECK-START-ARM64: void Main.halving_add_unsigned(char[], char[], char[]) loop_optimization (after)
   /// CHECK-DAG: <<Phi:i\d+>>  Phi                                  loop:<<Loop:B\d+>> outer_loop:none
   /// CHECK-DAG: <<Get1:d\d+>> VecLoad                              loop:<<Loop>>      outer_loop:none
@@ -72,6 +79,13 @@
   /// CHECK-DAG: <<Cnv:c\d+>>  TypeConversion [<<UShr>>]           loop:<<Loop>>      outer_loop:none
   /// CHECK-DAG:               ArraySet [{{l\d+}},<<Phi>>,<<Cnv>>] loop:<<Loop>>      outer_loop:none
   //
+  /// CHECK-START-ARM: void Main.halving_add_also_unsigned(char[], char[], char[]) loop_optimization (after)
+  /// CHECK-DAG: <<Phi:i\d+>>  Phi                                  loop:<<Loop:B\d+>> outer_loop:none
+  /// CHECK-DAG: <<Get1:d\d+>> VecLoad                              loop:<<Loop>>      outer_loop:none
+  /// CHECK-DAG: <<Get2:d\d+>> VecLoad                              loop:<<Loop>>      outer_loop:none
+  /// CHECK-DAG: <<HAdd:d\d+>> VecHalvingAdd [<<Get1>>,<<Get2>>] unsigned:true rounded:false loop:<<Loop>> outer_loop:none
+  /// CHECK-DAG:               VecStore [{{l\d+}},<<Phi>>,<<HAdd>>] loop:<<Loop>>      outer_loop:none
+  //
   /// CHECK-START-ARM64: void Main.halving_add_also_unsigned(char[], char[], char[]) loop_optimization (after)
   /// CHECK-DAG: <<Phi:i\d+>>  Phi                                  loop:<<Loop:B\d+>> outer_loop:none
   /// CHECK-DAG: <<Get1:d\d+>> VecLoad                              loop:<<Loop>>      outer_loop:none
@@ -106,6 +120,13 @@
   /// CHECK-DAG: <<Cnv:c\d+>>  TypeConversion [<<UShr>>]           loop:<<Loop>>      outer_loop:none
   /// CHECK-DAG:               ArraySet [{{l\d+}},<<Phi>>,<<Cnv>>] loop:<<Loop>>      outer_loop:none
   //
+  /// CHECK-START-ARM: void Main.rounding_halving_add_unsigned(char[], char[], char[]) loop_optimization (after)
+  /// CHECK-DAG: <<Phi:i\d+>>  Phi                                  loop:<<Loop:B\d+>> outer_loop:none
+  /// CHECK-DAG: <<Get1:d\d+>> VecLoad                              loop:<<Loop>>      outer_loop:none
+  /// CHECK-DAG: <<Get2:d\d+>> VecLoad                              loop:<<Loop>>      outer_loop:none
+  /// CHECK-DAG: <<HAdd:d\d+>> VecHalvingAdd [<<Get1>>,<<Get2>>] unsigned:true rounded:true loop:<<Loop>> outer_loop:none
+  /// CHECK-DAG:               VecStore [{{l\d+}},<<Phi>>,<<HAdd>>] loop:<<Loop>>      outer_loop:none
+  //
   /// CHECK-START-ARM64: void Main.rounding_halving_add_unsigned(char[], char[], char[]) loop_optimization (after)
   /// CHECK-DAG: <<Phi:i\d+>>  Phi                                  loop:<<Loop:B\d+>> outer_loop:none
   /// CHECK-DAG: <<Get1:d\d+>> VecLoad                              loop:<<Loop>>      outer_loop:none
@@ -140,6 +161,13 @@
   /// CHECK-DAG: <<Cnv:c\d+>>  TypeConversion [<<UShr>>]           loop:<<Loop>>      outer_loop:none
   /// CHECK-DAG:               ArraySet [{{l\d+}},<<Phi>>,<<Cnv>>] loop:<<Loop>>      outer_loop:none
   //
+  /// CHECK-START-ARM: void Main.rounding_halving_add_also_unsigned(char[], char[], char[]) loop_optimization (after)
+  /// CHECK-DAG: <<Phi:i\d+>>  Phi                                  loop:<<Loop:B\d+>> outer_loop:none
+  /// CHECK-DAG: <<Get1:d\d+>> VecLoad                              loop:<<Loop>>      outer_loop:none
+  /// CHECK-DAG: <<Get2:d\d+>> VecLoad                              loop:<<Loop>>      outer_loop:none
+  /// CHECK-DAG: <<HAdd:d\d+>> VecHalvingAdd [<<Get1>>,<<Get2>>] unsigned:true rounded:true loop:<<Loop>> outer_loop:none
+  /// CHECK-DAG:               VecStore [{{l\d+}},<<Phi>>,<<HAdd>>] loop:<<Loop>>      outer_loop:none
+  //
   /// CHECK-START-ARM64: void Main.rounding_halving_add_also_unsigned(char[], char[], char[]) loop_optimization (after)
   /// CHECK-DAG: <<Phi:i\d+>>  Phi                                  loop:<<Loop:B\d+>> outer_loop:none
   /// CHECK-DAG: <<Get1:d\d+>> VecLoad                              loop:<<Loop>>      outer_loop:none
@@ -173,6 +201,14 @@
   /// CHECK-DAG: <<Cnv:c\d+>>  TypeConversion [<<UShr>>]           loop:<<Loop>>      outer_loop:none
   /// CHECK-DAG:               ArraySet [{{l\d+}},<<Phi>>,<<Cnv>>] loop:<<Loop>>      outer_loop:none
   //
+  /// CHECK-START-ARM: void Main.halving_add_unsigned_constant(char[], char[]) loop_optimization (after)
+  /// CHECK-DAG: <<UMAX:i\d+>> IntConstant 65535                    loop:none
+  /// CHECK-DAG: <<Repl:d\d+>> VecReplicateScalar [<<UMAX>>]        loop:none
+  /// CHECK-DAG: <<Phi:i\d+>>  Phi                                  loop:<<Loop:B\d+>> outer_loop:none
+  /// CHECK-DAG: <<Get:d\d+>>  VecLoad                              loop:<<Loop>>      outer_loop:none
+  /// CHECK-DAG: <<HAdd:d\d+>> VecHalvingAdd [<<Get>>,<<Repl>>] unsigned:true rounded:false loop:<<Loop>> outer_loop:none
+  /// CHECK-DAG:               VecStore [{{l\d+}},<<Phi>>,<<HAdd>>] loop:<<Loop>>      outer_loop:none
+  //
   /// CHECK-START-ARM64: void Main.halving_add_unsigned_constant(char[], char[]) loop_optimization (after)
   /// CHECK-DAG: <<UMAX:i\d+>> IntConstant 65535                    loop:none
   /// CHECK-DAG: <<Repl:d\d+>> VecReplicateScalar [<<UMAX>>]        loop:none
diff --git a/test/646-checker-hadd-alt-short/src/Main.java b/test/646-checker-hadd-alt-short/src/Main.java
index 150626c..6cd102f 100644
--- a/test/646-checker-hadd-alt-short/src/Main.java
+++ b/test/646-checker-hadd-alt-short/src/Main.java
@@ -39,6 +39,13 @@
   /// CHECK-DAG: <<Cnv:s\d+>>  TypeConversion [<<UShr>>]           loop:<<Loop>>      outer_loop:none
   /// CHECK-DAG:               ArraySet [{{l\d+}},<<Phi>>,<<Cnv>>] loop:<<Loop>>      outer_loop:none
   //
+  /// CHECK-START-ARM: void Main.halving_add_signed(short[], short[], short[]) loop_optimization (after)
+  /// CHECK-DAG: <<Phi:i\d+>>  Phi                                  loop:<<Loop:B\d+>> outer_loop:none
+  /// CHECK-DAG: <<Get1:d\d+>> VecLoad                              loop:<<Loop>>      outer_loop:none
+  /// CHECK-DAG: <<Get2:d\d+>> VecLoad                              loop:<<Loop>>      outer_loop:none
+  /// CHECK-DAG: <<HAdd:d\d+>> VecHalvingAdd [<<Get1>>,<<Get2>>] unsigned:false rounded:false loop:<<Loop>> outer_loop:none
+  /// CHECK-DAG:               VecStore [{{l\d+}},<<Phi>>,<<HAdd>>] loop:<<Loop>>      outer_loop:none
+  //
   /// CHECK-START-ARM64: void Main.halving_add_signed(short[], short[], short[]) loop_optimization (after)
   /// CHECK-DAG: <<Phi:i\d+>>  Phi                                  loop:<<Loop:B\d+>> outer_loop:none
   /// CHECK-DAG: <<Get1:d\d+>> VecLoad                              loop:<<Loop>>      outer_loop:none
@@ -72,6 +79,13 @@
   /// CHECK-DAG: <<Cnv:s\d+>>  TypeConversion [<<UShr>>]           loop:<<Loop>>      outer_loop:none
   /// CHECK-DAG:               ArraySet [{{l\d+}},<<Phi>>,<<Cnv>>] loop:<<Loop>>      outer_loop:none
   //
+  /// CHECK-START-ARM: void Main.halving_add_unsigned(short[], short[], short[]) loop_optimization (after)
+  /// CHECK-DAG: <<Phi:i\d+>>  Phi                                  loop:<<Loop:B\d+>> outer_loop:none
+  /// CHECK-DAG: <<Get1:d\d+>> VecLoad                              loop:<<Loop>>      outer_loop:none
+  /// CHECK-DAG: <<Get2:d\d+>> VecLoad                              loop:<<Loop>>      outer_loop:none
+  /// CHECK-DAG: <<HAdd:d\d+>> VecHalvingAdd [<<Get1>>,<<Get2>>] unsigned:true rounded:false loop:<<Loop>> outer_loop:none
+  /// CHECK-DAG:               VecStore [{{l\d+}},<<Phi>>,<<HAdd>>] loop:<<Loop>>      outer_loop:none
+  //
   /// CHECK-START-ARM64: void Main.halving_add_unsigned(short[], short[], short[]) loop_optimization (after)
   /// CHECK-DAG: <<Phi:i\d+>>  Phi                                  loop:<<Loop:B\d+>> outer_loop:none
   /// CHECK-DAG: <<Get1:d\d+>> VecLoad                              loop:<<Loop>>      outer_loop:none
@@ -103,6 +117,13 @@
   /// CHECK-DAG: <<Cnv:s\d+>>  TypeConversion [<<UShr>>]           loop:<<Loop>>      outer_loop:none
   /// CHECK-DAG:               ArraySet [{{l\d+}},<<Phi>>,<<Cnv>>] loop:<<Loop>>      outer_loop:none
   //
+  /// CHECK-START-ARM: void Main.rounding_halving_add_signed(short[], short[], short[]) loop_optimization (after)
+  /// CHECK-DAG: <<Phi:i\d+>>  Phi                                  loop:<<Loop:B\d+>> outer_loop:none
+  /// CHECK-DAG: <<Get1:d\d+>> VecLoad                              loop:<<Loop>>      outer_loop:none
+  /// CHECK-DAG: <<Get2:d\d+>> VecLoad                              loop:<<Loop>>      outer_loop:none
+  /// CHECK-DAG: <<HAdd:d\d+>> VecHalvingAdd [<<Get1>>,<<Get2>>] unsigned:false rounded:true loop:<<Loop>> outer_loop:none
+  /// CHECK-DAG:               VecStore [{{l\d+}},<<Phi>>,<<HAdd>>] loop:<<Loop>>      outer_loop:none
+  //
   /// CHECK-START-ARM64: void Main.rounding_halving_add_signed(short[], short[], short[]) loop_optimization (after)
   /// CHECK-DAG: <<Phi:i\d+>>  Phi                                  loop:<<Loop:B\d+>> outer_loop:none
   /// CHECK-DAG: <<Get1:d\d+>> VecLoad                              loop:<<Loop>>      outer_loop:none
@@ -137,6 +158,13 @@
   /// CHECK-DAG: <<Cnv:s\d+>>  TypeConversion [<<UShr>>]           loop:<<Loop>>      outer_loop:none
   /// CHECK-DAG:               ArraySet [{{l\d+}},<<Phi>>,<<Cnv>>] loop:<<Loop>>      outer_loop:none
   //
+  /// CHECK-START-ARM: void Main.rounding_halving_add_unsigned(short[], short[], short[]) loop_optimization (after)
+  /// CHECK-DAG: <<Phi:i\d+>>  Phi                                  loop:<<Loop:B\d+>> outer_loop:none
+  /// CHECK-DAG: <<Get1:d\d+>> VecLoad                              loop:<<Loop>>      outer_loop:none
+  /// CHECK-DAG: <<Get2:d\d+>> VecLoad                              loop:<<Loop>>      outer_loop:none
+  /// CHECK-DAG: <<HAdd:d\d+>> VecHalvingAdd [<<Get1>>,<<Get2>>] unsigned:true rounded:true loop:<<Loop>> outer_loop:none
+  /// CHECK-DAG:               VecStore [{{l\d+}},<<Phi>>,<<HAdd>>] loop:<<Loop>>      outer_loop:none
+  //
   /// CHECK-START-ARM64: void Main.rounding_halving_add_unsigned(short[], short[], short[]) loop_optimization (after)
   /// CHECK-DAG: <<Phi:i\d+>>  Phi                                  loop:<<Loop:B\d+>> outer_loop:none
   /// CHECK-DAG: <<Get1:d\d+>> VecLoad                              loop:<<Loop>>      outer_loop:none
@@ -167,6 +195,14 @@
   /// CHECK-DAG: <<Cnv:s\d+>>  TypeConversion [<<UShr>>]           loop:<<Loop>>      outer_loop:none
   /// CHECK-DAG:               ArraySet [{{l\d+}},<<Phi>>,<<Cnv>>] loop:<<Loop>>      outer_loop:none
   //
+  /// CHECK-START-ARM: void Main.halving_add_signed_constant(short[], short[]) loop_optimization (after)
+  /// CHECK-DAG: <<SMAX:i\d+>> IntConstant 32767                    loop:none
+  /// CHECK-DAG: <<Repl:d\d+>> VecReplicateScalar [<<SMAX>>]        loop:none
+  /// CHECK-DAG: <<Phi:i\d+>>  Phi                                  loop:<<Loop:B\d+>> outer_loop:none
+  /// CHECK-DAG: <<Get:d\d+>>  VecLoad                              loop:<<Loop>>      outer_loop:none
+  /// CHECK-DAG: <<HAdd:d\d+>> VecHalvingAdd [<<Get>>,<<Repl>>] unsigned:false rounded:false loop:<<Loop>> outer_loop:none
+  /// CHECK-DAG:               VecStore [{{l\d+}},<<Phi>>,<<HAdd>>] loop:<<Loop>>      outer_loop:none
+  //
   /// CHECK-START-ARM64: void Main.halving_add_signed_constant(short[], short[]) loop_optimization (after)
   /// CHECK-DAG: <<SMAX:i\d+>> IntConstant 32767                    loop:none
   /// CHECK-DAG: <<Repl:d\d+>> VecReplicateScalar [<<SMAX>>]        loop:none
@@ -200,6 +236,14 @@
   /// CHECK-DAG: <<Cnv:s\d+>>  TypeConversion [<<UShr>>]           loop:<<Loop>>      outer_loop:none
   /// CHECK-DAG:               ArraySet [{{l\d+}},<<Phi>>,<<Cnv>>] loop:<<Loop>>      outer_loop:none
   //
+  /// CHECK-START-ARM: void Main.halving_add_unsigned_constant(short[], short[]) loop_optimization (after)
+  /// CHECK-DAG: <<UMAX:i\d+>> IntConstant 65535                    loop:none
+  /// CHECK-DAG: <<Repl:d\d+>> VecReplicateScalar [<<UMAX>>]        loop:none
+  /// CHECK-DAG: <<Phi:i\d+>>  Phi                                  loop:<<Loop:B\d+>> outer_loop:none
+  /// CHECK-DAG: <<Get:d\d+>>  VecLoad                              loop:<<Loop>>      outer_loop:none
+  /// CHECK-DAG: <<HAdd:d\d+>> VecHalvingAdd [<<Get>>,<<Repl>>] unsigned:true rounded:false loop:<<Loop>> outer_loop:none
+  /// CHECK-DAG:               VecStore [{{l\d+}},<<Phi>>,<<HAdd>>] loop:<<Loop>>      outer_loop:none
+  //
   /// CHECK-START-ARM64: void Main.halving_add_unsigned_constant(short[], short[]) loop_optimization (after)
   /// CHECK-DAG: <<UMAX:i\d+>> IntConstant 65535                    loop:none
   /// CHECK-DAG: <<Repl:d\d+>> VecReplicateScalar [<<UMAX>>]        loop:none
diff --git a/test/646-checker-hadd-byte/src/Main.java b/test/646-checker-hadd-byte/src/Main.java
index 5a615a4..a9e844c 100644
--- a/test/646-checker-hadd-byte/src/Main.java
+++ b/test/646-checker-hadd-byte/src/Main.java
@@ -36,6 +36,13 @@
   /// CHECK-DAG: <<Cnv:b\d+>>  TypeConversion [<<Shr>>]            loop:<<Loop>>      outer_loop:none
   /// CHECK-DAG:               ArraySet [{{l\d+}},<<Phi>>,<<Cnv>>] loop:<<Loop>>      outer_loop:none
   //
+  /// CHECK-START-ARM: void Main.halving_add_signed(byte[], byte[], byte[]) loop_optimization (after)
+  /// CHECK-DAG: <<Phi:i\d+>>  Phi                                  loop:<<Loop:B\d+>> outer_loop:none
+  /// CHECK-DAG: <<Get1:d\d+>> VecLoad                              loop:<<Loop>>      outer_loop:none
+  /// CHECK-DAG: <<Get2:d\d+>> VecLoad                              loop:<<Loop>>      outer_loop:none
+  /// CHECK-DAG: <<HAdd:d\d+>> VecHalvingAdd [<<Get1>>,<<Get2>>] unsigned:false rounded:false loop:<<Loop>> outer_loop:none
+  /// CHECK-DAG:               VecStore [{{l\d+}},<<Phi>>,<<HAdd>>] loop:<<Loop>>      outer_loop:none
+  //
   /// CHECK-START-ARM64: void Main.halving_add_signed(byte[], byte[], byte[]) loop_optimization (after)
   /// CHECK-DAG: <<Phi:i\d+>>  Phi                                  loop:<<Loop:B\d+>> outer_loop:none
   /// CHECK-DAG: <<Get1:d\d+>> VecLoad                              loop:<<Loop>>      outer_loop:none
@@ -69,6 +76,13 @@
   /// CHECK-DAG: <<Cnv:b\d+>>  TypeConversion [<<Shr>>]            loop:<<Loop>>      outer_loop:none
   /// CHECK-DAG:               ArraySet [{{l\d+}},<<Phi>>,<<Cnv>>] loop:<<Loop>>      outer_loop:none
   //
+  /// CHECK-START-ARM: void Main.halving_add_unsigned(byte[], byte[], byte[]) loop_optimization (after)
+  /// CHECK-DAG: <<Phi:i\d+>>  Phi                                  loop:<<Loop:B\d+>> outer_loop:none
+  /// CHECK-DAG: <<Get1:d\d+>> VecLoad                              loop:<<Loop>>      outer_loop:none
+  /// CHECK-DAG: <<Get2:d\d+>> VecLoad                              loop:<<Loop>>      outer_loop:none
+  /// CHECK-DAG: <<HAdd:d\d+>> VecHalvingAdd [<<Get1>>,<<Get2>>] unsigned:true rounded:false loop:<<Loop>> outer_loop:none
+  /// CHECK-DAG:               VecStore [{{l\d+}},<<Phi>>,<<HAdd>>] loop:<<Loop>>      outer_loop:none
+  //
   /// CHECK-START-ARM64: void Main.halving_add_unsigned(byte[], byte[], byte[]) loop_optimization (after)
   /// CHECK-DAG: <<Phi:i\d+>>  Phi                                  loop:<<Loop:B\d+>> outer_loop:none
   /// CHECK-DAG: <<Get1:d\d+>> VecLoad                              loop:<<Loop>>      outer_loop:none
@@ -100,6 +114,13 @@
   /// CHECK-DAG: <<Cnv:b\d+>>  TypeConversion [<<Shr>>]            loop:<<Loop>>      outer_loop:none
   /// CHECK-DAG:               ArraySet [{{l\d+}},<<Phi>>,<<Cnv>>] loop:<<Loop>>      outer_loop:none
   //
+  /// CHECK-START-ARM: void Main.rounding_halving_add_signed(byte[], byte[], byte[]) loop_optimization (after)
+  /// CHECK-DAG: <<Phi:i\d+>>  Phi                                  loop:<<Loop:B\d+>> outer_loop:none
+  /// CHECK-DAG: <<Get1:d\d+>> VecLoad                              loop:<<Loop>>      outer_loop:none
+  /// CHECK-DAG: <<Get2:d\d+>> VecLoad                              loop:<<Loop>>      outer_loop:none
+  /// CHECK-DAG: <<HAdd:d\d+>> VecHalvingAdd [<<Get1>>,<<Get2>>] unsigned:false rounded:true loop:<<Loop>> outer_loop:none
+  /// CHECK-DAG:               VecStore [{{l\d+}},<<Phi>>,<<HAdd>>] loop:<<Loop>>      outer_loop:none
+  //
   /// CHECK-START-ARM64: void Main.rounding_halving_add_signed(byte[], byte[], byte[]) loop_optimization (after)
   /// CHECK-DAG: <<Phi:i\d+>>  Phi                                  loop:<<Loop:B\d+>> outer_loop:none
   /// CHECK-DAG: <<Get1:d\d+>> VecLoad                              loop:<<Loop>>      outer_loop:none
@@ -134,6 +155,13 @@
   /// CHECK-DAG: <<Cnv:b\d+>>  TypeConversion [<<Shr>>]            loop:<<Loop>>      outer_loop:none
   /// CHECK-DAG:               ArraySet [{{l\d+}},<<Phi>>,<<Cnv>>] loop:<<Loop>>      outer_loop:none
   //
+  /// CHECK-START-ARM: void Main.rounding_halving_add_unsigned(byte[], byte[], byte[]) loop_optimization (after)
+  /// CHECK-DAG: <<Phi:i\d+>>  Phi                                  loop:<<Loop:B\d+>> outer_loop:none
+  /// CHECK-DAG: <<Get1:d\d+>> VecLoad                              loop:<<Loop>>      outer_loop:none
+  /// CHECK-DAG: <<Get2:d\d+>> VecLoad                              loop:<<Loop>>      outer_loop:none
+  /// CHECK-DAG: <<HAdd:d\d+>> VecHalvingAdd [<<Get1>>,<<Get2>>]  unsigned:true rounded:true loop:<<Loop>> outer_loop:none
+  /// CHECK-DAG:               VecStore [{{l\d+}},<<Phi>>,<<HAdd>>] loop:<<Loop>>      outer_loop:none
+  //
   /// CHECK-START-ARM64: void Main.rounding_halving_add_unsigned(byte[], byte[], byte[]) loop_optimization (after)
   /// CHECK-DAG: <<Phi:i\d+>>  Phi                                  loop:<<Loop:B\d+>> outer_loop:none
   /// CHECK-DAG: <<Get1:d\d+>> VecLoad                              loop:<<Loop>>      outer_loop:none
@@ -164,6 +192,14 @@
   /// CHECK-DAG: <<Cnv:b\d+>>  TypeConversion [<<Shr>>]            loop:<<Loop>>      outer_loop:none
   /// CHECK-DAG:               ArraySet [{{l\d+}},<<Phi>>,<<Cnv>>] loop:<<Loop>>      outer_loop:none
   //
+  /// CHECK-START-ARM: void Main.halving_add_signed_constant(byte[], byte[]) loop_optimization (after)
+  /// CHECK-DAG: <<I127:i\d+>> IntConstant 127                      loop:none
+  /// CHECK-DAG: <<Repl:d\d+>> VecReplicateScalar [<<I127>>]        loop:none
+  /// CHECK-DAG: <<Phi:i\d+>>  Phi                                  loop:<<Loop:B\d+>> outer_loop:none
+  /// CHECK-DAG: <<Get:d\d+>>  VecLoad                              loop:<<Loop>>      outer_loop:none
+  /// CHECK-DAG: <<HAdd:d\d+>> VecHalvingAdd [<<Get>>,<<Repl>>] unsigned:false rounded:false loop:<<Loop>> outer_loop:none
+  /// CHECK-DAG:               VecStore [{{l\d+}},<<Phi>>,<<HAdd>>] loop:<<Loop>>      outer_loop:none
+  //
   /// CHECK-START-ARM64: void Main.halving_add_signed_constant(byte[], byte[]) loop_optimization (after)
   /// CHECK-DAG: <<I127:i\d+>> IntConstant 127                      loop:none
   /// CHECK-DAG: <<Repl:d\d+>> VecReplicateScalar [<<I127>>]        loop:none
@@ -197,6 +233,14 @@
   /// CHECK-DAG: <<Cnv:b\d+>>  TypeConversion [<<Shr>>]            loop:<<Loop>>      outer_loop:none
   /// CHECK-DAG:               ArraySet [{{l\d+}},<<Phi>>,<<Cnv>>] loop:<<Loop>>      outer_loop:none
   //
+  /// CHECK-START-ARM: void Main.halving_add_unsigned_constant(byte[], byte[]) loop_optimization (after)
+  /// CHECK-DAG: <<I255:i\d+>> IntConstant 255                      loop:none
+  /// CHECK-DAG: <<Repl:d\d+>> VecReplicateScalar [<<I255>>]        loop:none
+  /// CHECK-DAG: <<Phi:i\d+>>  Phi                                  loop:<<Loop:B\d+>> outer_loop:none
+  /// CHECK-DAG: <<Get:d\d+>>  VecLoad                              loop:<<Loop>>      outer_loop:none
+  /// CHECK-DAG: <<HAdd:d\d+>> VecHalvingAdd [<<Get>>,<<Repl>>] unsigned:true rounded:false loop:<<Loop>> outer_loop:none
+  /// CHECK-DAG:               VecStore [{{l\d+}},<<Phi>>,<<HAdd>>] loop:<<Loop>>      outer_loop:none
+  //
   /// CHECK-START-ARM64: void Main.halving_add_unsigned_constant(byte[], byte[]) loop_optimization (after)
   /// CHECK-DAG: <<I255:i\d+>> IntConstant 255                      loop:none
   /// CHECK-DAG: <<Repl:d\d+>> VecReplicateScalar [<<I255>>]        loop:none
diff --git a/test/646-checker-hadd-char/src/Main.java b/test/646-checker-hadd-char/src/Main.java
index bb8a01f..22eb7cb 100644
--- a/test/646-checker-hadd-char/src/Main.java
+++ b/test/646-checker-hadd-char/src/Main.java
@@ -36,6 +36,13 @@
   /// CHECK-DAG: <<Cnv:c\d+>>  TypeConversion [<<Shr>>]            loop:<<Loop>>      outer_loop:none
   /// CHECK-DAG:               ArraySet [{{l\d+}},<<Phi>>,<<Cnv>>] loop:<<Loop>>      outer_loop:none
   //
+  /// CHECK-START-ARM: void Main.halving_add_unsigned(char[], char[], char[]) loop_optimization (after)
+  /// CHECK-DAG: <<Phi:i\d+>>  Phi                                  loop:<<Loop:B\d+>> outer_loop:none
+  /// CHECK-DAG: <<Get1:d\d+>> VecLoad                              loop:<<Loop>>      outer_loop:none
+  /// CHECK-DAG: <<Get2:d\d+>> VecLoad                              loop:<<Loop>>      outer_loop:none
+  /// CHECK-DAG: <<HAdd:d\d+>> VecHalvingAdd [<<Get1>>,<<Get2>>] unsigned:true rounded:false loop:<<Loop>> outer_loop:none
+  /// CHECK-DAG:               VecStore [{{l\d+}},<<Phi>>,<<HAdd>>] loop:<<Loop>>      outer_loop:none
+  //
   /// CHECK-START-ARM64: void Main.halving_add_unsigned(char[], char[], char[]) loop_optimization (after)
   /// CHECK-DAG: <<Phi:i\d+>>  Phi                                  loop:<<Loop:B\d+>> outer_loop:none
   /// CHECK-DAG: <<Get1:d\d+>> VecLoad                              loop:<<Loop>>      outer_loop:none
@@ -69,6 +76,13 @@
   /// CHECK-DAG: <<Cnv:c\d+>>  TypeConversion [<<Shr>>]            loop:<<Loop>>      outer_loop:none
   /// CHECK-DAG:               ArraySet [{{l\d+}},<<Phi>>,<<Cnv>>] loop:<<Loop>>      outer_loop:none
   //
+  /// CHECK-START-ARM: void Main.halving_add_also_unsigned(char[], char[], char[]) loop_optimization (after)
+  /// CHECK-DAG: <<Phi:i\d+>>  Phi                                  loop:<<Loop:B\d+>> outer_loop:none
+  /// CHECK-DAG: <<Get1:d\d+>> VecLoad                              loop:<<Loop>>      outer_loop:none
+  /// CHECK-DAG: <<Get2:d\d+>> VecLoad                              loop:<<Loop>>      outer_loop:none
+  /// CHECK-DAG: <<HAdd:d\d+>> VecHalvingAdd [<<Get1>>,<<Get2>>] unsigned:true rounded:false loop:<<Loop>> outer_loop:none
+  /// CHECK-DAG:               VecStore [{{l\d+}},<<Phi>>,<<HAdd>>] loop:<<Loop>>      outer_loop:none
+  //
   /// CHECK-START-ARM64: void Main.halving_add_also_unsigned(char[], char[], char[]) loop_optimization (after)
   /// CHECK-DAG: <<Phi:i\d+>>  Phi                                  loop:<<Loop:B\d+>> outer_loop:none
   /// CHECK-DAG: <<Get1:d\d+>> VecLoad                              loop:<<Loop>>      outer_loop:none
@@ -103,6 +117,13 @@
   /// CHECK-DAG: <<Cnv:c\d+>>  TypeConversion [<<Shr>>]            loop:<<Loop>>      outer_loop:none
   /// CHECK-DAG:               ArraySet [{{l\d+}},<<Phi>>,<<Cnv>>] loop:<<Loop>>      outer_loop:none
   //
+  /// CHECK-START-ARM: void Main.rounding_halving_add_unsigned(char[], char[], char[]) loop_optimization (after)
+  /// CHECK-DAG: <<Phi:i\d+>>  Phi                                  loop:<<Loop:B\d+>> outer_loop:none
+  /// CHECK-DAG: <<Get1:d\d+>> VecLoad                              loop:<<Loop>>      outer_loop:none
+  /// CHECK-DAG: <<Get2:d\d+>> VecLoad                              loop:<<Loop>>      outer_loop:none
+  /// CHECK-DAG: <<HAdd:d\d+>> VecHalvingAdd [<<Get1>>,<<Get2>>] unsigned:true rounded:true loop:<<Loop>> outer_loop:none
+  /// CHECK-DAG:               VecStore [{{l\d+}},<<Phi>>,<<HAdd>>] loop:<<Loop>>      outer_loop:none
+  //
   /// CHECK-START-ARM64: void Main.rounding_halving_add_unsigned(char[], char[], char[]) loop_optimization (after)
   /// CHECK-DAG: <<Phi:i\d+>>  Phi                                  loop:<<Loop:B\d+>> outer_loop:none
   /// CHECK-DAG: <<Get1:d\d+>> VecLoad                              loop:<<Loop>>      outer_loop:none
@@ -137,6 +158,13 @@
   /// CHECK-DAG: <<Cnv:c\d+>>  TypeConversion [<<Shr>>]            loop:<<Loop>>      outer_loop:none
   /// CHECK-DAG:               ArraySet [{{l\d+}},<<Phi>>,<<Cnv>>] loop:<<Loop>>      outer_loop:none
   //
+  /// CHECK-START-ARM: void Main.rounding_halving_add_also_unsigned(char[], char[], char[]) loop_optimization (after)
+  /// CHECK-DAG: <<Phi:i\d+>>  Phi                                  loop:<<Loop:B\d+>> outer_loop:none
+  /// CHECK-DAG: <<Get1:d\d+>> VecLoad                              loop:<<Loop>>      outer_loop:none
+  /// CHECK-DAG: <<Get2:d\d+>> VecLoad                              loop:<<Loop>>      outer_loop:none
+  /// CHECK-DAG: <<HAdd:d\d+>> VecHalvingAdd [<<Get1>>,<<Get2>>] unsigned:true rounded:true loop:<<Loop>> outer_loop:none
+  /// CHECK-DAG:               VecStore [{{l\d+}},<<Phi>>,<<HAdd>>] loop:<<Loop>>      outer_loop:none
+  //
   /// CHECK-START-ARM64: void Main.rounding_halving_add_also_unsigned(char[], char[], char[]) loop_optimization (after)
   /// CHECK-DAG: <<Phi:i\d+>>  Phi                                  loop:<<Loop:B\d+>> outer_loop:none
   /// CHECK-DAG: <<Get1:d\d+>> VecLoad                              loop:<<Loop>>      outer_loop:none
@@ -170,6 +198,14 @@
   /// CHECK-DAG: <<Cnv:c\d+>>  TypeConversion [<<Shr>>]            loop:<<Loop>>      outer_loop:none
   /// CHECK-DAG:               ArraySet [{{l\d+}},<<Phi>>,<<Cnv>>] loop:<<Loop>>      outer_loop:none
   //
+  /// CHECK-START-ARM: void Main.halving_add_unsigned_constant(char[], char[]) loop_optimization (after)
+  /// CHECK-DAG: <<UMAX:i\d+>> IntConstant 65535                   loop:none
+  /// CHECK-DAG: <<Repl:d\d+>> VecReplicateScalar [<<UMAX>>]        loop:none
+  /// CHECK-DAG: <<Phi:i\d+>>  Phi                                  loop:<<Loop:B\d+>> outer_loop:none
+  /// CHECK-DAG: <<Get:d\d+>>  VecLoad                              loop:<<Loop>>      outer_loop:none
+  /// CHECK-DAG: <<HAdd:d\d+>> VecHalvingAdd [<<Get>>,<<Repl>>] unsigned:true rounded:false loop:<<Loop>> outer_loop:none
+  /// CHECK-DAG:               VecStore [{{l\d+}},<<Phi>>,<<HAdd>>] loop:<<Loop>>      outer_loop:none
+  //
   /// CHECK-START-ARM64: void Main.halving_add_unsigned_constant(char[], char[]) loop_optimization (after)
   /// CHECK-DAG: <<UMAX:i\d+>> IntConstant 65535                   loop:none
   /// CHECK-DAG: <<Repl:d\d+>> VecReplicateScalar [<<UMAX>>]        loop:none
@@ -203,6 +239,14 @@
   /// CHECK-DAG: <<Cnv:c\d+>>  TypeConversion [<<Shr>>]            loop:<<Loop>>      outer_loop:none
   /// CHECK-DAG:               ArraySet [{{l\d+}},<<Phi>>,<<Cnv>>] loop:<<Loop>>      outer_loop:none
   //
+  /// CHECK-START-ARM: void Main.halving_add_also_unsigned_constant(char[], char[]) loop_optimization (after)
+  /// CHECK-DAG: <<UMAX:i\d+>> IntConstant 65535                    loop:none
+  /// CHECK-DAG: <<Repl:d\d+>> VecReplicateScalar [<<UMAX>>]        loop:none
+  /// CHECK-DAG: <<Phi:i\d+>>  Phi                                  loop:<<Loop:B\d+>> outer_loop:none
+  /// CHECK-DAG: <<Get:d\d+>>  VecLoad                              loop:<<Loop>>      outer_loop:none
+  /// CHECK-DAG: <<HAdd:d\d+>> VecHalvingAdd [<<Get>>,<<Repl>>] unsigned:true rounded:false loop:<<Loop>> outer_loop:none
+  /// CHECK-DAG:               VecStore [{{l\d+}},<<Phi>>,<<HAdd>>] loop:<<Loop>>      outer_loop:none
+  //
   /// CHECK-START-ARM64: void Main.halving_add_also_unsigned_constant(char[], char[]) loop_optimization (after)
   /// CHECK-DAG: <<UMAX:i\d+>> IntConstant 65535                    loop:none
   /// CHECK-DAG: <<Repl:d\d+>> VecReplicateScalar [<<UMAX>>]        loop:none
diff --git a/test/646-checker-hadd-short/src/Main.java b/test/646-checker-hadd-short/src/Main.java
index 07845a6..756f8a8 100644
--- a/test/646-checker-hadd-short/src/Main.java
+++ b/test/646-checker-hadd-short/src/Main.java
@@ -36,6 +36,13 @@
   /// CHECK-DAG: <<Cnv:s\d+>>  TypeConversion [<<Shr>>]            loop:<<Loop>>      outer_loop:none
   /// CHECK-DAG:               ArraySet [{{l\d+}},<<Phi>>,<<Cnv>>] loop:<<Loop>>      outer_loop:none
   //
+  /// CHECK-START-ARM: void Main.halving_add_signed(short[], short[], short[]) loop_optimization (after)
+  /// CHECK-DAG: <<Phi:i\d+>>  Phi                                  loop:<<Loop:B\d+>> outer_loop:none
+  /// CHECK-DAG: <<Get1:d\d+>> VecLoad                              loop:<<Loop>>      outer_loop:none
+  /// CHECK-DAG: <<Get2:d\d+>> VecLoad                              loop:<<Loop>>      outer_loop:none
+  /// CHECK-DAG: <<HAdd:d\d+>> VecHalvingAdd [<<Get1>>,<<Get2>>] unsigned:false rounded:false loop:<<Loop>> outer_loop:none
+  /// CHECK-DAG:               VecStore [{{l\d+}},<<Phi>>,<<HAdd>>] loop:<<Loop>>      outer_loop:none
+  //
   /// CHECK-START-ARM64: void Main.halving_add_signed(short[], short[], short[]) loop_optimization (after)
   /// CHECK-DAG: <<Phi:i\d+>>  Phi                                  loop:<<Loop:B\d+>> outer_loop:none
   /// CHECK-DAG: <<Get1:d\d+>> VecLoad                              loop:<<Loop>>      outer_loop:none
@@ -70,6 +77,13 @@
   /// CHECK-DAG: <<Cnv:s\d+>>  TypeConversion [<<Shr>>]            loop:<<Loop>>      outer_loop:none
   /// CHECK-DAG:               ArraySet [{{l\d+}},<<Phi>>,<<Cnv>>] loop:<<Loop>>      outer_loop:none
   //
+  /// CHECK-START-ARM: void Main.halving_add_signed_alt(short[], short[], short[]) loop_optimization (after)
+  /// CHECK-DAG: <<Phi:i\d+>>  Phi                                  loop:<<Loop:B\d+>> outer_loop:none
+  /// CHECK-DAG: <<Get1:d\d+>> VecLoad                              loop:<<Loop>>      outer_loop:none
+  /// CHECK-DAG: <<Get2:d\d+>> VecLoad                              loop:<<Loop>>      outer_loop:none
+  /// CHECK-DAG: <<HAdd:d\d+>> VecHalvingAdd [<<Get1>>,<<Get2>>] unsigned:false rounded:false loop:<<Loop>> outer_loop:none
+  /// CHECK-DAG:               VecStore [{{l\d+}},<<Phi>>,<<HAdd>>] loop:<<Loop>>      outer_loop:none
+  //
   /// CHECK-START-ARM64: void Main.halving_add_signed_alt(short[], short[], short[]) loop_optimization (after)
   /// CHECK-DAG: <<Phi:i\d+>>  Phi                                  loop:<<Loop:B\d+>> outer_loop:none
   /// CHECK-DAG: <<Get1:d\d+>> VecLoad                              loop:<<Loop>>      outer_loop:none
@@ -104,6 +118,13 @@
   /// CHECK-DAG: <<Cnv:s\d+>>  TypeConversion [<<Shr>>]            loop:<<Loop>>      outer_loop:none
   /// CHECK-DAG:               ArraySet [{{l\d+}},<<Phi>>,<<Cnv>>] loop:<<Loop>>      outer_loop:none
   //
+  /// CHECK-START-ARM: void Main.halving_add_unsigned(short[], short[], short[]) loop_optimization (after)
+  /// CHECK-DAG: <<Phi:i\d+>>  Phi                                  loop:<<Loop:B\d+>> outer_loop:none
+  /// CHECK-DAG: <<Get1:d\d+>> VecLoad                              loop:<<Loop>>      outer_loop:none
+  /// CHECK-DAG: <<Get2:d\d+>> VecLoad                              loop:<<Loop>>      outer_loop:none
+  /// CHECK-DAG: <<HAdd:d\d+>> VecHalvingAdd [<<Get1>>,<<Get2>>] unsigned:true rounded:false loop:<<Loop>> outer_loop:none
+  /// CHECK-DAG:               VecStore [{{l\d+}},<<Phi>>,<<HAdd>>] loop:<<Loop>>      outer_loop:none
+  //
   /// CHECK-START-ARM64: void Main.halving_add_unsigned(short[], short[], short[]) loop_optimization (after)
   /// CHECK-DAG: <<Phi:i\d+>>  Phi                                  loop:<<Loop:B\d+>> outer_loop:none
   /// CHECK-DAG: <<Get1:d\d+>> VecLoad                              loop:<<Loop>>      outer_loop:none
@@ -135,6 +156,13 @@
   /// CHECK-DAG: <<Cnv:s\d+>>  TypeConversion [<<Shr>>]            loop:<<Loop>>      outer_loop:none
   /// CHECK-DAG:               ArraySet [{{l\d+}},<<Phi>>,<<Cnv>>] loop:<<Loop>>      outer_loop:none
   //
+  /// CHECK-START-ARM: void Main.rounding_halving_add_signed(short[], short[], short[]) loop_optimization (after)
+  /// CHECK-DAG: <<Phi:i\d+>>  Phi                                  loop:<<Loop:B\d+>> outer_loop:none
+  /// CHECK-DAG: <<Get1:d\d+>> VecLoad                              loop:<<Loop>>      outer_loop:none
+  /// CHECK-DAG: <<Get2:d\d+>> VecLoad                              loop:<<Loop>>      outer_loop:none
+  /// CHECK-DAG: <<HAdd:d\d+>> VecHalvingAdd [<<Get1>>,<<Get2>>] unsigned:false rounded:true loop:<<Loop>> outer_loop:none
+  /// CHECK-DAG:               VecStore [{{l\d+}},<<Phi>>,<<HAdd>>] loop:<<Loop>>      outer_loop:none
+  //
   /// CHECK-START-ARM64: void Main.rounding_halving_add_signed(short[], short[], short[]) loop_optimization (after)
   /// CHECK-DAG: <<Phi:i\d+>>  Phi                                  loop:<<Loop:B\d+>> outer_loop:none
   /// CHECK-DAG: <<Get1:d\d+>> VecLoad                              loop:<<Loop>>      outer_loop:none
@@ -166,6 +194,13 @@
   /// CHECK-DAG: <<Cnv:s\d+>>  TypeConversion [<<Shr>>]            loop:<<Loop>>      outer_loop:none
   /// CHECK-DAG:               ArraySet [{{l\d+}},<<Phi>>,<<Cnv>>] loop:<<Loop>>      outer_loop:none
   //
+  /// CHECK-START-ARM: void Main.rounding_halving_add_signed_alt(short[], short[], short[]) loop_optimization (after)
+  /// CHECK-DAG: <<Phi:i\d+>>  Phi                                  loop:<<Loop:B\d+>> outer_loop:none
+  /// CHECK-DAG: <<Get1:d\d+>> VecLoad                              loop:<<Loop>>      outer_loop:none
+  /// CHECK-DAG: <<Get2:d\d+>> VecLoad                              loop:<<Loop>>      outer_loop:none
+  /// CHECK-DAG: <<HAdd:d\d+>> VecHalvingAdd [<<Get1>>,<<Get2>>] unsigned:false rounded:true loop:<<Loop>> outer_loop:none
+  /// CHECK-DAG:               VecStore [{{l\d+}},<<Phi>>,<<HAdd>>] loop:<<Loop>>      outer_loop:none
+  //
   /// CHECK-START-ARM64: void Main.rounding_halving_add_signed_alt(short[], short[], short[]) loop_optimization (after)
   /// CHECK-DAG: <<Phi:i\d+>>  Phi                                  loop:<<Loop:B\d+>> outer_loop:none
   /// CHECK-DAG: <<Get1:d\d+>> VecLoad                              loop:<<Loop>>      outer_loop:none
@@ -201,6 +236,13 @@
   /// CHECK-DAG: <<Cnv:s\d+>>  TypeConversion [<<Shr>>]            loop:<<Loop>>      outer_loop:none
   /// CHECK-DAG:               ArraySet [{{l\d+}},<<Phi>>,<<Cnv>>] loop:<<Loop>>      outer_loop:none
   //
+  /// CHECK-START-ARM: void Main.rounding_halving_add_signed_alt2(short[], short[], short[]) loop_optimization (after)
+  /// CHECK-DAG: <<Phi:i\d+>>  Phi                                  loop:<<Loop:B\d+>> outer_loop:none
+  /// CHECK-DAG: <<Get1:d\d+>> VecLoad                              loop:<<Loop>>      outer_loop:none
+  /// CHECK-DAG: <<Get2:d\d+>> VecLoad                              loop:<<Loop>>      outer_loop:none
+  /// CHECK-DAG: <<HAdd:d\d+>> VecHalvingAdd [<<Get1>>,<<Get2>>] unsigned:false rounded:true loop:<<Loop>> outer_loop:none
+  /// CHECK-DAG:               VecStore [{{l\d+}},<<Phi>>,<<HAdd>>] loop:<<Loop>>      outer_loop:none
+  //
   /// CHECK-START-ARM64: void Main.rounding_halving_add_signed_alt2(short[], short[], short[]) loop_optimization (after)
   /// CHECK-DAG: <<Phi:i\d+>>  Phi                                  loop:<<Loop:B\d+>> outer_loop:none
   /// CHECK-DAG: <<Get1:d\d+>> VecLoad                              loop:<<Loop>>      outer_loop:none
@@ -236,6 +278,13 @@
   /// CHECK-DAG: <<Cnv:s\d+>>  TypeConversion [<<Shr>>]            loop:<<Loop>>      outer_loop:none
   /// CHECK-DAG:               ArraySet [{{l\d+}},<<Phi>>,<<Cnv>>] loop:<<Loop>>      outer_loop:none
   //
+  /// CHECK-START-ARM: void Main.rounding_halving_add_unsigned(short[], short[], short[]) loop_optimization (after)
+  /// CHECK-DAG: <<Phi:i\d+>>  Phi                                  loop:<<Loop:B\d+>> outer_loop:none
+  /// CHECK-DAG: <<Get1:d\d+>> VecLoad                              loop:<<Loop>>      outer_loop:none
+  /// CHECK-DAG: <<Get2:d\d+>> VecLoad                              loop:<<Loop>>      outer_loop:none
+  /// CHECK-DAG: <<HAdd:d\d+>> VecHalvingAdd [<<Get1>>,<<Get2>>] unsigned:true rounded:true loop:<<Loop>> outer_loop:none
+  /// CHECK-DAG:               VecStore [{{l\d+}},<<Phi>>,<<HAdd>>] loop:<<Loop>>      outer_loop:none
+  //
   /// CHECK-START-ARM64: void Main.rounding_halving_add_unsigned(short[], short[], short[]) loop_optimization (after)
   /// CHECK-DAG: <<Phi:i\d+>>  Phi                                  loop:<<Loop:B\d+>> outer_loop:none
   /// CHECK-DAG: <<Get1:d\d+>> VecLoad                              loop:<<Loop>>      outer_loop:none
@@ -270,6 +319,13 @@
   /// CHECK-DAG: <<Cnv:s\d+>>  TypeConversion [<<Shr>>]            loop:<<Loop>>      outer_loop:none
   /// CHECK-DAG:               ArraySet [{{l\d+}},<<Phi>>,<<Cnv>>] loop:<<Loop>>      outer_loop:none
   //
+  /// CHECK-START-ARM: void Main.rounding_halving_add_unsigned_alt(short[], short[], short[]) loop_optimization (after)
+  /// CHECK-DAG: <<Phi:i\d+>>  Phi                                  loop:<<Loop:B\d+>> outer_loop:none
+  /// CHECK-DAG: <<Get1:d\d+>> VecLoad                              loop:<<Loop>>      outer_loop:none
+  /// CHECK-DAG: <<Get2:d\d+>> VecLoad                              loop:<<Loop>>      outer_loop:none
+  /// CHECK-DAG: <<HAdd:d\d+>> VecHalvingAdd [<<Get1>>,<<Get2>>] unsigned:true rounded:true loop:<<Loop>> outer_loop:none
+  /// CHECK-DAG:               VecStore [{{l\d+}},<<Phi>>,<<HAdd>>] loop:<<Loop>>      outer_loop:none
+  //
   /// CHECK-START-ARM64: void Main.rounding_halving_add_unsigned_alt(short[], short[], short[]) loop_optimization (after)
   /// CHECK-DAG: <<Phi:i\d+>>  Phi                                  loop:<<Loop:B\d+>> outer_loop:none
   /// CHECK-DAG: <<Get1:d\d+>> VecLoad                              loop:<<Loop>>      outer_loop:none
@@ -301,6 +357,14 @@
   /// CHECK-DAG: <<Cnv:s\d+>>  TypeConversion [<<Shr>>]            loop:<<Loop>>      outer_loop:none
   /// CHECK-DAG:               ArraySet [{{l\d+}},<<Phi>>,<<Cnv>>] loop:<<Loop>>      outer_loop:none
   //
+  /// CHECK-START-ARM: void Main.halving_add_signed_constant(short[], short[]) loop_optimization (after)
+  /// CHECK-DAG: <<SMAX:i\d+>> IntConstant 32767                    loop:none
+  /// CHECK-DAG: <<Repl:d\d+>> VecReplicateScalar [<<SMAX>>]        loop:none
+  /// CHECK-DAG: <<Phi:i\d+>>  Phi                                  loop:<<Loop:B\d+>> outer_loop:none
+  /// CHECK-DAG: <<Get:d\d+>>  VecLoad                              loop:<<Loop>>      outer_loop:none
+  /// CHECK-DAG: <<HAdd:d\d+>> VecHalvingAdd [<<Get>>,<<Repl>>] unsigned:false rounded:false loop:<<Loop>> outer_loop:none
+  /// CHECK-DAG:               VecStore [{{l\d+}},<<Phi>>,<<HAdd>>] loop:<<Loop>>      outer_loop:none
+  //
   /// CHECK-START-ARM64: void Main.halving_add_signed_constant(short[], short[]) loop_optimization (after)
   /// CHECK-DAG: <<SMAX:i\d+>> IntConstant 32767                    loop:none
   /// CHECK-DAG: <<Repl:d\d+>> VecReplicateScalar [<<SMAX>>]        loop:none
@@ -334,6 +398,14 @@
   /// CHECK-DAG: <<Cnv:s\d+>>  TypeConversion [<<Shr>>]            loop:<<Loop>>      outer_loop:none
   /// CHECK-DAG:               ArraySet [{{l\d+}},<<Phi>>,<<Cnv>>] loop:<<Loop>>      outer_loop:none
   //
+  /// CHECK-START-ARM: void Main.halving_add_unsigned_constant(short[], short[]) loop_optimization (after)
+  /// CHECK-DAG: <<UMAX:i\d+>> IntConstant 65535                    loop:none
+  /// CHECK-DAG: <<Repl:d\d+>> VecReplicateScalar [<<UMAX>>]        loop:none
+  /// CHECK-DAG: <<Phi:i\d+>>  Phi                                  loop:<<Loop:B\d+>> outer_loop:none
+  /// CHECK-DAG: <<Get:d\d+>>  VecLoad                              loop:<<Loop>>      outer_loop:none
+  /// CHECK-DAG: <<HAdd:d\d+>> VecHalvingAdd [<<Get>>,<<Repl>>] unsigned:true rounded:false loop:<<Loop>> outer_loop:none
+  /// CHECK-DAG:               VecStore [{{l\d+}},<<Phi>>,<<HAdd>>] loop:<<Loop>>      outer_loop:none
+  //
   /// CHECK-START-ARM64: void Main.halving_add_unsigned_constant(short[], short[]) loop_optimization (after)
   /// CHECK-DAG: <<UMAX:i\d+>> IntConstant 65535                    loop:none
   /// CHECK-DAG: <<Repl:d\d+>> VecReplicateScalar [<<UMAX>>]        loop:none
diff --git a/test/651-checker-byte-simd-minmax/src/Main.java b/test/651-checker-byte-simd-minmax/src/Main.java
index 4711214..e018b56 100644
--- a/test/651-checker-byte-simd-minmax/src/Main.java
+++ b/test/651-checker-byte-simd-minmax/src/Main.java
@@ -27,6 +27,13 @@
   /// CHECK-DAG: <<Cnv:b\d+>>  TypeConversion [<<Min>>]            loop:<<Loop>>      outer_loop:none
   /// CHECK-DAG:               ArraySet [{{l\d+}},<<Phi>>,<<Cnv>>] loop:<<Loop>>      outer_loop:none
   //
+  /// CHECK-START-ARM: void Main.doitMin(byte[], byte[], byte[]) loop_optimization (after)
+  /// CHECK-DAG: <<Phi:i\d+>>  Phi                                 loop:<<Loop:B\d+>> outer_loop:none
+  /// CHECK-DAG: <<Get1:d\d+>> VecLoad                             loop:<<Loop>>      outer_loop:none
+  /// CHECK-DAG: <<Get2:d\d+>> VecLoad                             loop:<<Loop>>      outer_loop:none
+  /// CHECK-DAG: <<Min:d\d+>>  VecMin [<<Get1>>,<<Get2>>] unsigned:false loop:<<Loop>> outer_loop:none
+  /// CHECK-DAG:               VecStore [{{l\d+}},<<Phi>>,<<Min>>] loop:<<Loop>>      outer_loop:none
+  //
   /// CHECK-START-ARM64: void Main.doitMin(byte[], byte[], byte[]) loop_optimization (after)
   /// CHECK-DAG: <<Phi:i\d+>>  Phi                                 loop:<<Loop:B\d+>> outer_loop:none
   /// CHECK-DAG: <<Get1:d\d+>> VecLoad                             loop:<<Loop>>      outer_loop:none
@@ -58,6 +65,13 @@
   /// CHECK-DAG: <<Cnv:b\d+>>  TypeConversion [<<Min>>]            loop:<<Loop>>      outer_loop:none
   /// CHECK-DAG:               ArraySet [{{l\d+}},<<Phi>>,<<Cnv>>] loop:<<Loop>>      outer_loop:none
   //
+  /// CHECK-START-ARM: void Main.doitMinUnsigned(byte[], byte[], byte[]) loop_optimization (after)
+  /// CHECK-DAG: <<Phi:i\d+>>  Phi                                 loop:<<Loop:B\d+>> outer_loop:none
+  /// CHECK-DAG: <<Get1:d\d+>> VecLoad                             loop:<<Loop>>      outer_loop:none
+  /// CHECK-DAG: <<Get2:d\d+>> VecLoad                             loop:<<Loop>>      outer_loop:none
+  /// CHECK-DAG: <<Min:d\d+>>  VecMin [<<Get1>>,<<Get2>>] unsigned:true loop:<<Loop>> outer_loop:none
+  /// CHECK-DAG:               VecStore [{{l\d+}},<<Phi>>,<<Min>>] loop:<<Loop>>      outer_loop:none
+  //
   /// CHECK-START-ARM64: void Main.doitMinUnsigned(byte[], byte[], byte[]) loop_optimization (after)
   /// CHECK-DAG: <<Phi:i\d+>>  Phi                                 loop:<<Loop:B\d+>> outer_loop:none
   /// CHECK-DAG: <<Get1:d\d+>> VecLoad                             loop:<<Loop>>      outer_loop:none
@@ -86,6 +100,13 @@
   /// CHECK-DAG: <<Cnv:b\d+>>  TypeConversion [<<Max>>]            loop:<<Loop>>      outer_loop:none
   /// CHECK-DAG:               ArraySet [{{l\d+}},<<Phi>>,<<Cnv>>] loop:<<Loop>>      outer_loop:none
   //
+  /// CHECK-START-ARM: void Main.doitMax(byte[], byte[], byte[]) loop_optimization (after)
+  /// CHECK-DAG: <<Phi:i\d+>>  Phi                                 loop:<<Loop:B\d+>> outer_loop:none
+  /// CHECK-DAG: <<Get1:d\d+>> VecLoad                             loop:<<Loop>>      outer_loop:none
+  /// CHECK-DAG: <<Get2:d\d+>> VecLoad                             loop:<<Loop>>      outer_loop:none
+  /// CHECK-DAG: <<Max:d\d+>>  VecMax [<<Get1>>,<<Get2>>] unsigned:false loop:<<Loop>> outer_loop:none
+  /// CHECK-DAG:               VecStore [{{l\d+}},<<Phi>>,<<Max>>] loop:<<Loop>>      outer_loop:none
+  //
   /// CHECK-START-ARM64: void Main.doitMax(byte[], byte[], byte[]) loop_optimization (after)
   /// CHECK-DAG: <<Phi:i\d+>>  Phi                                 loop:<<Loop:B\d+>> outer_loop:none
   /// CHECK-DAG: <<Get1:d\d+>> VecLoad                             loop:<<Loop>>      outer_loop:none
@@ -117,6 +138,13 @@
   /// CHECK-DAG: <<Cnv:b\d+>>  TypeConversion [<<Max>>]            loop:<<Loop>>      outer_loop:none
   /// CHECK-DAG:               ArraySet [{{l\d+}},<<Phi>>,<<Cnv>>] loop:<<Loop>>      outer_loop:none
   //
+  /// CHECK-START-ARM: void Main.doitMaxUnsigned(byte[], byte[], byte[]) loop_optimization (after)
+  /// CHECK-DAG: <<Phi:i\d+>>  Phi                                 loop:<<Loop:B\d+>> outer_loop:none
+  /// CHECK-DAG: <<Get1:d\d+>> VecLoad                             loop:<<Loop>>      outer_loop:none
+  /// CHECK-DAG: <<Get2:d\d+>> VecLoad                             loop:<<Loop>>      outer_loop:none
+  /// CHECK-DAG: <<Max:d\d+>>  VecMax [<<Get1>>,<<Get2>>] unsigned:true loop:<<Loop>> outer_loop:none
+  /// CHECK-DAG:               VecStore [{{l\d+}},<<Phi>>,<<Max>>] loop:<<Loop>>      outer_loop:none
+  //
   /// CHECK-START-ARM64: void Main.doitMaxUnsigned(byte[], byte[], byte[]) loop_optimization (after)
   /// CHECK-DAG: <<Phi:i\d+>>  Phi                                 loop:<<Loop:B\d+>> outer_loop:none
   /// CHECK-DAG: <<Get1:d\d+>> VecLoad                             loop:<<Loop>>      outer_loop:none
diff --git a/test/651-checker-char-simd-minmax/src/Main.java b/test/651-checker-char-simd-minmax/src/Main.java
index 79795ee..57cad9b 100644
--- a/test/651-checker-char-simd-minmax/src/Main.java
+++ b/test/651-checker-char-simd-minmax/src/Main.java
@@ -27,6 +27,13 @@
   /// CHECK-DAG: <<Cnv:c\d+>>  TypeConversion [<<Min>>]            loop:<<Loop>>      outer_loop:none
   /// CHECK-DAG:               ArraySet [{{l\d+}},<<Phi>>,<<Cnv>>] loop:<<Loop>>      outer_loop:none
   //
+  /// CHECK-START-ARM: void Main.doitMin(char[], char[], char[]) loop_optimization (after)
+  /// CHECK-DAG: <<Phi:i\d+>>  Phi                                 loop:<<Loop:B\d+>> outer_loop:none
+  /// CHECK-DAG: <<Get1:d\d+>> VecLoad                             loop:<<Loop>>      outer_loop:none
+  /// CHECK-DAG: <<Get2:d\d+>> VecLoad                             loop:<<Loop>>      outer_loop:none
+  /// CHECK-DAG: <<Min:d\d+>>  VecMin [<<Get1>>,<<Get2>>] unsigned:true loop:<<Loop>> outer_loop:none
+  /// CHECK-DAG:               VecStore [{{l\d+}},<<Phi>>,<<Min>>] loop:<<Loop>>      outer_loop:none
+  //
   /// CHECK-START-ARM64: void Main.doitMin(char[], char[], char[]) loop_optimization (after)
   /// CHECK-DAG: <<Phi:i\d+>>  Phi                                 loop:<<Loop:B\d+>> outer_loop:none
   /// CHECK-DAG: <<Get1:d\d+>> VecLoad                             loop:<<Loop>>      outer_loop:none
@@ -55,6 +62,13 @@
   /// CHECK-DAG: <<Cnv:c\d+>>  TypeConversion [<<Max>>]            loop:<<Loop>>      outer_loop:none
   /// CHECK-DAG:               ArraySet [{{l\d+}},<<Phi>>,<<Cnv>>] loop:<<Loop>>      outer_loop:none
   //
+  /// CHECK-START-ARM: void Main.doitMax(char[], char[], char[]) loop_optimization (after)
+  /// CHECK-DAG: <<Phi:i\d+>>  Phi                                 loop:<<Loop:B\d+>> outer_loop:none
+  /// CHECK-DAG: <<Get1:d\d+>> VecLoad                             loop:<<Loop>>      outer_loop:none
+  /// CHECK-DAG: <<Get2:d\d+>> VecLoad                             loop:<<Loop>>      outer_loop:none
+  /// CHECK-DAG: <<Max:d\d+>>  VecMax [<<Get1>>,<<Get2>>] unsigned:true loop:<<Loop>> outer_loop:none
+  /// CHECK-DAG:               VecStore [{{l\d+}},<<Phi>>,<<Max>>] loop:<<Loop>>      outer_loop:none
+  //
   /// CHECK-START-ARM64: void Main.doitMax(char[], char[], char[]) loop_optimization (after)
   /// CHECK-DAG: <<Phi:i\d+>>  Phi                                 loop:<<Loop:B\d+>> outer_loop:none
   /// CHECK-DAG: <<Get1:d\d+>> VecLoad                             loop:<<Loop>>      outer_loop:none
diff --git a/test/651-checker-int-simd-minmax/src/Main.java b/test/651-checker-int-simd-minmax/src/Main.java
index 2a97009..11b67b8 100644
--- a/test/651-checker-int-simd-minmax/src/Main.java
+++ b/test/651-checker-int-simd-minmax/src/Main.java
@@ -26,6 +26,13 @@
   /// CHECK-DAG: <<Min:i\d+>>  InvokeStaticOrDirect [<<Get1>>,<<Get2>>] intrinsic:MathMinIntInt loop:<<Loop>> outer_loop:none
   /// CHECK-DAG:               ArraySet [{{l\d+}},<<Phi>>,<<Min>>] loop:<<Loop>>      outer_loop:none
   //
+  /// CHECK-START-ARM: void Main.doitMin(int[], int[], int[]) loop_optimization (after)
+  /// CHECK-DAG: <<Phi:i\d+>>  Phi                                 loop:<<Loop:B\d+>> outer_loop:none
+  /// CHECK-DAG: <<Get1:d\d+>> VecLoad                             loop:<<Loop>>      outer_loop:none
+  /// CHECK-DAG: <<Get2:d\d+>> VecLoad                             loop:<<Loop>>      outer_loop:none
+  /// CHECK-DAG: <<Min:d\d+>>  VecMin [<<Get1>>,<<Get2>>] unsigned:false loop:<<Loop>> outer_loop:none
+  /// CHECK-DAG:               VecStore [{{l\d+}},<<Phi>>,<<Min>>] loop:<<Loop>>      outer_loop:none
+  //
   /// CHECK-START-ARM64: void Main.doitMin(int[], int[], int[]) loop_optimization (after)
   /// CHECK-DAG: <<Phi:i\d+>>  Phi                                 loop:<<Loop:B\d+>> outer_loop:none
   /// CHECK-DAG: <<Get1:d\d+>> VecLoad                             loop:<<Loop>>      outer_loop:none
@@ -53,6 +60,13 @@
   /// CHECK-DAG: <<Max:i\d+>>  InvokeStaticOrDirect [<<Get1>>,<<Get2>>] intrinsic:MathMaxIntInt loop:<<Loop>> outer_loop:none
   /// CHECK-DAG:               ArraySet [{{l\d+}},<<Phi>>,<<Max>>] loop:<<Loop>>      outer_loop:none
   //
+  /// CHECK-START-ARM: void Main.doitMax(int[], int[], int[]) loop_optimization (after)
+  /// CHECK-DAG: <<Phi:i\d+>>  Phi                                 loop:<<Loop:B\d+>> outer_loop:none
+  /// CHECK-DAG: <<Get1:d\d+>> VecLoad                             loop:<<Loop>>      outer_loop:none
+  /// CHECK-DAG: <<Get2:d\d+>> VecLoad                             loop:<<Loop>>      outer_loop:none
+  /// CHECK-DAG: <<Max:d\d+>>  VecMax [<<Get1>>,<<Get2>>] unsigned:false loop:<<Loop>> outer_loop:none
+  /// CHECK-DAG:               VecStore [{{l\d+}},<<Phi>>,<<Max>>] loop:<<Loop>>      outer_loop:none
+  //
   /// CHECK-START-ARM64: void Main.doitMax(int[], int[], int[]) loop_optimization (after)
   /// CHECK-DAG: <<Phi:i\d+>>  Phi                                 loop:<<Loop:B\d+>> outer_loop:none
   /// CHECK-DAG: <<Get1:d\d+>> VecLoad                             loop:<<Loop>>      outer_loop:none
diff --git a/test/651-checker-short-simd-minmax/src/Main.java b/test/651-checker-short-simd-minmax/src/Main.java
index 3bd1305..4f2a7a4 100644
--- a/test/651-checker-short-simd-minmax/src/Main.java
+++ b/test/651-checker-short-simd-minmax/src/Main.java
@@ -27,6 +27,13 @@
   /// CHECK-DAG: <<Cnv:s\d+>>  TypeConversion [<<Min>>]            loop:<<Loop>>      outer_loop:none
   /// CHECK-DAG:               ArraySet [{{l\d+}},<<Phi>>,<<Cnv>>] loop:<<Loop>>      outer_loop:none
   //
+  /// CHECK-START-ARM: void Main.doitMin(short[], short[], short[]) loop_optimization (after)
+  /// CHECK-DAG: <<Phi:i\d+>>  Phi                                 loop:<<Loop:B\d+>> outer_loop:none
+  /// CHECK-DAG: <<Get1:d\d+>> VecLoad                             loop:<<Loop>>      outer_loop:none
+  /// CHECK-DAG: <<Get2:d\d+>> VecLoad                             loop:<<Loop>>      outer_loop:none
+  /// CHECK-DAG: <<Min:d\d+>>  VecMin [<<Get1>>,<<Get2>>] unsigned:false loop:<<Loop>> outer_loop:none
+  /// CHECK-DAG:               VecStore [{{l\d+}},<<Phi>>,<<Min>>] loop:<<Loop>>      outer_loop:none
+  //
   /// CHECK-START-ARM64: void Main.doitMin(short[], short[], short[]) loop_optimization (after)
   /// CHECK-DAG: <<Phi:i\d+>>  Phi                                 loop:<<Loop:B\d+>> outer_loop:none
   /// CHECK-DAG: <<Get1:d\d+>> VecLoad                             loop:<<Loop>>      outer_loop:none
@@ -58,6 +65,13 @@
   /// CHECK-DAG: <<Cnv:s\d+>>  TypeConversion [<<Min>>]            loop:<<Loop>>      outer_loop:none
   /// CHECK-DAG:               ArraySet [{{l\d+}},<<Phi>>,<<Cnv>>] loop:<<Loop>>      outer_loop:none
   //
+  /// CHECK-START-ARM: void Main.doitMinUnsigned(short[], short[], short[]) loop_optimization (after)
+  /// CHECK-DAG: <<Phi:i\d+>>  Phi                                 loop:<<Loop:B\d+>> outer_loop:none
+  /// CHECK-DAG: <<Get1:d\d+>> VecLoad                             loop:<<Loop>>      outer_loop:none
+  /// CHECK-DAG: <<Get2:d\d+>> VecLoad                             loop:<<Loop>>      outer_loop:none
+  /// CHECK-DAG: <<Min:d\d+>>  VecMin [<<Get1>>,<<Get2>>] unsigned:true loop:<<Loop>> outer_loop:none
+  /// CHECK-DAG:               VecStore [{{l\d+}},<<Phi>>,<<Min>>] loop:<<Loop>>      outer_loop:none
+  //
   /// CHECK-START-ARM64: void Main.doitMinUnsigned(short[], short[], short[]) loop_optimization (after)
   /// CHECK-DAG: <<Phi:i\d+>>  Phi                                 loop:<<Loop:B\d+>> outer_loop:none
   /// CHECK-DAG: <<Get1:d\d+>> VecLoad                             loop:<<Loop>>      outer_loop:none
@@ -86,6 +100,13 @@
   /// CHECK-DAG: <<Cnv:s\d+>>  TypeConversion [<<Max>>]            loop:<<Loop>>      outer_loop:none
   /// CHECK-DAG:               ArraySet [{{l\d+}},<<Phi>>,<<Cnv>>] loop:<<Loop>>      outer_loop:none
   //
+  /// CHECK-START-ARM: void Main.doitMax(short[], short[], short[]) loop_optimization (after)
+  /// CHECK-DAG: <<Phi:i\d+>>  Phi                                 loop:<<Loop:B\d+>> outer_loop:none
+  /// CHECK-DAG: <<Get1:d\d+>> VecLoad                             loop:<<Loop>>      outer_loop:none
+  /// CHECK-DAG: <<Get2:d\d+>> VecLoad                             loop:<<Loop>>      outer_loop:none
+  /// CHECK-DAG: <<Max:d\d+>>  VecMax [<<Get1>>,<<Get2>>] unsigned:false loop:<<Loop>> outer_loop:none
+  /// CHECK-DAG:               VecStore [{{l\d+}},<<Phi>>,<<Max>>] loop:<<Loop>>      outer_loop:none
+  //
   /// CHECK-START-ARM64: void Main.doitMax(short[], short[], short[]) loop_optimization (after)
   /// CHECK-DAG: <<Phi:i\d+>>  Phi                                 loop:<<Loop:B\d+>> outer_loop:none
   /// CHECK-DAG: <<Get1:d\d+>> VecLoad                             loop:<<Loop>>      outer_loop:none
@@ -117,6 +138,13 @@
   /// CHECK-DAG: <<Cnv:s\d+>>  TypeConversion [<<Max>>]            loop:<<Loop>>      outer_loop:none
   /// CHECK-DAG:               ArraySet [{{l\d+}},<<Phi>>,<<Cnv>>] loop:<<Loop>>      outer_loop:none
   //
+  /// CHECK-START-ARM: void Main.doitMaxUnsigned(short[], short[], short[]) loop_optimization (after)
+  /// CHECK-DAG: <<Phi:i\d+>>  Phi                                 loop:<<Loop:B\d+>> outer_loop:none
+  /// CHECK-DAG: <<Get1:d\d+>> VecLoad                             loop:<<Loop>>      outer_loop:none
+  /// CHECK-DAG: <<Get2:d\d+>> VecLoad                             loop:<<Loop>>      outer_loop:none
+  /// CHECK-DAG: <<Max:d\d+>>  VecMax [<<Get1>>,<<Get2>>] unsigned:true loop:<<Loop>> outer_loop:none
+  /// CHECK-DAG:               VecStore [{{l\d+}},<<Phi>>,<<Max>>] loop:<<Loop>>      outer_loop:none
+  //
   /// CHECK-START-ARM64: void Main.doitMaxUnsigned(short[], short[], short[]) loop_optimization (after)
   /// CHECK-DAG: <<Phi:i\d+>>  Phi                                 loop:<<Loop:B\d+>> outer_loop:none
   /// CHECK-DAG: <<Get1:d\d+>> VecLoad                             loop:<<Loop>>      outer_loop:none
diff --git a/test/988-redefine-use-after-free/expected.txt b/test/658-fp-read-barrier/expected.txt
similarity index 100%
copy from test/988-redefine-use-after-free/expected.txt
copy to test/658-fp-read-barrier/expected.txt
diff --git a/test/658-fp-read-barrier/info.txt b/test/658-fp-read-barrier/info.txt
new file mode 100644
index 0000000..26ecb60
--- /dev/null
+++ b/test/658-fp-read-barrier/info.txt
@@ -0,0 +1,2 @@
+Regression test for the read barrier implementation in ARM64,
+which used to not restore floating point registers.
diff --git a/test/658-fp-read-barrier/src/Main.java b/test/658-fp-read-barrier/src/Main.java
new file mode 100644
index 0000000..eed3c61
--- /dev/null
+++ b/test/658-fp-read-barrier/src/Main.java
@@ -0,0 +1,138 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+public class Main {
+  static volatile boolean done = false;
+
+  public static void main(String[] args) {
+    // Run a thread for 30 seconds, allocating memory and triggering garbage
+    // collection.
+    // Time is limited to 30 seconds to not make this test too long. The test used
+    // to trigger the failure around 1 every 10 runs.
+    Thread t = new Thread() {
+      public void run() {
+        long time = System.currentTimeMillis();
+        while (System.currentTimeMillis() - time < 30000) {
+          for (int j = 0; j < 10000; j++) {
+            o = new Object[1000];
+          }
+          Runtime.getRuntime().gc();
+          Thread.yield();
+        }
+        Main.done = true;
+      }
+      Object o;
+    };
+    // Make the thread a daemon to quit early in case of an
+    // exception thrown below.
+    t.setDaemon(true);
+    t.start();
+
+    // Run 'foo' as long as the test runs.
+    while (!done) {
+      double res = foo(staticMain);
+      if (res != 529.0) {
+        throw new Error("Unexpected result " + res);
+      }
+    }
+  }
+
+  public static double foo(Main main) {
+    // Use up all D registers on arm64.
+    double d1 = main.field1;
+    double d2 = main.field2;
+    double d3 = main.field3;
+    double d4 = main.field4;
+    double d5 = main.field5;
+    double d6 = main.field6;
+    double d7 = main.field7;
+    double d8 = main.field8;
+    double d9 = main.field9;
+    double d10 = main.field10;
+    double d11 = main.field11;
+    double d12 = main.field12;
+    double d13 = main.field13;
+    double d14 = main.field14;
+    double d15 = main.field15;
+    double d16 = main.field16;
+    double d17 = main.field17;
+    double d18 = main.field18;
+    double d19 = main.field19;
+    double d20 = main.field20;
+    double d21 = main.field21;
+    double d22 = main.field22;
+    double d23 = main.field23;
+    double d24 = main.field24;
+    double d25 = main.field25;
+    double d26 = main.field26;
+    double d27 = main.field27;
+    double d28 = main.field28;
+    double d29 = main.field29;
+    double d30 = main.field30;
+    double d31 = main.field31;
+    double d32 = main.field32;
+
+    // Trigger a read barrier. This used to make the test trip on ARM64 as
+    // the read barrier stub used to not restore the D registers.
+    double p = main.objectField.field1;
+
+    return p + d1 + d2 + d3 + d4 + d5 + d6 + d7 + d8 + d9 + d10 + d11 + d12 +
+        d13 + d14 + d15 + d16 + d17 + d18 + d19 + d20 + d21 + d22 + d23 + d24 +
+        d25 + d26 + d27 + d28 + d29 + d30 + d31 + d32;
+  }
+
+  // Initialize objects here and not in 'main' to avoid having
+  // these objects in roots.
+  public static Main staticMain = new Main();
+  static {
+    staticMain.objectField = new Main();
+  }
+
+  public Main objectField;
+
+  public double field1 = 1.0;
+  public double field2 = 2.0;
+  public double field3 = 3.0;
+  public double field4 = 4.0;
+  public double field5 = 5.0;
+  public double field6 = 6.0;
+  public double field7 = 7.0;
+  public double field8 = 8.0;
+  public double field9 = 9.0;
+  public double field10 = 10.0;
+  public double field11 = 11.0;
+  public double field12 = 12.0;
+  public double field13 = 13.0;
+  public double field14 = 14.0;
+  public double field15 = 15.0;
+  public double field16 = 16.0;
+  public double field17 = 17.0;
+  public double field18 = 18.0;
+  public double field19 = 19.0;
+  public double field20 = 20.0;
+  public double field21 = 21.0;
+  public double field22 = 22.0;
+  public double field23 = 23.0;
+  public double field24 = 24.0;
+  public double field25 = 25.0;
+  public double field26 = 26.0;
+  public double field27 = 27.0;
+  public double field28 = 28.0;
+  public double field29 = 29.0;
+  public double field30 = 30.0;
+  public double field31 = 31.0;
+  public double field32 = 32.0;
+}
diff --git a/test/706-checker-scheduler/src/Main.java b/test/706-checker-scheduler/src/Main.java
index 1721e42..a68565b 100644
--- a/test/706-checker-scheduler/src/Main.java
+++ b/test/706-checker-scheduler/src/Main.java
@@ -16,8 +16,22 @@
 
 public class Main {
 
+  public class ExampleObj {
+    int n1;
+    int n2;
+
+    public ExampleObj(int n1, int n2) {
+      this.n1 = n1;
+      this.n2 = n2;
+    }
+  }
+
   static int static_variable = 0;
 
+  public ExampleObj my_obj;
+  public static int number1;
+  public static int number2;
+
   /// CHECK-START-ARM64: int Main.arrayAccess() scheduler (before)
   /// CHECK:    <<Const1:i\d+>>       IntConstant 1
   /// CHECK:    <<i0:i\d+>>           Phi
@@ -50,6 +64,282 @@
     return res;
   }
 
+  /// CHECK-START-ARM: void Main.arrayAccessVariable(int) scheduler (before)
+  /// CHECK:     <<Param:i\d+>>        ParameterValue
+  /// CHECK-DAG: <<Const1:i\d+>>       IntConstant 1
+  /// CHECK-DAG: <<Const2:i\d+>>       IntConstant 2
+  /// CHECK-DAG: <<Const3:i\d+>>       IntConstant -1
+  /// CHECK:     <<Add1:i\d+>>         Add [<<Param>>,<<Const1>>]
+  /// CHECK:     <<Add2:i\d+>>         Add [<<Param>>,<<Const2>>]
+  /// CHECK:     <<Add3:i\d+>>         Add [<<Param>>,<<Const3>>]
+  /// CHECK:     <<Array:i\d+>>        IntermediateAddress
+  /// CHECK:     <<ArrayGet1:i\d+>>    ArrayGet [<<Array>>,<<Add1>>]
+  /// CHECK:     <<AddArray1:i\d+>>    Add [<<ArrayGet1>>,<<Const1>>]
+  /// CHECK:     <<ArraySet1:v\d+>>    ArraySet [<<Array>>,<<Add1>>,<<AddArray1>>]
+  /// CHECK:     <<ArrayGet2:i\d+>>    ArrayGet [<<Array>>,<<Add2>>]
+  /// CHECK:     <<AddArray2:i\d+>>    Add [<<ArrayGet2>>,<<Const1>>]
+  /// CHECK:     <<ArraySet2:v\d+>>    ArraySet [<<Array>>,<<Add2>>,<<AddArray2>>]
+  /// CHECK:     <<ArrayGet3:i\d+>>    ArrayGet [<<Array>>,<<Add3>>]
+  /// CHECK:     <<AddArray3:i\d+>>    Add [<<ArrayGet3>>,<<Const1>>]
+  /// CHECK:     <<ArraySet3:v\d+>>    ArraySet [<<Array>>,<<Add3>>,<<AddArray3>>]
+
+  /// CHECK-START-ARM: void Main.arrayAccessVariable(int) scheduler (after)
+  /// CHECK:     <<Param:i\d+>>        ParameterValue
+  /// CHECK-DAG: <<Const1:i\d+>>       IntConstant 1
+  /// CHECK-DAG: <<Const2:i\d+>>       IntConstant 2
+  /// CHECK-DAG: <<Const3:i\d+>>       IntConstant -1
+  /// CHECK:     <<Add1:i\d+>>         Add [<<Param>>,<<Const1>>]
+  /// CHECK:     <<Add2:i\d+>>         Add [<<Param>>,<<Const2>>]
+  /// CHECK:     <<Add3:i\d+>>         Add [<<Param>>,<<Const3>>]
+  /// CHECK:     <<Array:i\d+>>        IntermediateAddress
+  /// CHECK:                           ArrayGet [<<Array>>,{{i\d+}}]
+  /// CHECK:                           ArrayGet [<<Array>>,{{i\d+}}]
+  /// CHECK:                           ArrayGet [<<Array>>,{{i\d+}}]
+  /// CHECK:                           Add
+  /// CHECK:                           Add
+  /// CHECK:                           Add
+  /// CHECK:                           ArraySet
+  /// CHECK:                           ArraySet
+  /// CHECK:                           ArraySet
+
+  /// CHECK-START-ARM64: void Main.arrayAccessVariable(int) scheduler (before)
+  /// CHECK:     <<Param:i\d+>>        ParameterValue
+  /// CHECK-DAG: <<Const1:i\d+>>       IntConstant 1
+  /// CHECK-DAG: <<Const2:i\d+>>       IntConstant 2
+  /// CHECK-DAG: <<Const3:i\d+>>       IntConstant -1
+  /// CHECK:     <<Add1:i\d+>>         Add [<<Param>>,<<Const1>>]
+  /// CHECK:     <<Add2:i\d+>>         Add [<<Param>>,<<Const2>>]
+  /// CHECK:     <<Add3:i\d+>>         Add [<<Param>>,<<Const3>>]
+  /// CHECK:     <<Array:i\d+>>        IntermediateAddress
+  /// CHECK:     <<ArrayGet1:i\d+>>    ArrayGet [<<Array>>,<<Add1>>]
+  /// CHECK:     <<AddArray1:i\d+>>    Add [<<ArrayGet1>>,<<Const1>>]
+  /// CHECK:     <<ArraySet1:v\d+>>    ArraySet [<<Array>>,<<Add1>>,<<AddArray1>>]
+  /// CHECK:     <<ArrayGet2:i\d+>>    ArrayGet [<<Array>>,<<Add2>>]
+  /// CHECK:     <<AddArray2:i\d+>>    Add [<<ArrayGet2>>,<<Const1>>]
+  /// CHECK:     <<ArraySet2:v\d+>>    ArraySet [<<Array>>,<<Add2>>,<<AddArray2>>]
+  /// CHECK:     <<ArrayGet3:i\d+>>    ArrayGet [<<Array>>,<<Add3>>]
+  /// CHECK:     <<AddArray3:i\d+>>    Add [<<ArrayGet3>>,<<Const1>>]
+  /// CHECK:     <<ArraySet3:v\d+>>    ArraySet [<<Array>>,<<Add3>>,<<AddArray3>>]
+
+  /// CHECK-START-ARM64: void Main.arrayAccessVariable(int) scheduler (after)
+  /// CHECK:     <<Param:i\d+>>        ParameterValue
+  /// CHECK-DAG: <<Const1:i\d+>>       IntConstant 1
+  /// CHECK-DAG: <<Const2:i\d+>>       IntConstant 2
+  /// CHECK-DAG: <<Const3:i\d+>>       IntConstant -1
+  /// CHECK:     <<Add1:i\d+>>         Add [<<Param>>,<<Const1>>]
+  /// CHECK:     <<Add2:i\d+>>         Add [<<Param>>,<<Const2>>]
+  /// CHECK:     <<Add3:i\d+>>         Add [<<Param>>,<<Const3>>]
+  /// CHECK:     <<Array:i\d+>>        IntermediateAddress
+  /// CHECK:                           ArrayGet [<<Array>>,{{i\d+}}]
+  /// CHECK:                           ArrayGet [<<Array>>,{{i\d+}}]
+  /// CHECK:                           ArrayGet [<<Array>>,{{i\d+}}]
+  /// CHECK:                           Add
+  /// CHECK:                           Add
+  /// CHECK:                           Add
+  /// CHECK:                           ArraySet
+  /// CHECK:                           ArraySet
+  /// CHECK:                           ArraySet
+  public static void arrayAccessVariable(int i) {
+    int [] array = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10};
+    for (int j = 0; j < 100; j++) {
+      array[i + 1]++;
+      array[i + 2]++;
+      array[i - 1]++;
+    }
+  }
+
+  /// CHECK-START-ARM: void Main.arrayAccessSub(int) scheduler (before)
+  /// CHECK:      <<Param:i\d+>>        ParameterValue
+  /// CHECK-DAG:  <<Const1:i\d+>>       IntConstant -1
+  /// CHECK-DAG:  <<Const2:i\d+>>       IntConstant 9
+  /// CHECK-DAG:  <<Const3:i\d+>>       IntConstant 1
+  /// CHECK:      <<Add1:i\d+>>         Add [<<Param>>,<<Const1>>]
+  /// CHECK:      <<Sub2:i\d+>>         Sub [<<Const2>>,<<Param>>]
+  /// CHECK:      <<Array:i\d+>>        IntermediateAddress
+  /// CHECK:      <<ArrayGet1:i\d+>>    ArrayGet [<<Array>>,<<Add1>>]
+  /// CHECK:      <<AddArray1:i\d+>>    Add [<<ArrayGet1>>,<<Const3>>]
+  /// CHECK:      <<ArraySet1:v\d+>>    ArraySet [<<Array>>,<<Add1>>,<<AddArray1>>]
+  /// CHECK:      <<ArrayGet2:i\d+>>    ArrayGet [<<Array>>,<<Sub2>>]
+  /// CHECK:      <<AddArray2:i\d+>>    Add [<<ArrayGet2>>,<<Const3>>]
+  /// CHECK:      <<ArraySet2:v\d+>>    ArraySet [<<Array>>,<<Sub2>>,<<AddArray2>>]
+
+  /// CHECK-START-ARM: void Main.arrayAccessSub(int) scheduler (after)
+  /// CHECK:      <<Param:i\d+>>        ParameterValue
+  /// CHECK-DAG:  <<Const1:i\d+>>       IntConstant -1
+  /// CHECK-DAG:  <<Const2:i\d+>>       IntConstant 9
+  /// CHECK-DAG:  <<Const3:i\d+>>       IntConstant 1
+  /// CHECK:      <<Add1:i\d+>>         Add [<<Param>>,<<Const1>>]
+  /// CHECK:      <<Sub2:i\d+>>         Sub [<<Const2>>,<<Param>>]
+  /// CHECK:      <<Array:i\d+>>        IntermediateAddress
+  /// CHECK:      <<ArrayGet1:i\d+>>    ArrayGet [<<Array>>,<<Add1>>]
+  /// CHECK:      <<AddArray1:i\d+>>    Add [<<ArrayGet1>>,<<Const3>>]
+  /// CHECK:      <<ArraySet1:v\d+>>    ArraySet [<<Array>>,<<Add1>>,<<AddArray1>>]
+  /// CHECK:      <<ArrayGet2:i\d+>>    ArrayGet [<<Array>>,<<Sub2>>]
+  /// CHECK:      <<AddArray2:i\d+>>    Add [<<ArrayGet2>>,<<Const3>>]
+  /// CHECK:      <<ArraySet2:v\d+>>    ArraySet [<<Array>>,<<Sub2>>,<<AddArray2>>]
+
+  /// CHECK-START-ARM64: void Main.arrayAccessSub(int) scheduler (before)
+  /// CHECK:      <<Param:i\d+>>        ParameterValue
+  /// CHECK-DAG:  <<Const1:i\d+>>       IntConstant -1
+  /// CHECK-DAG:  <<Const2:i\d+>>       IntConstant 9
+  /// CHECK-DAG:  <<Const3:i\d+>>       IntConstant 1
+  /// CHECK:      <<Add1:i\d+>>         Add [<<Param>>,<<Const1>>]
+  /// CHECK:      <<Sub2:i\d+>>         Sub [<<Const2>>,<<Param>>]
+  /// CHECK:      <<Array:i\d+>>        IntermediateAddress
+  /// CHECK:      <<ArrayGet1:i\d+>>    ArrayGet [<<Array>>,<<Add1>>]
+  /// CHECK:      <<AddArray1:i\d+>>    Add [<<ArrayGet1>>,<<Const3>>]
+  /// CHECK:      <<ArraySet1:v\d+>>    ArraySet [<<Array>>,<<Add1>>,<<AddArray1>>]
+  /// CHECK:      <<ArrayGet2:i\d+>>    ArrayGet [<<Array>>,<<Sub2>>]
+  /// CHECK:      <<AddArray2:i\d+>>    Add [<<ArrayGet2>>,<<Const3>>]
+  /// CHECK:      <<ArraySet2:v\d+>>    ArraySet [<<Array>>,<<Sub2>>,<<AddArray2>>]
+
+  /// CHECK-START-ARM64: void Main.arrayAccessSub(int) scheduler (after)
+  /// CHECK:      <<Param:i\d+>>        ParameterValue
+  /// CHECK-DAG:  <<Const1:i\d+>>       IntConstant -1
+  /// CHECK-DAG:  <<Const2:i\d+>>       IntConstant 9
+  /// CHECK-DAG:  <<Const3:i\d+>>       IntConstant 1
+  /// CHECK:      <<Add1:i\d+>>         Add [<<Param>>,<<Const1>>]
+  /// CHECK:      <<Sub2:i\d+>>         Sub [<<Const2>>,<<Param>>]
+  /// CHECK:      <<Array:i\d+>>        IntermediateAddress
+  /// CHECK:      <<ArrayGet1:i\d+>>    ArrayGet [<<Array>>,<<Add1>>]
+  /// CHECK:      <<AddArray1:i\d+>>    Add [<<ArrayGet1>>,<<Const3>>]
+  /// CHECK:      <<ArraySet1:v\d+>>    ArraySet [<<Array>>,<<Add1>>,<<AddArray1>>]
+  /// CHECK:      <<ArrayGet2:i\d+>>    ArrayGet [<<Array>>,<<Sub2>>]
+  /// CHECK:      <<AddArray2:i\d+>>    Add [<<ArrayGet2>>,<<Const3>>]
+  /// CHECK:      <<ArraySet2:v\d+>>    ArraySet [<<Array>>,<<Sub2>>,<<AddArray2>>]
+  public static void arrayAccessSub(int i) {
+    int [] array = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10};
+    for (int j = 0; j < 100; j++) {
+      // These two accesses MAY ALIAS
+      array[i - 1]++;
+      array[9 - i]++;
+    }
+  }
+
+  /// CHECK-START-ARM: void Main.arrayAccessLoopVariable() scheduler (before)
+  /// CHECK-DAG: <<Const0:i\d+>>       IntConstant 0
+  /// CHECK-DAG: <<Const1:i\d+>>       IntConstant 1
+  /// CHECK:     <<Phi:i\d+>>          Phi
+  /// CHECK:     <<Array:i\d+>>        IntermediateAddress
+  /// CHECK:     <<ArrayGet1:i\d+>>    ArrayGet
+  /// CHECK:     <<AddArray1:i\d+>>    Add
+  /// CHECK:     <<ArraySet1:v\d+>>    ArraySet
+  /// CHECK:     <<AddVar:i\d+>>       Add
+  /// CHECK:     <<ArrayGet2:i\d+>>    ArrayGet
+  /// CHECK:     <<AddArray2:i\d+>>    Add
+  /// CHECK:     <<ArraySet2:v\d+>>    ArraySet
+
+  /// CHECK-START-ARM: void Main.arrayAccessLoopVariable() scheduler (after)
+  /// CHECK-DAG: <<Const0:i\d+>>       IntConstant 0
+  /// CHECK-DAG: <<Const1:i\d+>>       IntConstant 1
+  /// CHECK:     <<Phi:i\d+>>          Phi
+  /// CHECK:     <<Array:i\d+>>        IntermediateAddress
+  /// CHECK:     <<AddVar:i\d+>>       Add
+  /// CHECK:     <<ArrayGet1:i\d+>>    ArrayGet
+  /// CHECK:     <<ArrayGet2:i\d+>>    ArrayGet
+  /// CHECK:     <<AddArray1:i\d+>>    Add
+  /// CHECK:     <<AddArray2:i\d+>>    Add
+  /// CHECK:     <<ArraySet1:v\d+>>    ArraySet
+  /// CHECK:     <<ArraySet2:v\d+>>    ArraySet
+
+  /// CHECK-START-ARM64: void Main.arrayAccessLoopVariable() scheduler (before)
+  /// CHECK-DAG: <<Const0:i\d+>>       IntConstant 0
+  /// CHECK-DAG: <<Const1:i\d+>>       IntConstant 1
+  /// CHECK:     <<Phi:i\d+>>          Phi
+  /// CHECK:     <<Array:i\d+>>        IntermediateAddress
+  /// CHECK:     <<ArrayGet1:i\d+>>    ArrayGet
+  /// CHECK:     <<AddArray1:i\d+>>    Add
+  /// CHECK:     <<ArraySet1:v\d+>>    ArraySet
+  /// CHECK:     <<AddVar:i\d+>>       Add
+  /// CHECK:     <<ArrayGet2:i\d+>>    ArrayGet
+  /// CHECK:     <<AddArray2:i\d+>>    Add
+  /// CHECK:     <<ArraySet2:v\d+>>    ArraySet
+
+  /// CHECK-START-ARM64: void Main.arrayAccessLoopVariable() scheduler (after)
+  /// CHECK-DAG: <<Const0:i\d+>>       IntConstant 0
+  /// CHECK-DAG: <<Const1:i\d+>>       IntConstant 1
+  /// CHECK:     <<Phi:i\d+>>          Phi
+  /// CHECK:     <<Array:i\d+>>        IntermediateAddress
+  /// CHECK:     <<AddVar:i\d+>>       Add
+  /// CHECK:     <<ArrayGet1:i\d+>>    ArrayGet
+  /// CHECK:     <<ArrayGet2:i\d+>>    ArrayGet
+  /// CHECK:     <<AddArray1:i\d+>>    Add
+  /// CHECK:     <<AddArray2:i\d+>>    Add
+  /// CHECK:     <<ArraySet1:v\d+>>    ArraySet
+  /// CHECK:     <<ArraySet2:v\d+>>    ArraySet
+  public static void arrayAccessLoopVariable() {
+    int [] array = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10};
+    for (int j = 0; j < 9; j++) {
+      array[j]++;
+      array[j + 1]++;
+    }
+  }
+
+  /// CHECK-START-ARM: void Main.accessFields() scheduler (before)
+  /// CHECK:            InstanceFieldGet
+  /// CHECK:            Add
+  /// CHECK:            InstanceFieldSet
+  /// CHECK:            InstanceFieldGet
+  /// CHECK:            Add
+  /// CHECK:            InstanceFieldSet
+  /// CHECK:            StaticFieldGet
+  /// CHECK:            Add
+  /// CHECK:            StaticFieldSet
+  /// CHECK:            StaticFieldGet
+  /// CHECK:            Add
+  /// CHECK:            StaticFieldSet
+
+  /// CHECK-START-ARM: void Main.accessFields() scheduler (after)
+  /// CHECK-DAG:        InstanceFieldGet
+  /// CHECK-DAG:        InstanceFieldGet
+  /// CHECK-DAG:        StaticFieldGet
+  /// CHECK-DAG:        StaticFieldGet
+  /// CHECK:            Add
+  /// CHECK:            Add
+  /// CHECK:            Add
+  /// CHECK:            Add
+  /// CHECK-DAG:        InstanceFieldSet
+  /// CHECK-DAG:        InstanceFieldSet
+  /// CHECK-DAG:        StaticFieldSet
+  /// CHECK-DAG:        StaticFieldSet
+
+  /// CHECK-START-ARM64: void Main.accessFields() scheduler (before)
+  /// CHECK:            InstanceFieldGet
+  /// CHECK:            Add
+  /// CHECK:            InstanceFieldSet
+  /// CHECK:            InstanceFieldGet
+  /// CHECK:            Add
+  /// CHECK:            InstanceFieldSet
+  /// CHECK:            StaticFieldGet
+  /// CHECK:            Add
+  /// CHECK:            StaticFieldSet
+  /// CHECK:            StaticFieldGet
+  /// CHECK:            Add
+  /// CHECK:            StaticFieldSet
+
+  /// CHECK-START-ARM64: void Main.accessFields() scheduler (after)
+  /// CHECK-DAG:        InstanceFieldGet
+  /// CHECK-DAG:        InstanceFieldGet
+  /// CHECK-DAG:        StaticFieldGet
+  /// CHECK-DAG:        StaticFieldGet
+  /// CHECK:            Add
+  /// CHECK:            Add
+  /// CHECK:            Add
+  /// CHECK:            Add
+  /// CHECK-DAG:        InstanceFieldSet
+  /// CHECK-DAG:        InstanceFieldSet
+  /// CHECK-DAG:        StaticFieldSet
+  /// CHECK-DAG:        StaticFieldSet
+  public void accessFields() {
+    my_obj = new ExampleObj(1, 2);
+    for (int i = 0; i < 10; i++) {
+      my_obj.n1++;
+      my_obj.n2++;
+      number1++;
+      number2++;
+    }
+  }
+
   /// CHECK-START-ARM64: int Main.intDiv(int) scheduler (before)
   /// CHECK:               Sub
   /// CHECK:               DivZeroCheck
diff --git a/test/952-invoke-custom-kinds/build b/test/952-invoke-custom-kinds/build
new file mode 100644
index 0000000..a02cdc3
--- /dev/null
+++ b/test/952-invoke-custom-kinds/build
@@ -0,0 +1,22 @@
+#!/bin/bash
+#
+# Copyright (C) 2017 The Android Open Source Project
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#     http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+# Stop if something fails.
+set -e
+
+${DX} --dex --min-sdk-version=26 --output=classes.dex classes
+
+zip $TEST_NAME.jar classes.dex
diff --git a/test/952-invoke-custom-kinds/classes/Main.class b/test/952-invoke-custom-kinds/classes/Main.class
new file mode 100644
index 0000000..6bc04e3
--- /dev/null
+++ b/test/952-invoke-custom-kinds/classes/Main.class
Binary files differ
diff --git a/test/952-invoke-custom-kinds/classes/invokecustom/Interface.class b/test/952-invoke-custom-kinds/classes/invokecustom/Interface.class
new file mode 100644
index 0000000..5dfe958
--- /dev/null
+++ b/test/952-invoke-custom-kinds/classes/invokecustom/Interface.class
Binary files differ
diff --git a/test/952-invoke-custom-kinds/classes/invokecustom/InterfaceImplementor.class b/test/952-invoke-custom-kinds/classes/invokecustom/InterfaceImplementor.class
new file mode 100644
index 0000000..a11ee69
--- /dev/null
+++ b/test/952-invoke-custom-kinds/classes/invokecustom/InterfaceImplementor.class
Binary files differ
diff --git a/test/952-invoke-custom-kinds/classes/invokecustom/InvokeCustom$Interface.class b/test/952-invoke-custom-kinds/classes/invokecustom/InvokeCustom$Interface.class
new file mode 100644
index 0000000..e233feb
--- /dev/null
+++ b/test/952-invoke-custom-kinds/classes/invokecustom/InvokeCustom$Interface.class
Binary files differ
diff --git a/test/952-invoke-custom-kinds/classes/invokecustom/InvokeCustom$InterfaceImplementor.class b/test/952-invoke-custom-kinds/classes/invokecustom/InvokeCustom$InterfaceImplementor.class
new file mode 100644
index 0000000..41e1d43
--- /dev/null
+++ b/test/952-invoke-custom-kinds/classes/invokecustom/InvokeCustom$InterfaceImplementor.class
Binary files differ
diff --git a/test/952-invoke-custom-kinds/classes/invokecustom/InvokeCustom.class b/test/952-invoke-custom-kinds/classes/invokecustom/InvokeCustom.class
new file mode 100644
index 0000000..4f0f497
--- /dev/null
+++ b/test/952-invoke-custom-kinds/classes/invokecustom/InvokeCustom.class
Binary files differ
diff --git a/test/952-invoke-custom-kinds/classes/invokecustom/Super.class b/test/952-invoke-custom-kinds/classes/invokecustom/Super.class
new file mode 100644
index 0000000..5990f28
--- /dev/null
+++ b/test/952-invoke-custom-kinds/classes/invokecustom/Super.class
Binary files differ
diff --git a/test/952-invoke-custom-kinds/classes/invokecustom/TestGenerator$1.class b/test/952-invoke-custom-kinds/classes/invokecustom/TestGenerator$1.class
new file mode 100644
index 0000000..c3266e4
--- /dev/null
+++ b/test/952-invoke-custom-kinds/classes/invokecustom/TestGenerator$1.class
Binary files differ
diff --git a/test/952-invoke-custom-kinds/classes/invokecustom/TestGenerator.class b/test/952-invoke-custom-kinds/classes/invokecustom/TestGenerator.class
new file mode 100644
index 0000000..711db23
--- /dev/null
+++ b/test/952-invoke-custom-kinds/classes/invokecustom/TestGenerator.class
Binary files differ
diff --git a/test/952-invoke-custom-kinds/expected.txt b/test/952-invoke-custom-kinds/expected.txt
new file mode 100644
index 0000000..c72da25
--- /dev/null
+++ b/test/952-invoke-custom-kinds/expected.txt
@@ -0,0 +1,38 @@
+bsmLookupStatic []
+Hello World!
+bsmLookupStatic []
+true
+127
+c
+1024
+123456
+1.2
+123456789
+3.5123456789
+String
+bsmLookupStaticWithExtraArgs [1, 123456789, 123.456, 123456.789123]
+targetMethodTest3 from InvokeCustom
+bsmCreateCallSite [MethodHandle(Super)void]
+targetMethodTest4 from Super
+bsmLookupStatic []
+targetMethodTest5 1000 + -923 = 77
+targetMethodTest5 returned: 77
+bsmLookupStatic []
+targetMethodTest6 8209686820727 + -1172812402961 = 7036874417766
+targetMethodTest6 returned: 7036874417766
+bsmLookupStatic []
+targetMethodTest7 0.50097656 * -0.50097656 = -0.2509775161743164
+targetMethodTest6 returned: -0.2509775161743164
+bsmLookupStatic []
+targetMethodTest8 First invokedynamic invocation
+bsmLookupStatic []
+targetMethodTest8 Second invokedynamic invocation
+bsmLookupStatic []
+targetMethodTest8 Dupe first invokedynamic invocation
+bsmLookupTest9 [MethodHandle()int, MethodHandle(int)void, MethodHandle(InvokeCustom)float, MethodHandle(InvokeCustom,float)void]
+targetMethodTest9 ()void
+checkStaticFieldTest9: old 0 new 1985229328 expected 1985229328 OK
+checkFieldTest9: old 0.0 new 1.99E-19 expected 1.99E-19 OK
+helperMethodTest9 in class invokecustom.InvokeCustom
+run() for Test9
+targetMethodTest9()
diff --git a/test/952-invoke-custom-kinds/info.txt b/test/952-invoke-custom-kinds/info.txt
new file mode 100644
index 0000000..cddb96d
--- /dev/null
+++ b/test/952-invoke-custom-kinds/info.txt
@@ -0,0 +1,7 @@
+This test checks call sites and constant method handles in DEX files used
+by invoke-custom.
+
+It is derived from a dx test (dalvik/dx/tests/135-invoke-custom) which
+generates the invoke-custom using ASM to generate class files. The
+test here differs as it not include an instance a constant method
+handle with a constructor kind (see b/62774190).
diff --git a/test/988-redefine-use-after-free/expected.txt b/test/998-redefine-use-after-free/expected.txt
similarity index 100%
rename from test/988-redefine-use-after-free/expected.txt
rename to test/998-redefine-use-after-free/expected.txt
diff --git a/test/988-redefine-use-after-free/info.txt b/test/998-redefine-use-after-free/info.txt
similarity index 100%
rename from test/988-redefine-use-after-free/info.txt
rename to test/998-redefine-use-after-free/info.txt
diff --git a/test/988-redefine-use-after-free/run b/test/998-redefine-use-after-free/run
similarity index 100%
rename from test/988-redefine-use-after-free/run
rename to test/998-redefine-use-after-free/run
diff --git a/test/988-redefine-use-after-free/src-ex/DexCacheSmash.java b/test/998-redefine-use-after-free/src-ex/DexCacheSmash.java
similarity index 100%
rename from test/988-redefine-use-after-free/src-ex/DexCacheSmash.java
rename to test/998-redefine-use-after-free/src-ex/DexCacheSmash.java
diff --git a/test/988-redefine-use-after-free/src-ex/art/Redefinition.java b/test/998-redefine-use-after-free/src-ex/art/Redefinition.java
similarity index 100%
rename from test/988-redefine-use-after-free/src-ex/art/Redefinition.java
rename to test/998-redefine-use-after-free/src-ex/art/Redefinition.java
diff --git a/test/988-redefine-use-after-free/src/Main.java b/test/998-redefine-use-after-free/src/Main.java
similarity index 96%
rename from test/988-redefine-use-after-free/src/Main.java
rename to test/998-redefine-use-after-free/src/Main.java
index d88c471..cd3babf 100644
--- a/test/988-redefine-use-after-free/src/Main.java
+++ b/test/998-redefine-use-after-free/src/Main.java
@@ -17,7 +17,7 @@
 import java.lang.reflect.*;
 
 public class Main {
-  public static final String TEST_NAME = "988-redefine-use-after-free";
+  public static final String TEST_NAME = "998-redefine-use-after-free";
   public static final int REPS = 1000;
   public static final int STEP = 100;
 
diff --git a/test/Android.bp b/test/Android.bp
index 0dff01b..f893531 100644
--- a/test/Android.bp
+++ b/test/Android.bp
@@ -250,7 +250,10 @@
         "ti-agent/jni_binder.cc",
         "ti-agent/jvmti_helper.cc",
         "ti-agent/test_env.cc",
+        "ti-agent/breakpoint_helper.cc",
         "ti-agent/common_helper.cc",
+        "ti-agent/redefinition_helper.cc",
+        "ti-agent/trace_helper.cc",
         // This is the list of non-special OnLoad things and excludes BCI and anything that depends
         // on ART internals.
         "903-hello-tagging/tagging.cc",
diff --git a/test/dexdump/invoke-custom.dex b/test/dexdump/invoke-custom.dex
index 67261ca..dab6f0f 100644
--- a/test/dexdump/invoke-custom.dex
+++ b/test/dexdump/invoke-custom.dex
Binary files differ
diff --git a/test/dexdump/invoke-custom.lst b/test/dexdump/invoke-custom.lst
index 3540bd1..9037c28 100644
--- a/test/dexdump/invoke-custom.lst
+++ b/test/dexdump/invoke-custom.lst
@@ -1,6 +1,35 @@
 #invoke-custom.dex
-0x000003fc 8 com.android.jack.java7.invokecustom.test004.Tests <init> ()V Tests.java 35
-0x00000414 6 com.android.jack.java7.invokecustom.test004.Tests add (II)I Tests.java 55
-0x0000042c 166 com.android.jack.java7.invokecustom.test004.Tests linkerMethod (Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/invoke/MethodType;ZBCSIFDLjava/lang/String;Ljava/lang/Class;J)Ljava/lang/invoke/CallSite; Tests.java 62
-0x000004e4 24 com.android.jack.java7.invokecustom.test004.Tests main ([Ljava/lang/String;)V Tests.java 82
-0x0000050c 22 com.android.jack.java7.invokecustom.test004.Tests test ()V Tests.java 78
+0x000009a0 8 invokecustom.Super <init> ()V InvokeCustom.java 29
+0x000009b8 16 invokecustom.Super targetMethodTest4 ()V InvokeCustom.java 31
+0x000009d8 8 invokecustom.InvokeCustom <clinit> ()V InvokeCustom.java 102
+0x000009f0 14 invokecustom.InvokeCustom <init> ()V InvokeCustom.java 39
+0x00000a10 74 invokecustom.InvokeCustom <init> (I)V InvokeCustom.java 40
+0x00000a6c 72 invokecustom.InvokeCustom bsmCreateCallSite (Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/invoke/MethodType;Ljava/lang/invoke/MethodHandle;)Ljava/lang/invoke/CallSite; InvokeCustom.java 160
+0x00000ac4 58 invokecustom.InvokeCustom bsmLookupStatic (Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/invoke/MethodType;)Ljava/lang/invoke/CallSite; InvokeCustom.java 142
+0x00000b10 164 invokecustom.InvokeCustom bsmLookupStaticWithExtraArgs (Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/invoke/MethodType;IJFD)Ljava/lang/invoke/CallSite; InvokeCustom.java 151
+0x00000bc4 270 invokecustom.InvokeCustom bsmLookupTest9 (Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/invoke/MethodType;Ljava/lang/invoke/MethodHandle;Ljava/lang/invoke/MethodHandle;Ljava/lang/invoke/MethodHandle;Ljava/lang/invoke/MethodHandle;Ljava/lang/invoke/MethodHandle;Ljava/lang/invoke/MethodHandle;Ljava/lang/invoke/MethodHandle;)Ljava/lang/invoke/CallSite; InvokeCustom.java 170
+0x00000ce4 164 invokecustom.InvokeCustom checkFieldTest9 (Ljava/lang/invoke/MethodHandle;Ljava/lang/invoke/MethodHandle;)V InvokeCustom.java 120
+0x00000d98 160 invokecustom.InvokeCustom checkStaticFieldTest9 (Ljava/lang/invoke/MethodHandle;Ljava/lang/invoke/MethodHandle;)V InvokeCustom.java 107
+0x00000e48 22 invokecustom.InvokeCustom lambda$lambdaTest$0 (Ljava/lang/String;)Z InvokeCustom.java 192
+0x00000e70 142 invokecustom.InvokeCustom lambdaTest ()V InvokeCustom.java 191
+0x00000f10 56 invokecustom.InvokeCustom main ([Ljava/lang/String;)V InvokeCustom.java -1
+0x00000f58 16 invokecustom.InvokeCustom targetMethodTest1 ()V InvokeCustom.java 45
+0x00000f78 92 invokecustom.InvokeCustom targetMethodTest2 (ZBCSIFJDLjava/lang/String;)V InvokeCustom.java 50
+0x00000fe4 16 invokecustom.InvokeCustom targetMethodTest3 ()V InvokeCustom.java 62
+0x00001004 166 invokecustom.InvokeCustom targetMethodTest5 (III)I InvokeCustom.java 72
+0x000010bc 170 invokecustom.InvokeCustom targetMethodTest6 (JJJ)J InvokeCustom.java 81
+0x00001178 172 invokecustom.InvokeCustom targetMethodTest7 (FFD)D InvokeCustom.java 90
+0x00001234 50 invokecustom.InvokeCustom targetMethodTest8 (Ljava/lang/String;)V InvokeCustom.java 99
+0x00001278 16 invokecustom.InvokeCustom targetMethodTest9 ()V InvokeCustom.java 133
+0x00001298 8 invokecustom.InvokeCustom test1 ()V InvokeCustom.java -1
+0x000012b0 54 invokecustom.InvokeCustom test2 ()V InvokeCustom.java -1
+0x000012f8 8 invokecustom.InvokeCustom test3 ()V InvokeCustom.java -1
+0x00001310 18 invokecustom.InvokeCustom test4 ()V InvokeCustom.java -1
+0x00001334 70 invokecustom.InvokeCustom test5 ()V InvokeCustom.java -1
+0x0000138c 88 invokecustom.InvokeCustom test6 ()V InvokeCustom.java -1
+0x000013f4 80 invokecustom.InvokeCustom test7 ()V InvokeCustom.java -1
+0x00001454 32 invokecustom.InvokeCustom test8 ()V InvokeCustom.java -1
+0x00001484 8 invokecustom.InvokeCustom test9 ()V InvokeCustom.java -1
+0x0000149c 54 invokecustom.InvokeCustom helperMethodTest9 ()V InvokeCustom.java 129
+0x000014e4 16 invokecustom.InvokeCustom run ()V InvokeCustom.java 137
+0x00001504 16 invokecustom.InvokeCustom targetMethodTest4 ()V InvokeCustom.java 68
diff --git a/test/dexdump/invoke-custom.txt b/test/dexdump/invoke-custom.txt
index e92549a..bd32508 100644
--- a/test/dexdump/invoke-custom.txt
+++ b/test/dexdump/invoke-custom.txt
@@ -2,253 +2,1424 @@
 Opened 'invoke-custom.dex', DEX version '038'
 DEX file header:
 magic               : 'dex\n038\0'
-checksum            : db57516f
-signature           : 57be...ffc4
-file_size           : 3276
+checksum            : d11a9e29
+signature           : 5b54...15c3
+file_size           : 8984
 header_size         : 112
 link_size           : 0
 link_off            : 0 (0x000000)
-string_ids_size     : 82
+string_ids_size     : 165
 string_ids_off      : 112 (0x000070)
-type_ids_size       : 31
-type_ids_off        : 440 (0x0001b8)
-proto_ids_size      : 16
-proto_ids_off       : 564 (0x000234)
+type_ids_size       : 38
+type_ids_off        : 772 (0x000304)
+proto_ids_size      : 51
+proto_ids_off       : 924 (0x00039c)
 field_ids_size      : 3
-field_ids_off       : 756 (0x0002f4)
-method_ids_size     : 18
-method_ids_off      : 780 (0x00030c)
-class_defs_size     : 1
-class_defs_off      : 932 (0x0003a4)
-data_size           : 2304
-data_off            : 972 (0x0003cc)
+field_ids_off       : 1536 (0x000600)
+method_ids_size     : 78
+method_ids_off      : 1560 (0x000618)
+class_defs_size     : 2
+class_defs_off      : 2184 (0x000888)
+data_size           : 6552
+data_off            : 2432 (0x000980)
 
 Class #0 header:
-class_idx           : 10
-access_flags        : 1 (0x0001)
-superclass_idx      : 15
+class_idx           : 8
+access_flags        : 1024 (0x0400)
+superclass_idx      : 13
 interfaces_off      : 0 (0x000000)
-source_file_idx     : 38
-annotations_off     : 1316 (0x000524)
-class_data_off      : 3014 (0x000bc6)
-static_fields_size  : 1
+source_file_idx     : 27
+annotations_off     : 0 (0x000000)
+class_data_off      : 8589 (0x00218d)
+static_fields_size  : 0
 instance_fields_size: 0
-direct_methods_size : 4
-virtual_methods_size: 1
-
-Class #0 annotations:
-Annotations on method #1 'add'
-  VISIBILITY_BUILD Lcom/android/jack/annotations/CalledByInvokeCustom; argumentTypes={ I I } invokeMethodHandle={ Lcom/android/jack/annotations/LinkerMethodHandle; argumentTypes={ Ljava/lang/invoke/MethodHandles$Lookup; Ljava/lang/String; Ljava/lang/invoke/MethodType; Z B C S I F D Ljava/lang/String; Ljava/lang/Class; J } enclosingType=Lcom/android/jack/java7/invokecustom/test004/Tests; kind=INVOKE_STATIC name="linkerMethod" } methodHandleExtraArgs={ Lcom/android/jack/annotations/Constant; booleanValue={ true } Lcom/android/jack/annotations/Constant; byteValue={ 1 } Lcom/android/jack/annotations/Constant; charValue={ 97 } Lcom/android/jack/annotations/Constant; shortValue={ 1024 } Lcom/android/jack/annotations/Constant; intValue={ 1 } Lcom/android/jack/annotations/Constant; floatValue={ 11.1 } Lcom/android/jack/annotations/Constant; doubleValue={ 2.2 } Lcom/android/jack/annotations/Constant; stringValue={ "Hello" } Lcom/android/jack/annotations/Constant; classValue={ Lcom/android/jack/java7/invokecustom/test004/Tests; } Lcom/android/jack/annotations/Constant; longValue={ 123456789 } } name="add" returnType=I
-Annotations on method #2 'linkerMethod'
-  VISIBILITY_SYSTEM Ldalvik/annotation/Signature; value={ "(" "Ljava/lang/invoke/MethodHandles$Lookup;" "Ljava/lang/String;" "Ljava/lang/invoke/MethodType;" "ZBCSIFD" "Ljava/lang/String;" "Ljava/lang/Class" "<*>;J)" "Ljava/lang/invoke/CallSite;" }
-  VISIBILITY_SYSTEM Ldalvik/annotation/Throws; value={ Ljava/lang/Throwable; }
-Annotations on method #4 'test'
-  VISIBILITY_SYSTEM Ldalvik/annotation/Throws; value={ Ljava/lang/Throwable; }
-  VISIBILITY_RUNTIME Lorg/junit/Test;
+direct_methods_size : 1
+virtual_methods_size: 2
 
 Class #0            -
-  Class descriptor  : 'Lcom/android/jack/java7/invokecustom/test004/Tests;'
-  Access flags      : 0x0001 (PUBLIC)
+  Class descriptor  : 'Linvokecustom/Super;'
+  Access flags      : 0x0400 (ABSTRACT)
   Superclass        : 'Ljava/lang/Object;'
   Interfaces        -
   Static fields     -
-    #0              : (in Lcom/android/jack/java7/invokecustom/test004/Tests;)
-      name          : 'fieldCallSite'
-      type          : 'Ljava/lang/invoke/CallSite;'
-      access        : 0x0009 (PUBLIC STATIC)
   Instance fields   -
   Direct methods    -
-    #0              : (in Lcom/android/jack/java7/invokecustom/test004/Tests;)
+    #0              : (in Linvokecustom/Super;)
       name          : '<init>'
       type          : '()V'
-      access        : 0x10001 (PUBLIC CONSTRUCTOR)
+      access        : 0x10000 (CONSTRUCTOR)
       code          -
       registers     : 1
       ins           : 1
       outs          : 1
       insns size    : 4 16-bit code units
-0003ec:                                        |[0003ec] com.android.jack.java7.invokecustom.test004.Tests.<init>:()V
-0003fc: 7010 0600 0000                         |0000: invoke-direct {v0}, Ljava/lang/Object;.<init>:()V // method@0006
-000402: 0e00                                   |0003: return-void
+000990:                                        |[000990] invokecustom.Super.<init>:()V
+0009a0: 7010 2b00 0000                         |0000: invoke-direct {v0}, Ljava/lang/Object;.<init>:()V // method@002b
+0009a6: 0e00                                   |0003: return-void
       catches       : (none)
       positions     : 
-        0x0000 line=35
+        0x0000 line=29
       locals        : 
-        0x0000 - 0x0004 reg=0 this Lcom/android/jack/java7/invokecustom/test004/Tests; 
-
-    #1              : (in Lcom/android/jack/java7/invokecustom/test004/Tests;)
-      name          : 'add'
-      type          : '(II)I'
-      access        : 0x000a (PRIVATE STATIC)
-      code          -
-      registers     : 3
-      ins           : 2
-      outs          : 0
-      insns size    : 3 16-bit code units
-000404:                                        |[000404] com.android.jack.java7.invokecustom.test004.Tests.add:(II)I
-000414: 9000 0102                              |0000: add-int v0, v1, v2
-000418: 0f00                                   |0002: return v0
-      catches       : (none)
-      positions     : 
-        0x0000 line=55
-      locals        : 
-        0x0000 - 0x0003 reg=1 (null) I 
-        0x0000 - 0x0003 reg=2 (null) I 
-
-    #2              : (in Lcom/android/jack/java7/invokecustom/test004/Tests;)
-      name          : 'linkerMethod'
-      type          : '(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/invoke/MethodType;ZBCSIFDLjava/lang/String;Ljava/lang/Class;J)Ljava/lang/invoke/CallSite;'
-      access        : 0x000a (PRIVATE STATIC)
-      code          -
-      registers     : 24
-      ins           : 15
-      outs          : 6
-      insns size    : 83 16-bit code units
-00041c:                                        |[00041c] com.android.jack.java7.invokecustom.test004.Tests.linkerMethod:(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/invoke/MethodType;ZBCSIFDLjava/lang/String;Ljava/lang/Class;J)Ljava/lang/invoke/CallSite;
-00042c: 7110 1100 0c00                         |0000: invoke-static {v12}, Ljunit/framework/Assert;.assertTrue:(Z)V // method@0011
-000432: 1212                                   |0003: const/4 v2, #int 1 // #1
-000434: 7120 0d00 d200                         |0004: invoke-static {v2, v13}, Ljunit/framework/Assert;.assertEquals:(II)V // method@000d
-00043a: 1302 6100                              |0007: const/16 v2, #int 97 // #61
-00043e: 7120 0a00 e200                         |0009: invoke-static {v2, v14}, Ljunit/framework/Assert;.assertEquals:(CC)V // method@000a
-000444: 1302 0004                              |000c: const/16 v2, #int 1024 // #400
-000448: 7120 0d00 f200                         |000e: invoke-static {v2, v15}, Ljunit/framework/Assert;.assertEquals:(II)V // method@000d
-00044e: 1212                                   |0011: const/4 v2, #int 1 // #1
-000450: 0200 1000                              |0012: move/from16 v0, v16
-000454: 7120 0d00 0200                         |0014: invoke-static {v2, v0}, Ljunit/framework/Assert;.assertEquals:(II)V // method@000d
-00045a: 1202                                   |0017: const/4 v2, #int 0 // #0
-00045c: 1403 9a99 3141                         |0018: const v3, #float 11.1 // #4131999a
-000462: 0200 1100                              |001b: move/from16 v0, v17
-000466: 7130 0c00 0302                         |001d: invoke-static {v3, v0, v2}, Ljunit/framework/Assert;.assertEquals:(FFF)V // method@000c
-00046c: 1606 0000                              |0020: const-wide/16 v6, #int 0 // #0
-000470: 1802 9a99 9999 9999 0140               |0022: const-wide v2, #double 2.2 // #400199999999999a
-00047a: 0504 1200                              |0027: move-wide/from16 v4, v18
-00047e: 7706 0b00 0200                         |0029: invoke-static/range {v2, v3, v4, v5, v6, v7}, Ljunit/framework/Assert;.assertEquals:(DDD)V // method@000b
-000484: 1b02 0700 0000                         |002c: const-string/jumbo v2, "Hello" // string@00000007
-00048a: 0800 1400                              |002f: move-object/from16 v0, v20
-00048e: 7120 1000 0200                         |0031: invoke-static {v2, v0}, Ljunit/framework/Assert;.assertEquals:(Ljava/lang/String;Ljava/lang/String;)V // method@0010
-000494: 1c02 0a00                              |0034: const-class v2, Lcom/android/jack/java7/invokecustom/test004/Tests; // type@000a
-000498: 0800 1500                              |0036: move-object/from16 v0, v21
-00049c: 7120 0f00 0200                         |0038: invoke-static {v2, v0}, Ljunit/framework/Assert;.assertEquals:(Ljava/lang/Object;Ljava/lang/Object;)V // method@000f
-0004a2: 1702 15cd 5b07                         |003b: const-wide/32 v2, #float 1.6536e-34 // #075bcd15
-0004a8: 0500 1600                              |003e: move-wide/from16 v0, v22
-0004ac: 7140 0e00 3210                         |0040: invoke-static {v2, v3, v0, v1}, Ljunit/framework/Assert;.assertEquals:(JJ)V // method@000e
-0004b2: 7100 0900 0000                         |0043: invoke-static {}, Ljava/lang/invoke/MethodHandles;.lookup:()Ljava/lang/invoke/MethodHandles$Lookup; // method@0009
-0004b8: 0c02                                   |0046: move-result-object v2
-0004ba: 1c03 0a00                              |0047: const-class v3, Lcom/android/jack/java7/invokecustom/test004/Tests; // type@000a
-0004be: 6e40 0800 32ba                         |0049: invoke-virtual {v2, v3, v10, v11}, Ljava/lang/invoke/MethodHandles$Lookup;.findStatic:(Ljava/lang/Class;Ljava/lang/String;Ljava/lang/invoke/MethodType;)Ljava/lang/invoke/MethodHandle; // method@0008
-0004c4: 0c02                                   |004c: move-result-object v2
-0004c6: 2203 1400                              |004d: new-instance v3, Ljava/lang/invoke/ConstantCallSite; // type@0014
-0004ca: 7020 0700 2300                         |004f: invoke-direct {v3, v2}, Ljava/lang/invoke/ConstantCallSite;.<init>:(Ljava/lang/invoke/MethodHandle;)V // method@0007
-0004d0: 1103                                   |0052: return-object v3
-      catches       : (none)
-      positions     : 
-        0x0000 line=62
-        0x0003 line=63
-        0x0007 line=64
-        0x000c line=65
-        0x0011 line=66
-        0x0017 line=67
-        0x0020 line=68
-        0x002c line=69
-        0x0034 line=70
-        0x003b line=71
-        0x0043 line=72
-        0x004d line=73
-      locals        : 
-        0x0000 - 0x0053 reg=9 (null) Ljava/lang/invoke/MethodHandles$Lookup; 
-        0x0000 - 0x0053 reg=10 (null) Ljava/lang/String; 
-        0x0000 - 0x0053 reg=11 (null) Ljava/lang/invoke/MethodType; 
-        0x0000 - 0x0053 reg=12 (null) Z 
-        0x0000 - 0x0053 reg=13 (null) B 
-        0x0000 - 0x0053 reg=14 (null) C 
-        0x0000 - 0x0053 reg=15 (null) S 
-        0x0000 - 0x0053 reg=16 (null) I 
-        0x0000 - 0x0053 reg=17 (null) F 
-        0x0000 - 0x0053 reg=18 (null) D 
-        0x0000 - 0x0053 reg=20 (null) Ljava/lang/String; 
-        0x0000 - 0x0053 reg=21 (null) Ljava/lang/Class; 
-        0x0000 - 0x0053 reg=22 (null) J 
-
-    #3              : (in Lcom/android/jack/java7/invokecustom/test004/Tests;)
-      name          : 'main'
-      type          : '([Ljava/lang/String;)V'
-      access        : 0x0009 (PUBLIC STATIC)
-      code          -
-      registers     : 4
-      ins           : 1
-      outs          : 2
-      insns size    : 12 16-bit code units
-0004d4:                                        |[0004d4] com.android.jack.java7.invokecustom.test004.Tests.main:([Ljava/lang/String;)V
-0004e4: 6200 0200                              |0000: sget-object v0, Ljava/lang/System;.out:Ljava/io/PrintStream; // field@0002
-0004e8: 1221                                   |0002: const/4 v1, #int 2 // #2
-0004ea: 1232                                   |0003: const/4 v2, #int 3 // #3
-0004ec: fc20 0000 2100                         |0004: invoke-custom {v1, v2}, call_site@0000
-0004f2: 0a01                                   |0007: move-result v1
-0004f4: 6e20 0500 1000                         |0008: invoke-virtual {v0, v1}, Ljava/io/PrintStream;.println:(I)V // method@0005
-0004fa: 0e00                                   |000b: return-void
-      catches       : (none)
-      positions     : 
-        0x0000 line=82
-        0x000b line=83
-      locals        : 
-        0x0000 - 0x000c reg=3 (null) [Ljava/lang/String; 
+        0x0000 - 0x0004 reg=0 this Linvokecustom/Super; 
 
   Virtual methods   -
-    #0              : (in Lcom/android/jack/java7/invokecustom/test004/Tests;)
-      name          : 'test'
+    #0              : (in Linvokecustom/Super;)
+      name          : 'helperMethodTest9'
+      type          : '()V'
+      access        : 0x0401 (PUBLIC ABSTRACT)
+      code          : (none)
+
+    #1              : (in Linvokecustom/Super;)
+      name          : 'targetMethodTest4'
       type          : '()V'
       access        : 0x0001 (PUBLIC)
       code          -
       registers     : 3
       ins           : 1
       outs          : 2
-      insns size    : 11 16-bit code units
-0004fc:                                        |[0004fc] com.android.jack.java7.invokecustom.test004.Tests.test:()V
-00050c: 1220                                   |0000: const/4 v0, #int 2 // #2
-00050e: 1231                                   |0001: const/4 v1, #int 3 // #3
-000510: fc20 0100 1000                         |0002: invoke-custom {v0, v1}, call_site@0001
-000516: 0a00                                   |0005: move-result v0
-000518: 1251                                   |0006: const/4 v1, #int 5 // #5
-00051a: 7120 0d00 0100                         |0007: invoke-static {v1, v0}, Ljunit/framework/Assert;.assertEquals:(II)V // method@000d
-000520: 0e00                                   |000a: return-void
+      insns size    : 8 16-bit code units
+0009a8:                                        |[0009a8] invokecustom.Super.targetMethodTest4:()V
+0009b8: 6200 0200                              |0000: sget-object v0, Ljava/lang/System;.out:Ljava/io/PrintStream; // field@0002
+0009bc: 1a01 8b00                              |0002: const-string v1, "targetMethodTest4 from Super" // string@008b
+0009c0: 6e20 2900 1000                         |0004: invoke-virtual {v0, v1}, Ljava/io/PrintStream;.println:(Ljava/lang/String;)V // method@0029
+0009c6: 0e00                                   |0007: return-void
       catches       : (none)
       positions     : 
-        0x0000 line=78
-        0x000a line=79
+        0x0000 line=31
+        0x0007 line=32
       locals        : 
-        0x0000 - 0x000b reg=2 this Lcom/android/jack/java7/invokecustom/test004/Tests; 
+        0x0000 - 0x0008 reg=2 this Linvokecustom/Super; 
 
-  source_file_idx   : 38 (Tests.java)
+  source_file_idx   : 27 (InvokeCustom.java)
+
+Class #1 header:
+class_idx           : 7
+access_flags        : 1 (0x0001)
+superclass_idx      : 8
+interfaces_off      : 5460 (0x001554)
+source_file_idx     : 27
+annotations_off     : 5396 (0x001514)
+class_data_off      : 8607 (0x00219f)
+static_fields_size  : 1
+instance_fields_size: 1
+direct_methods_size : 29
+virtual_methods_size: 3
+
+Class #1 annotations:
+Annotations on method #3 'bsmCreateCallSite'
+  VISIBILITY_SYSTEM Ldalvik/annotation/Throws; value={ Ljava/lang/Throwable; }
+Annotations on method #4 'bsmLookupStatic'
+  VISIBILITY_SYSTEM Ldalvik/annotation/Throws; value={ Ljava/lang/NoSuchMethodException; Ljava/lang/IllegalAccessException; }
+Annotations on method #5 'bsmLookupStaticWithExtraArgs'
+  VISIBILITY_SYSTEM Ldalvik/annotation/Throws; value={ Ljava/lang/NoSuchMethodException; Ljava/lang/IllegalAccessException; }
+Annotations on method #6 'bsmLookupTest9'
+  VISIBILITY_SYSTEM Ldalvik/annotation/Throws; value={ Ljava/lang/Throwable; }
+Annotations on method #7 'checkFieldTest9'
+  VISIBILITY_SYSTEM Ldalvik/annotation/Throws; value={ Ljava/lang/Throwable; }
+Annotations on method #8 'checkStaticFieldTest9'
+  VISIBILITY_SYSTEM Ldalvik/annotation/Throws; value={ Ljava/lang/Throwable; }
+
+Class #1            -
+  Class descriptor  : 'Linvokecustom/InvokeCustom;'
+  Access flags      : 0x0001 (PUBLIC)
+  Superclass        : 'Linvokecustom/Super;'
+  Interfaces        -
+    #0              : 'Ljava/lang/Runnable;'
+  Static fields     -
+    #0              : (in Linvokecustom/InvokeCustom;)
+      name          : 'staticFieldTest9'
+      type          : 'I'
+      access        : 0x000a (PRIVATE STATIC)
+  Instance fields   -
+    #0              : (in Linvokecustom/InvokeCustom;)
+      name          : 'fieldTest9'
+      type          : 'F'
+      access        : 0x0002 (PRIVATE)
+  Direct methods    -
+    #0              : (in Linvokecustom/InvokeCustom;)
+      name          : '<clinit>'
+      type          : '()V'
+      access        : 0x10008 (STATIC CONSTRUCTOR)
+      code          -
+      registers     : 1
+      ins           : 0
+      outs          : 0
+      insns size    : 4 16-bit code units
+0009c8:                                        |[0009c8] invokecustom.InvokeCustom.<clinit>:()V
+0009d8: 1200                                   |0000: const/4 v0, #int 0 // #0
+0009da: 6700 0100                              |0001: sput v0, Linvokecustom/InvokeCustom;.staticFieldTest9:I // field@0001
+0009de: 0e00                                   |0003: return-void
+      catches       : (none)
+      positions     : 
+        0x0000 line=102
+      locals        : 
+
+    #1              : (in Linvokecustom/InvokeCustom;)
+      name          : '<init>'
+      type          : '()V'
+      access        : 0x10001 (PUBLIC CONSTRUCTOR)
+      code          -
+      registers     : 2
+      ins           : 1
+      outs          : 1
+      insns size    : 7 16-bit code units
+0009e0:                                        |[0009e0] invokecustom.InvokeCustom.<init>:()V
+0009f0: 7010 2000 0100                         |0000: invoke-direct {v1}, Linvokecustom/Super;.<init>:()V // method@0020
+0009f6: 1200                                   |0003: const/4 v0, #int 0 // #0
+0009f8: 5910 0000                              |0004: iput v0, v1, Linvokecustom/InvokeCustom;.fieldTest9:F // field@0000
+0009fc: 0e00                                   |0006: return-void
+      catches       : (none)
+      positions     : 
+        0x0000 line=39
+        0x0003 line=115
+        0x0006 line=39
+      locals        : 
+        0x0000 - 0x0007 reg=1 this Linvokecustom/InvokeCustom; 
+
+    #2              : (in Linvokecustom/InvokeCustom;)
+      name          : '<init>'
+      type          : '(I)V'
+      access        : 0x10001 (PUBLIC CONSTRUCTOR)
+      code          -
+      registers     : 5
+      ins           : 2
+      outs          : 2
+      insns size    : 37 16-bit code units
+000a00:                                        |[000a00] invokecustom.InvokeCustom.<init>:(I)V
+000a10: 7010 2000 0300                         |0000: invoke-direct {v3}, Linvokecustom/Super;.<init>:()V // method@0020
+000a16: 1200                                   |0003: const/4 v0, #int 0 // #0
+000a18: 5930 0000                              |0004: iput v0, v3, Linvokecustom/InvokeCustom;.fieldTest9:F // field@0000
+000a1c: 6200 0200                              |0006: sget-object v0, Ljava/lang/System;.out:Ljava/io/PrintStream; // field@0002
+000a20: 2201 1000                              |0008: new-instance v1, Ljava/lang/StringBuilder; // type@0010
+000a24: 7010 3000 0100                         |000a: invoke-direct {v1}, Ljava/lang/StringBuilder;.<init>:()V // method@0030
+000a2a: 1a02 1a00                              |000d: const-string v2, "InvokeCustom.<init>(" // string@001a
+000a2e: 6e20 3600 2100                         |000f: invoke-virtual {v1, v2}, Ljava/lang/StringBuilder;.append:(Ljava/lang/String;)Ljava/lang/StringBuilder; // method@0036
+000a34: 0c01                                   |0012: move-result-object v1
+000a36: 6e20 3300 4100                         |0013: invoke-virtual {v1, v4}, Ljava/lang/StringBuilder;.append:(I)Ljava/lang/StringBuilder; // method@0033
+000a3c: 0c01                                   |0016: move-result-object v1
+000a3e: 1a02 0800                              |0017: const-string v2, ")" // string@0008
+000a42: 6e20 3600 2100                         |0019: invoke-virtual {v1, v2}, Ljava/lang/StringBuilder;.append:(Ljava/lang/String;)Ljava/lang/StringBuilder; // method@0036
+000a48: 0c01                                   |001c: move-result-object v1
+000a4a: 6e10 3700 0100                         |001d: invoke-virtual {v1}, Ljava/lang/StringBuilder;.toString:()Ljava/lang/String; // method@0037
+000a50: 0c01                                   |0020: move-result-object v1
+000a52: 6e20 2900 1000                         |0021: invoke-virtual {v0, v1}, Ljava/io/PrintStream;.println:(Ljava/lang/String;)V // method@0029
+000a58: 0e00                                   |0024: return-void
+      catches       : (none)
+      positions     : 
+        0x0000 line=40
+        0x0003 line=115
+        0x0006 line=41
+        0x0024 line=42
+      locals        : 
+        0x0000 - 0x0025 reg=3 this Linvokecustom/InvokeCustom; 
+        0x0000 - 0x0025 reg=4 (null) I 
+
+    #3              : (in Linvokecustom/InvokeCustom;)
+      name          : 'bsmCreateCallSite'
+      type          : '(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/invoke/MethodType;Ljava/lang/invoke/MethodHandle;)Ljava/lang/invoke/CallSite;'
+      access        : 0x0009 (PUBLIC STATIC)
+      code          -
+      registers     : 7
+      ins           : 4
+      outs          : 2
+      insns size    : 36 16-bit code units
+000a5c:                                        |[000a5c] invokecustom.InvokeCustom.bsmCreateCallSite:(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/invoke/MethodType;Ljava/lang/invoke/MethodHandle;)Ljava/lang/invoke/CallSite;
+000a6c: 6200 0200                              |0000: sget-object v0, Ljava/lang/System;.out:Ljava/io/PrintStream; // field@0002
+000a70: 2201 1000                              |0002: new-instance v1, Ljava/lang/StringBuilder; // type@0010
+000a74: 7010 3000 0100                         |0004: invoke-direct {v1}, Ljava/lang/StringBuilder;.<init>:()V // method@0030
+000a7a: 1a02 6000                              |0007: const-string v2, "bsmCreateCallSite [" // string@0060
+000a7e: 6e20 3600 2100                         |0009: invoke-virtual {v1, v2}, Ljava/lang/StringBuilder;.append:(Ljava/lang/String;)Ljava/lang/StringBuilder; // method@0036
+000a84: 0c01                                   |000c: move-result-object v1
+000a86: 6e20 3500 6100                         |000d: invoke-virtual {v1, v6}, Ljava/lang/StringBuilder;.append:(Ljava/lang/Object;)Ljava/lang/StringBuilder; // method@0035
+000a8c: 0c01                                   |0010: move-result-object v1
+000a8e: 1a02 5900                              |0011: const-string v2, "]" // string@0059
+000a92: 6e20 3600 2100                         |0013: invoke-virtual {v1, v2}, Ljava/lang/StringBuilder;.append:(Ljava/lang/String;)Ljava/lang/StringBuilder; // method@0036
+000a98: 0c01                                   |0016: move-result-object v1
+000a9a: 6e10 3700 0100                         |0017: invoke-virtual {v1}, Ljava/lang/StringBuilder;.toString:()Ljava/lang/String; // method@0037
+000aa0: 0c01                                   |001a: move-result-object v1
+000aa2: 6e20 2900 1000                         |001b: invoke-virtual {v0, v1}, Ljava/io/PrintStream;.println:(Ljava/lang/String;)V // method@0029
+000aa8: 2200 1400                              |001e: new-instance v0, Ljava/lang/invoke/ConstantCallSite; // type@0014
+000aac: 7020 3800 6000                         |0020: invoke-direct {v0, v6}, Ljava/lang/invoke/ConstantCallSite;.<init>:(Ljava/lang/invoke/MethodHandle;)V // method@0038
+000ab2: 1100                                   |0023: return-object v0
+      catches       : (none)
+      positions     : 
+        0x0000 line=160
+        0x001e line=161
+      locals        : 
+        0x0000 - 0x0024 reg=3 (null) Ljava/lang/invoke/MethodHandles$Lookup; 
+        0x0000 - 0x0024 reg=4 (null) Ljava/lang/String; 
+        0x0000 - 0x0024 reg=5 (null) Ljava/lang/invoke/MethodType; 
+        0x0000 - 0x0024 reg=6 (null) Ljava/lang/invoke/MethodHandle; 
+
+    #4              : (in Linvokecustom/InvokeCustom;)
+      name          : 'bsmLookupStatic'
+      type          : '(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/invoke/MethodType;)Ljava/lang/invoke/CallSite;'
+      access        : 0x0009 (PUBLIC STATIC)
+      code          -
+      registers     : 5
+      ins           : 3
+      outs          : 4
+      insns size    : 29 16-bit code units
+000ab4:                                        |[000ab4] invokecustom.InvokeCustom.bsmLookupStatic:(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/invoke/MethodType;)Ljava/lang/invoke/CallSite;
+000ac4: 6200 0200                              |0000: sget-object v0, Ljava/lang/System;.out:Ljava/io/PrintStream; // field@0002
+000ac8: 1a01 6200                              |0002: const-string v1, "bsmLookupStatic []" // string@0062
+000acc: 6e20 2900 1000                         |0004: invoke-virtual {v0, v1}, Ljava/io/PrintStream;.println:(Ljava/lang/String;)V // method@0029
+000ad2: 7100 4600 0000                         |0007: invoke-static {}, Ljava/lang/invoke/MethodHandles;.lookup:()Ljava/lang/invoke/MethodHandles$Lookup; // method@0046
+000ad8: 0c00                                   |000a: move-result-object v0
+000ada: 6e10 4500 0000                         |000b: invoke-virtual {v0}, Ljava/lang/invoke/MethodHandles$Lookup;.lookupClass:()Ljava/lang/Class; // method@0045
+000ae0: 0c01                                   |000e: move-result-object v1
+000ae2: 6e40 4400 1043                         |000f: invoke-virtual {v0, v1, v3, v4}, Ljava/lang/invoke/MethodHandles$Lookup;.findStatic:(Ljava/lang/Class;Ljava/lang/String;Ljava/lang/invoke/MethodType;)Ljava/lang/invoke/MethodHandle; // method@0044
+000ae8: 0c00                                   |0012: move-result-object v0
+000aea: 2201 1400                              |0013: new-instance v1, Ljava/lang/invoke/ConstantCallSite; // type@0014
+000aee: 6e20 3a00 4000                         |0015: invoke-virtual {v0, v4}, Ljava/lang/invoke/MethodHandle;.asType:(Ljava/lang/invoke/MethodType;)Ljava/lang/invoke/MethodHandle; // method@003a
+000af4: 0c00                                   |0018: move-result-object v0
+000af6: 7020 3800 0100                         |0019: invoke-direct {v1, v0}, Ljava/lang/invoke/ConstantCallSite;.<init>:(Ljava/lang/invoke/MethodHandle;)V // method@0038
+000afc: 1101                                   |001c: return-object v1
+      catches       : (none)
+      positions     : 
+        0x0000 line=142
+        0x0007 line=143
+        0x000b line=144
+        0x0013 line=145
+      locals        : 
+        0x0000 - 0x001d reg=2 (null) Ljava/lang/invoke/MethodHandles$Lookup; 
+        0x0000 - 0x001d reg=3 (null) Ljava/lang/String; 
+        0x0000 - 0x001d reg=4 (null) Ljava/lang/invoke/MethodType; 
+
+    #5              : (in Linvokecustom/InvokeCustom;)
+      name          : 'bsmLookupStaticWithExtraArgs'
+      type          : '(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/invoke/MethodType;IJFD)Ljava/lang/invoke/CallSite;'
+      access        : 0x0009 (PUBLIC STATIC)
+      code          -
+      registers     : 12
+      ins           : 9
+      outs          : 4
+      insns size    : 82 16-bit code units
+000b00:                                        |[000b00] invokecustom.InvokeCustom.bsmLookupStaticWithExtraArgs:(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/invoke/MethodType;IJFD)Ljava/lang/invoke/CallSite;
+000b10: 6200 0200                              |0000: sget-object v0, Ljava/lang/System;.out:Ljava/io/PrintStream; // field@0002
+000b14: 2201 1000                              |0002: new-instance v1, Ljava/lang/StringBuilder; // type@0010
+000b18: 7010 3000 0100                         |0004: invoke-direct {v1}, Ljava/lang/StringBuilder;.<init>:()V // method@0030
+000b1e: 1a02 6400                              |0007: const-string v2, "bsmLookupStaticWithExtraArgs [" // string@0064
+000b22: 6e20 3600 2100                         |0009: invoke-virtual {v1, v2}, Ljava/lang/StringBuilder;.append:(Ljava/lang/String;)Ljava/lang/StringBuilder; // method@0036
+000b28: 0c01                                   |000c: move-result-object v1
+000b2a: 6e20 3300 6100                         |000d: invoke-virtual {v1, v6}, Ljava/lang/StringBuilder;.append:(I)Ljava/lang/StringBuilder; // method@0033
+000b30: 0c01                                   |0010: move-result-object v1
+000b32: 1a02 0900                              |0011: const-string v2, ", " // string@0009
+000b36: 6e20 3600 2100                         |0013: invoke-virtual {v1, v2}, Ljava/lang/StringBuilder;.append:(Ljava/lang/String;)Ljava/lang/StringBuilder; // method@0036
+000b3c: 0c01                                   |0016: move-result-object v1
+000b3e: 6e30 3400 7108                         |0017: invoke-virtual {v1, v7, v8}, Ljava/lang/StringBuilder;.append:(J)Ljava/lang/StringBuilder; // method@0034
+000b44: 0c01                                   |001a: move-result-object v1
+000b46: 1a02 0900                              |001b: const-string v2, ", " // string@0009
+000b4a: 6e20 3600 2100                         |001d: invoke-virtual {v1, v2}, Ljava/lang/StringBuilder;.append:(Ljava/lang/String;)Ljava/lang/StringBuilder; // method@0036
+000b50: 0c01                                   |0020: move-result-object v1
+000b52: 6e20 3200 9100                         |0021: invoke-virtual {v1, v9}, Ljava/lang/StringBuilder;.append:(F)Ljava/lang/StringBuilder; // method@0032
+000b58: 0c01                                   |0024: move-result-object v1
+000b5a: 1a02 0900                              |0025: const-string v2, ", " // string@0009
+000b5e: 6e20 3600 2100                         |0027: invoke-virtual {v1, v2}, Ljava/lang/StringBuilder;.append:(Ljava/lang/String;)Ljava/lang/StringBuilder; // method@0036
+000b64: 0c01                                   |002a: move-result-object v1
+000b66: 6e30 3100 a10b                         |002b: invoke-virtual {v1, v10, v11}, Ljava/lang/StringBuilder;.append:(D)Ljava/lang/StringBuilder; // method@0031
+000b6c: 0c01                                   |002e: move-result-object v1
+000b6e: 1a02 5900                              |002f: const-string v2, "]" // string@0059
+000b72: 6e20 3600 2100                         |0031: invoke-virtual {v1, v2}, Ljava/lang/StringBuilder;.append:(Ljava/lang/String;)Ljava/lang/StringBuilder; // method@0036
+000b78: 0c01                                   |0034: move-result-object v1
+000b7a: 6e10 3700 0100                         |0035: invoke-virtual {v1}, Ljava/lang/StringBuilder;.toString:()Ljava/lang/String; // method@0037
+000b80: 0c01                                   |0038: move-result-object v1
+000b82: 6e20 2900 1000                         |0039: invoke-virtual {v0, v1}, Ljava/io/PrintStream;.println:(Ljava/lang/String;)V // method@0029
+000b88: 7100 4600 0000                         |003c: invoke-static {}, Ljava/lang/invoke/MethodHandles;.lookup:()Ljava/lang/invoke/MethodHandles$Lookup; // method@0046
+000b8e: 0c00                                   |003f: move-result-object v0
+000b90: 6e10 4500 0000                         |0040: invoke-virtual {v0}, Ljava/lang/invoke/MethodHandles$Lookup;.lookupClass:()Ljava/lang/Class; // method@0045
+000b96: 0c01                                   |0043: move-result-object v1
+000b98: 6e40 4400 1054                         |0044: invoke-virtual {v0, v1, v4, v5}, Ljava/lang/invoke/MethodHandles$Lookup;.findStatic:(Ljava/lang/Class;Ljava/lang/String;Ljava/lang/invoke/MethodType;)Ljava/lang/invoke/MethodHandle; // method@0044
+000b9e: 0c00                                   |0047: move-result-object v0
+000ba0: 2201 1400                              |0048: new-instance v1, Ljava/lang/invoke/ConstantCallSite; // type@0014
+000ba4: 6e20 3a00 5000                         |004a: invoke-virtual {v0, v5}, Ljava/lang/invoke/MethodHandle;.asType:(Ljava/lang/invoke/MethodType;)Ljava/lang/invoke/MethodHandle; // method@003a
+000baa: 0c00                                   |004d: move-result-object v0
+000bac: 7020 3800 0100                         |004e: invoke-direct {v1, v0}, Ljava/lang/invoke/ConstantCallSite;.<init>:(Ljava/lang/invoke/MethodHandle;)V // method@0038
+000bb2: 1101                                   |0051: return-object v1
+      catches       : (none)
+      positions     : 
+        0x0000 line=151
+        0x003c line=152
+        0x0040 line=153
+        0x0048 line=154
+      locals        : 
+        0x0000 - 0x0052 reg=3 (null) Ljava/lang/invoke/MethodHandles$Lookup; 
+        0x0000 - 0x0052 reg=4 (null) Ljava/lang/String; 
+        0x0000 - 0x0052 reg=5 (null) Ljava/lang/invoke/MethodType; 
+        0x0000 - 0x0052 reg=6 (null) I 
+        0x0000 - 0x0052 reg=7 (null) J 
+        0x0000 - 0x0052 reg=9 (null) F 
+        0x0000 - 0x0052 reg=10 (null) D 
+
+    #6              : (in Linvokecustom/InvokeCustom;)
+      name          : 'bsmLookupTest9'
+      type          : '(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/invoke/MethodType;Ljava/lang/invoke/MethodHandle;Ljava/lang/invoke/MethodHandle;Ljava/lang/invoke/MethodHandle;Ljava/lang/invoke/MethodHandle;Ljava/lang/invoke/MethodHandle;Ljava/lang/invoke/MethodHandle;Ljava/lang/invoke/MethodHandle;)Ljava/lang/invoke/CallSite;'
+      access        : 0x0009 (PUBLIC STATIC)
+      code          -
+      registers     : 13
+      ins           : 10
+      outs          : 4
+      insns size    : 135 16-bit code units
+000bb4:                                        |[000bb4] invokecustom.InvokeCustom.bsmLookupTest9:(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/invoke/MethodType;Ljava/lang/invoke/MethodHandle;Ljava/lang/invoke/MethodHandle;Ljava/lang/invoke/MethodHandle;Ljava/lang/invoke/MethodHandle;Ljava/lang/invoke/MethodHandle;Ljava/lang/invoke/MethodHandle;Ljava/lang/invoke/MethodHandle;)Ljava/lang/invoke/CallSite;
+000bc4: 6200 0200                              |0000: sget-object v0, Ljava/lang/System;.out:Ljava/io/PrintStream; // field@0002
+000bc8: 2201 1000                              |0002: new-instance v1, Ljava/lang/StringBuilder; // type@0010
+000bcc: 7010 3000 0100                         |0004: invoke-direct {v1}, Ljava/lang/StringBuilder;.<init>:()V // method@0030
+000bd2: 1a02 6600                              |0007: const-string v2, "bsmLookupTest9 [" // string@0066
+000bd6: 6e20 3600 2100                         |0009: invoke-virtual {v1, v2}, Ljava/lang/StringBuilder;.append:(Ljava/lang/String;)Ljava/lang/StringBuilder; // method@0036
+000bdc: 0c01                                   |000c: move-result-object v1
+000bde: 6e20 3500 6100                         |000d: invoke-virtual {v1, v6}, Ljava/lang/StringBuilder;.append:(Ljava/lang/Object;)Ljava/lang/StringBuilder; // method@0035
+000be4: 0c01                                   |0010: move-result-object v1
+000be6: 1a02 0900                              |0011: const-string v2, ", " // string@0009
+000bea: 6e20 3600 2100                         |0013: invoke-virtual {v1, v2}, Ljava/lang/StringBuilder;.append:(Ljava/lang/String;)Ljava/lang/StringBuilder; // method@0036
+000bf0: 0c01                                   |0016: move-result-object v1
+000bf2: 6e20 3500 7100                         |0017: invoke-virtual {v1, v7}, Ljava/lang/StringBuilder;.append:(Ljava/lang/Object;)Ljava/lang/StringBuilder; // method@0035
+000bf8: 0c01                                   |001a: move-result-object v1
+000bfa: 1a02 0900                              |001b: const-string v2, ", " // string@0009
+000bfe: 6e20 3600 2100                         |001d: invoke-virtual {v1, v2}, Ljava/lang/StringBuilder;.append:(Ljava/lang/String;)Ljava/lang/StringBuilder; // method@0036
+000c04: 0c01                                   |0020: move-result-object v1
+000c06: 6e20 3500 8100                         |0021: invoke-virtual {v1, v8}, Ljava/lang/StringBuilder;.append:(Ljava/lang/Object;)Ljava/lang/StringBuilder; // method@0035
+000c0c: 0c01                                   |0024: move-result-object v1
+000c0e: 1a02 0900                              |0025: const-string v2, ", " // string@0009
+000c12: 6e20 3600 2100                         |0027: invoke-virtual {v1, v2}, Ljava/lang/StringBuilder;.append:(Ljava/lang/String;)Ljava/lang/StringBuilder; // method@0036
+000c18: 0c01                                   |002a: move-result-object v1
+000c1a: 6e20 3500 9100                         |002b: invoke-virtual {v1, v9}, Ljava/lang/StringBuilder;.append:(Ljava/lang/Object;)Ljava/lang/StringBuilder; // method@0035
+000c20: 0c01                                   |002e: move-result-object v1
+000c22: 1a02 5900                              |002f: const-string v2, "]" // string@0059
+000c26: 6e20 3600 2100                         |0031: invoke-virtual {v1, v2}, Ljava/lang/StringBuilder;.append:(Ljava/lang/String;)Ljava/lang/StringBuilder; // method@0036
+000c2c: 0c01                                   |0034: move-result-object v1
+000c2e: 6e10 3700 0100                         |0035: invoke-virtual {v1}, Ljava/lang/StringBuilder;.toString:()Ljava/lang/String; // method@0037
+000c34: 0c01                                   |0038: move-result-object v1
+000c36: 6e20 2900 1000                         |0039: invoke-virtual {v0, v1}, Ljava/io/PrintStream;.println:(Ljava/lang/String;)V // method@0029
+000c3c: 6200 0200                              |003c: sget-object v0, Ljava/lang/System;.out:Ljava/io/PrintStream; // field@0002
+000c40: 2201 1000                              |003e: new-instance v1, Ljava/lang/StringBuilder; // type@0010
+000c44: 7010 3000 0100                         |0040: invoke-direct {v1}, Ljava/lang/StringBuilder;.<init>:()V // method@0030
+000c4a: 6e20 3600 4100                         |0043: invoke-virtual {v1, v4}, Ljava/lang/StringBuilder;.append:(Ljava/lang/String;)Ljava/lang/StringBuilder; // method@0036
+000c50: 0c01                                   |0046: move-result-object v1
+000c52: 1a02 0100                              |0047: const-string v2, " " // string@0001
+000c56: 6e20 3600 2100                         |0049: invoke-virtual {v1, v2}, Ljava/lang/StringBuilder;.append:(Ljava/lang/String;)Ljava/lang/StringBuilder; // method@0036
+000c5c: 0c01                                   |004c: move-result-object v1
+000c5e: 6e20 3500 5100                         |004d: invoke-virtual {v1, v5}, Ljava/lang/StringBuilder;.append:(Ljava/lang/Object;)Ljava/lang/StringBuilder; // method@0035
+000c64: 0c01                                   |0050: move-result-object v1
+000c66: 6e10 3700 0100                         |0051: invoke-virtual {v1}, Ljava/lang/StringBuilder;.toString:()Ljava/lang/String; // method@0037
+000c6c: 0c01                                   |0054: move-result-object v1
+000c6e: 6e20 2900 1000                         |0055: invoke-virtual {v0, v1}, Ljava/io/PrintStream;.println:(Ljava/lang/String;)V // method@0029
+000c74: 7120 0800 7600                         |0058: invoke-static {v6, v7}, Linvokecustom/InvokeCustom;.checkStaticFieldTest9:(Ljava/lang/invoke/MethodHandle;Ljava/lang/invoke/MethodHandle;)V // method@0008
+000c7a: 2200 0700                              |005b: new-instance v0, Linvokecustom/InvokeCustom; // type@0007
+000c7e: 7010 0100 0000                         |005d: invoke-direct {v0}, Linvokecustom/InvokeCustom;.<init>:()V // method@0001
+000c84: 7030 0700 8009                         |0060: invoke-direct {v0, v8, v9}, Linvokecustom/InvokeCustom;.checkFieldTest9:(Ljava/lang/invoke/MethodHandle;Ljava/lang/invoke/MethodHandle;)V // method@0007
+000c8a: fa20 4000 0a00 2700                    |0063: invoke-polymorphic {v10, v0}, Ljava/lang/invoke/MethodHandle;.invokeExact:([Ljava/lang/Object;)Ljava/lang/Object;, (Linvokecustom/InvokeCustom;)V // method@0040, proto@0027
+000c92: 1230                                   |0067: const/4 v0, #int 3 // #3
+000c94: fa20 4000 0b00 0500                    |0068: invoke-polymorphic {v11, v0}, Ljava/lang/invoke/MethodHandle;.invokeExact:([Ljava/lang/Object;)Ljava/lang/Object;, (I)Linvokecustom/InvokeCustom; // method@0040, proto@0005
+000c9c: 0c00                                   |006c: move-result-object v0
+000c9e: fa20 3b00 0c00 2700                    |006d: invoke-polymorphic {v12, v0}, Ljava/lang/invoke/MethodHandle;.invoke:([Ljava/lang/Object;)Ljava/lang/Object;, (Linvokecustom/InvokeCustom;)V // method@003b, proto@0027
+000ca6: 7100 4600 0000                         |0071: invoke-static {}, Ljava/lang/invoke/MethodHandles;.lookup:()Ljava/lang/invoke/MethodHandles$Lookup; // method@0046
+000cac: 0c00                                   |0074: move-result-object v0
+000cae: 6e10 4500 0000                         |0075: invoke-virtual {v0}, Ljava/lang/invoke/MethodHandles$Lookup;.lookupClass:()Ljava/lang/Class; // method@0045
+000cb4: 0c01                                   |0078: move-result-object v1
+000cb6: 6e40 4400 1054                         |0079: invoke-virtual {v0, v1, v4, v5}, Ljava/lang/invoke/MethodHandles$Lookup;.findStatic:(Ljava/lang/Class;Ljava/lang/String;Ljava/lang/invoke/MethodType;)Ljava/lang/invoke/MethodHandle; // method@0044
+000cbc: 0c00                                   |007c: move-result-object v0
+000cbe: 2201 1400                              |007d: new-instance v1, Ljava/lang/invoke/ConstantCallSite; // type@0014
+000cc2: 6e20 3a00 5000                         |007f: invoke-virtual {v0, v5}, Ljava/lang/invoke/MethodHandle;.asType:(Ljava/lang/invoke/MethodType;)Ljava/lang/invoke/MethodHandle; // method@003a
+000cc8: 0c00                                   |0082: move-result-object v0
+000cca: 7020 3800 0100                         |0083: invoke-direct {v1, v0}, Ljava/lang/invoke/ConstantCallSite;.<init>:(Ljava/lang/invoke/MethodHandle;)V // method@0038
+000cd0: 1101                                   |0086: return-object v1
+      catches       : (none)
+      positions     : 
+        0x0000 line=170
+        0x003c line=172
+        0x0058 line=175
+        0x005b line=176
+        0x0060 line=177
+        0x0063 line=180
+        0x0067 line=182
+        0x006d line=183
+        0x0071 line=185
+        0x0075 line=186
+        0x007d line=187
+      locals        : 
+        0x0000 - 0x0087 reg=3 (null) Ljava/lang/invoke/MethodHandles$Lookup; 
+        0x0000 - 0x0087 reg=4 (null) Ljava/lang/String; 
+        0x0000 - 0x0087 reg=5 (null) Ljava/lang/invoke/MethodType; 
+        0x0000 - 0x0087 reg=6 (null) Ljava/lang/invoke/MethodHandle; 
+        0x0000 - 0x0087 reg=7 (null) Ljava/lang/invoke/MethodHandle; 
+        0x0000 - 0x0087 reg=8 (null) Ljava/lang/invoke/MethodHandle; 
+        0x0000 - 0x0087 reg=9 (null) Ljava/lang/invoke/MethodHandle; 
+        0x0000 - 0x0087 reg=10 (null) Ljava/lang/invoke/MethodHandle; 
+        0x0000 - 0x0087 reg=11 (null) Ljava/lang/invoke/MethodHandle; 
+        0x0000 - 0x0087 reg=12 (null) Ljava/lang/invoke/MethodHandle; 
+
+    #7              : (in Linvokecustom/InvokeCustom;)
+      name          : 'checkFieldTest9'
+      type          : '(Ljava/lang/invoke/MethodHandle;Ljava/lang/invoke/MethodHandle;)V'
+      access        : 0x0002 (PRIVATE)
+      code          -
+      registers     : 9
+      ins           : 3
+      outs          : 3
+      insns size    : 82 16-bit code units
+000cd4:                                        |[000cd4] invokecustom.InvokeCustom.checkFieldTest9:(Ljava/lang/invoke/MethodHandle;Ljava/lang/invoke/MethodHandle;)V
+000ce4: 1405 0ff0 6a20                         |0000: const v5, #float 1.99e-19 // #206af00f
+000cea: fa20 4000 6700 0100                    |0003: invoke-polymorphic {v7, v6}, Ljava/lang/invoke/MethodHandle;.invokeExact:([Ljava/lang/Object;)Ljava/lang/Object;, (Linvokecustom/InvokeCustom;)F // method@0040, proto@0001
+000cf2: 0a00                                   |0007: move-result v0
+000cf4: fa30 4000 6805 2800                    |0008: invoke-polymorphic {v8, v6, v5}, Ljava/lang/invoke/MethodHandle;.invokeExact:([Ljava/lang/Object;)Ljava/lang/Object;, (Linvokecustom/InvokeCustom;F)V // method@0040, proto@0028
+000cfc: fa20 4000 6700 0100                    |000c: invoke-polymorphic {v7, v6}, Ljava/lang/invoke/MethodHandle;.invokeExact:([Ljava/lang/Object;)Ljava/lang/Object;, (Linvokecustom/InvokeCustom;)F // method@0040, proto@0001
+000d04: 0a01                                   |0010: move-result v1
+000d06: 6202 0200                              |0011: sget-object v2, Ljava/lang/System;.out:Ljava/io/PrintStream; // field@0002
+000d0a: 2203 1000                              |0013: new-instance v3, Ljava/lang/StringBuilder; // type@0010
+000d0e: 7010 3000 0300                         |0015: invoke-direct {v3}, Ljava/lang/StringBuilder;.<init>:()V // method@0030
+000d14: 1a04 6800                              |0018: const-string v4, "checkFieldTest9: old " // string@0068
+000d18: 6e20 3600 4300                         |001a: invoke-virtual {v3, v4}, Ljava/lang/StringBuilder;.append:(Ljava/lang/String;)Ljava/lang/StringBuilder; // method@0036
+000d1e: 0c03                                   |001d: move-result-object v3
+000d20: 6e20 3200 0300                         |001e: invoke-virtual {v3, v0}, Ljava/lang/StringBuilder;.append:(F)Ljava/lang/StringBuilder; // method@0032
+000d26: 0c00                                   |0021: move-result-object v0
+000d28: 1a03 0700                              |0022: const-string v3, " new " // string@0007
+000d2c: 6e20 3600 3000                         |0024: invoke-virtual {v0, v3}, Ljava/lang/StringBuilder;.append:(Ljava/lang/String;)Ljava/lang/StringBuilder; // method@0036
+000d32: 0c00                                   |0027: move-result-object v0
+000d34: 6e20 3200 1000                         |0028: invoke-virtual {v0, v1}, Ljava/lang/StringBuilder;.append:(F)Ljava/lang/StringBuilder; // method@0032
+000d3a: 0c00                                   |002b: move-result-object v0
+000d3c: 1a03 0600                              |002c: const-string v3, " expected " // string@0006
+000d40: 6e20 3600 3000                         |002e: invoke-virtual {v0, v3}, Ljava/lang/StringBuilder;.append:(Ljava/lang/String;)Ljava/lang/StringBuilder; // method@0036
+000d46: 0c00                                   |0031: move-result-object v0
+000d48: 6e20 3200 5000                         |0032: invoke-virtual {v0, v5}, Ljava/lang/StringBuilder;.append:(F)Ljava/lang/StringBuilder; // method@0032
+000d4e: 0c00                                   |0035: move-result-object v0
+000d50: 1a03 0100                              |0036: const-string v3, " " // string@0001
+000d54: 6e20 3600 3000                         |0038: invoke-virtual {v0, v3}, Ljava/lang/StringBuilder;.append:(Ljava/lang/String;)Ljava/lang/StringBuilder; // method@0036
+000d5a: 0c00                                   |003b: move-result-object v0
+000d5c: 6e10 3700 0000                         |003c: invoke-virtual {v0}, Ljava/lang/StringBuilder;.toString:()Ljava/lang/String; // method@0037
+000d62: 0c00                                   |003f: move-result-object v0
+000d64: 6e20 2300 0200                         |0040: invoke-virtual {v2, v0}, Ljava/io/PrintStream;.print:(Ljava/lang/String;)V // method@0023
+000d6a: 6202 0200                              |0043: sget-object v2, Ljava/lang/System;.out:Ljava/io/PrintStream; // field@0002
+000d6e: 2d00 0105                              |0045: cmpl-float v0, v1, v5
+000d72: 3900 0800                              |0047: if-nez v0, 004f // +0008
+000d76: 1a00 4400                              |0049: const-string v0, "OK" // string@0044
+000d7a: 6e20 2900 0200                         |004b: invoke-virtual {v2, v0}, Ljava/io/PrintStream;.println:(Ljava/lang/String;)V // method@0029
+000d80: 0e00                                   |004e: return-void
+000d82: 1a00 1100                              |004f: const-string v0, "ERROR" // string@0011
+000d86: 28fa                                   |0051: goto 004b // -0006
+      catches       : (none)
+      positions     : 
+        0x0003 line=120
+        0x0008 line=121
+        0x000c line=122
+        0x0011 line=123
+        0x0043 line=125
+        0x004e line=126
+        0x004f line=125
+      locals        : 
+        0x0000 - 0x0052 reg=6 this Linvokecustom/InvokeCustom; 
+        0x0000 - 0x0052 reg=7 (null) Ljava/lang/invoke/MethodHandle; 
+        0x0000 - 0x0052 reg=8 (null) Ljava/lang/invoke/MethodHandle; 
+
+    #8              : (in Linvokecustom/InvokeCustom;)
+      name          : 'checkStaticFieldTest9'
+      type          : '(Ljava/lang/invoke/MethodHandle;Ljava/lang/invoke/MethodHandle;)V'
+      access        : 0x000a (PRIVATE STATIC)
+      code          -
+      registers     : 8
+      ins           : 2
+      outs          : 2
+      insns size    : 80 16-bit code units
+000d88:                                        |[000d88] invokecustom.InvokeCustom.checkStaticFieldTest9:(Ljava/lang/invoke/MethodHandle;Ljava/lang/invoke/MethodHandle;)V
+000d98: 1405 1032 5476                         |0000: const v5, #float 1.07596e+33 // #76543210
+000d9e: fa10 4000 0600 0200                    |0003: invoke-polymorphic {v6}, Ljava/lang/invoke/MethodHandle;.invokeExact:([Ljava/lang/Object;)Ljava/lang/Object;, ()I // method@0040, proto@0002
+000da6: 0a00                                   |0007: move-result v0
+000da8: fa20 4000 5700 2500                    |0008: invoke-polymorphic {v7, v5}, Ljava/lang/invoke/MethodHandle;.invokeExact:([Ljava/lang/Object;)Ljava/lang/Object;, (I)V // method@0040, proto@0025
+000db0: fa10 4000 0600 0200                    |000c: invoke-polymorphic {v6}, Ljava/lang/invoke/MethodHandle;.invokeExact:([Ljava/lang/Object;)Ljava/lang/Object;, ()I // method@0040, proto@0002
+000db8: 0a01                                   |0010: move-result v1
+000dba: 6202 0200                              |0011: sget-object v2, Ljava/lang/System;.out:Ljava/io/PrintStream; // field@0002
+000dbe: 2203 1000                              |0013: new-instance v3, Ljava/lang/StringBuilder; // type@0010
+000dc2: 7010 3000 0300                         |0015: invoke-direct {v3}, Ljava/lang/StringBuilder;.<init>:()V // method@0030
+000dc8: 1a04 6a00                              |0018: const-string v4, "checkStaticFieldTest9: old " // string@006a
+000dcc: 6e20 3600 4300                         |001a: invoke-virtual {v3, v4}, Ljava/lang/StringBuilder;.append:(Ljava/lang/String;)Ljava/lang/StringBuilder; // method@0036
+000dd2: 0c03                                   |001d: move-result-object v3
+000dd4: 6e20 3300 0300                         |001e: invoke-virtual {v3, v0}, Ljava/lang/StringBuilder;.append:(I)Ljava/lang/StringBuilder; // method@0033
+000dda: 0c00                                   |0021: move-result-object v0
+000ddc: 1a03 0700                              |0022: const-string v3, " new " // string@0007
+000de0: 6e20 3600 3000                         |0024: invoke-virtual {v0, v3}, Ljava/lang/StringBuilder;.append:(Ljava/lang/String;)Ljava/lang/StringBuilder; // method@0036
+000de6: 0c00                                   |0027: move-result-object v0
+000de8: 6e20 3300 1000                         |0028: invoke-virtual {v0, v1}, Ljava/lang/StringBuilder;.append:(I)Ljava/lang/StringBuilder; // method@0033
+000dee: 0c00                                   |002b: move-result-object v0
+000df0: 1a03 0600                              |002c: const-string v3, " expected " // string@0006
+000df4: 6e20 3600 3000                         |002e: invoke-virtual {v0, v3}, Ljava/lang/StringBuilder;.append:(Ljava/lang/String;)Ljava/lang/StringBuilder; // method@0036
+000dfa: 0c00                                   |0031: move-result-object v0
+000dfc: 6e20 3300 5000                         |0032: invoke-virtual {v0, v5}, Ljava/lang/StringBuilder;.append:(I)Ljava/lang/StringBuilder; // method@0033
+000e02: 0c00                                   |0035: move-result-object v0
+000e04: 1a03 0100                              |0036: const-string v3, " " // string@0001
+000e08: 6e20 3600 3000                         |0038: invoke-virtual {v0, v3}, Ljava/lang/StringBuilder;.append:(Ljava/lang/String;)Ljava/lang/StringBuilder; // method@0036
+000e0e: 0c00                                   |003b: move-result-object v0
+000e10: 6e10 3700 0000                         |003c: invoke-virtual {v0}, Ljava/lang/StringBuilder;.toString:()Ljava/lang/String; // method@0037
+000e16: 0c00                                   |003f: move-result-object v0
+000e18: 6e20 2300 0200                         |0040: invoke-virtual {v2, v0}, Ljava/io/PrintStream;.print:(Ljava/lang/String;)V // method@0023
+000e1e: 6202 0200                              |0043: sget-object v2, Ljava/lang/System;.out:Ljava/io/PrintStream; // field@0002
+000e22: 3351 0800                              |0045: if-ne v1, v5, 004d // +0008
+000e26: 1a00 4400                              |0047: const-string v0, "OK" // string@0044
+000e2a: 6e20 2900 0200                         |0049: invoke-virtual {v2, v0}, Ljava/io/PrintStream;.println:(Ljava/lang/String;)V // method@0029
+000e30: 0e00                                   |004c: return-void
+000e32: 1a00 1100                              |004d: const-string v0, "ERROR" // string@0011
+000e36: 28fa                                   |004f: goto 0049 // -0006
+      catches       : (none)
+      positions     : 
+        0x0003 line=107
+        0x0008 line=108
+        0x000c line=109
+        0x0011 line=110
+        0x0043 line=112
+        0x004c line=113
+        0x004d line=112
+      locals        : 
+        0x0000 - 0x0050 reg=6 (null) Ljava/lang/invoke/MethodHandle; 
+        0x0000 - 0x0050 reg=7 (null) Ljava/lang/invoke/MethodHandle; 
+
+    #9              : (in Linvokecustom/InvokeCustom;)
+      name          : 'lambda$lambdaTest$0'
+      type          : '(Ljava/lang/String;)Z'
+      access        : 0x100a (PRIVATE STATIC SYNTHETIC)
+      code          -
+      registers     : 3
+      ins           : 1
+      outs          : 2
+      insns size    : 11 16-bit code units
+000e38:                                        |[000e38] invokecustom.InvokeCustom.lambda$lambdaTest$0:(Ljava/lang/String;)Z
+000e48: 1a00 4500                              |0000: const-string v0, "One" // string@0045
+000e4c: 6e10 2f00 0200                         |0002: invoke-virtual {v2}, Ljava/lang/String;.trim:()Ljava/lang/String; // method@002f
+000e52: 0c01                                   |0005: move-result-object v1
+000e54: 6e20 2e00 1000                         |0006: invoke-virtual {v0, v1}, Ljava/lang/String;.equals:(Ljava/lang/Object;)Z // method@002e
+000e5a: 0a00                                   |0009: move-result v0
+000e5c: 0f00                                   |000a: return v0
+      catches       : (none)
+      positions     : 
+        0x0000 line=192
+      locals        : 
+        0x0000 - 0x000b reg=2 (null) Ljava/lang/String; 
+
+    #10              : (in Linvokecustom/InvokeCustom;)
+      name          : 'lambdaTest'
+      type          : '()V'
+      access        : 0x0009 (PUBLIC STATIC)
+      code          -
+      registers     : 3
+      ins           : 0
+      outs          : 2
+      insns size    : 71 16-bit code units
+000e60:                                        |[000e60] invokecustom.InvokeCustom.lambdaTest:()V
+000e70: 1230                                   |0000: const/4 v0, #int 3 // #3
+000e72: 2300 2500                              |0001: new-array v0, v0, [Ljava/lang/String; // type@0025
+000e76: 1201                                   |0003: const/4 v1, #int 0 // #0
+000e78: 1a02 4900                              |0004: const-string v2, "Three" // string@0049
+000e7c: 4d02 0001                              |0006: aput-object v2, v0, v1
+000e80: 1211                                   |0008: const/4 v1, #int 1 // #1
+000e82: 1a02 4500                              |0009: const-string v2, "One" // string@0045
+000e86: 4d02 0001                              |000b: aput-object v2, v0, v1
+000e8a: 1221                                   |000d: const/4 v1, #int 2 // #2
+000e8c: 1a02 1600                              |000e: const-string v2, "FortyTwo" // string@0016
+000e90: 4d02 0001                              |0010: aput-object v2, v0, v1
+000e94: 7110 4700 0000                         |0012: invoke-static {v0}, Ljava/util/Arrays;.asList:([Ljava/lang/Object;)Ljava/util/List; // method@0047
+000e9a: 0c01                                   |0015: move-result-object v1
+000e9c: 7210 4800 0100                         |0016: invoke-interface {v1}, Ljava/util/List;.stream:()Ljava/util/stream/Stream; // method@0048
+000ea2: 0c00                                   |0019: move-result-object v0
+000ea4: fc00 0000 0000                         |001a: invoke-custom {}, call_site@0000
+000eaa: 0c02                                   |001d: move-result-object v2
+000eac: 7220 4a00 2000                         |001e: invoke-interface {v0, v2}, Ljava/util/stream/Stream;.filter:(Ljava/util/function/Predicate;)Ljava/util/stream/Stream; // method@004a
+000eb2: 0c00                                   |0021: move-result-object v0
+000eb4: fc00 0100 0000                         |0022: invoke-custom {}, call_site@0001
+000eba: 0c02                                   |0025: move-result-object v2
+000ebc: 7220 4d00 2000                         |0026: invoke-interface {v0, v2}, Ljava/util/stream/Stream;.map:(Ljava/util/function/Function;)Ljava/util/stream/Stream; // method@004d
+000ec2: 0c00                                   |0029: move-result-object v0
+000ec4: 7210 4b00 0000                         |002a: invoke-interface {v0}, Ljava/util/stream/Stream;.findAny:()Ljava/util/Optional; // method@004b
+000eca: 0c00                                   |002d: move-result-object v0
+000ecc: 1a02 0000                              |002e: const-string v2, "" // string@0000
+000ed0: 6e20 4900 2000                         |0030: invoke-virtual {v0, v2}, Ljava/util/Optional;.orElse:(Ljava/lang/Object;)Ljava/lang/Object; // method@0049
+000ed6: 0c00                                   |0033: move-result-object v0
+000ed8: 1f00 0f00                              |0034: check-cast v0, Ljava/lang/String; // type@000f
+000edc: 7210 4800 0100                         |0036: invoke-interface {v1}, Ljava/util/List;.stream:()Ljava/util/stream/Stream; // method@0048
+000ee2: 0c00                                   |0039: move-result-object v0
+000ee4: 6201 0200                              |003a: sget-object v1, Ljava/lang/System;.out:Ljava/io/PrintStream; // field@0002
+000ee8: 6e10 2c00 0100                         |003c: invoke-virtual {v1}, Ljava/lang/Object;.getClass:()Ljava/lang/Class; // method@002c
+000eee: fc10 0200 0100                         |003f: invoke-custom {v1}, call_site@0002
+000ef4: 0c01                                   |0042: move-result-object v1
+000ef6: 7220 4c00 1000                         |0043: invoke-interface {v0, v1}, Ljava/util/stream/Stream;.forEach:(Ljava/util/function/Consumer;)V // method@004c
+000efc: 0e00                                   |0046: return-void
+      catches       : (none)
+      positions     : 
+        0x0000 line=191
+        0x0016 line=192
+        0x0026 line=193
+        0x0036 line=194
+        0x0046 line=195
+      locals        : 
+
+    #11              : (in Linvokecustom/InvokeCustom;)
+      name          : 'main'
+      type          : '([Ljava/lang/String;)V'
+      access        : 0x0009 (PUBLIC STATIC)
+      code          -
+      registers     : 1
+      ins           : 1
+      outs          : 0
+      insns size    : 28 16-bit code units
+000f00:                                        |[000f00] invokecustom.InvokeCustom.main:([Ljava/lang/String;)V
+000f10: 7100 1700 0000                         |0000: invoke-static {}, Linvokecustom/InvokeCustom;.test1:()V // method@0017
+000f16: 7100 1800 0000                         |0003: invoke-static {}, Linvokecustom/InvokeCustom;.test2:()V // method@0018
+000f1c: 7100 1900 0000                         |0006: invoke-static {}, Linvokecustom/InvokeCustom;.test3:()V // method@0019
+000f22: 7100 1a00 0000                         |0009: invoke-static {}, Linvokecustom/InvokeCustom;.test4:()V // method@001a
+000f28: 7100 1b00 0000                         |000c: invoke-static {}, Linvokecustom/InvokeCustom;.test5:()V // method@001b
+000f2e: 7100 1c00 0000                         |000f: invoke-static {}, Linvokecustom/InvokeCustom;.test6:()V // method@001c
+000f34: 7100 1d00 0000                         |0012: invoke-static {}, Linvokecustom/InvokeCustom;.test7:()V // method@001d
+000f3a: 7100 1e00 0000                         |0015: invoke-static {}, Linvokecustom/InvokeCustom;.test8:()V // method@001e
+000f40: 7100 1f00 0000                         |0018: invoke-static {}, Linvokecustom/InvokeCustom;.test9:()V // method@001f
+000f46: 0e00                                   |001b: return-void
+      catches       : (none)
+      positions     : 
+      locals        : 
+
+    #12              : (in Linvokecustom/InvokeCustom;)
+      name          : 'targetMethodTest1'
+      type          : '()V'
+      access        : 0x000a (PRIVATE STATIC)
+      code          -
+      registers     : 2
+      ins           : 0
+      outs          : 2
+      insns size    : 8 16-bit code units
+000f48:                                        |[000f48] invokecustom.InvokeCustom.targetMethodTest1:()V
+000f58: 6200 0200                              |0000: sget-object v0, Ljava/lang/System;.out:Ljava/io/PrintStream; // field@0002
+000f5c: 1a01 1700                              |0002: const-string v1, "Hello World!" // string@0017
+000f60: 6e20 2900 1000                         |0004: invoke-virtual {v0, v1}, Ljava/io/PrintStream;.println:(Ljava/lang/String;)V // method@0029
+000f66: 0e00                                   |0007: return-void
+      catches       : (none)
+      positions     : 
+        0x0000 line=45
+        0x0007 line=46
+      locals        : 
+
+    #13              : (in Linvokecustom/InvokeCustom;)
+      name          : 'targetMethodTest2'
+      type          : '(ZBCSIFJDLjava/lang/String;)V'
+      access        : 0x000a (PRIVATE STATIC)
+      code          -
+      registers     : 13
+      ins           : 11
+      outs          : 3
+      insns size    : 46 16-bit code units
+000f68:                                        |[000f68] invokecustom.InvokeCustom.targetMethodTest2:(ZBCSIFJDLjava/lang/String;)V
+000f78: 6200 0200                              |0000: sget-object v0, Ljava/lang/System;.out:Ljava/io/PrintStream; // field@0002
+000f7c: 6e20 2a00 2000                         |0002: invoke-virtual {v0, v2}, Ljava/io/PrintStream;.println:(Z)V // method@002a
+000f82: 6200 0200                              |0005: sget-object v0, Ljava/lang/System;.out:Ljava/io/PrintStream; // field@0002
+000f86: 6e20 2700 3000                         |0007: invoke-virtual {v0, v3}, Ljava/io/PrintStream;.println:(I)V // method@0027
+000f8c: 6200 0200                              |000a: sget-object v0, Ljava/lang/System;.out:Ljava/io/PrintStream; // field@0002
+000f90: 6e20 2400 4000                         |000c: invoke-virtual {v0, v4}, Ljava/io/PrintStream;.println:(C)V // method@0024
+000f96: 6200 0200                              |000f: sget-object v0, Ljava/lang/System;.out:Ljava/io/PrintStream; // field@0002
+000f9a: 6e20 2700 5000                         |0011: invoke-virtual {v0, v5}, Ljava/io/PrintStream;.println:(I)V // method@0027
+000fa0: 6200 0200                              |0014: sget-object v0, Ljava/lang/System;.out:Ljava/io/PrintStream; // field@0002
+000fa4: 6e20 2700 6000                         |0016: invoke-virtual {v0, v6}, Ljava/io/PrintStream;.println:(I)V // method@0027
+000faa: 6200 0200                              |0019: sget-object v0, Ljava/lang/System;.out:Ljava/io/PrintStream; // field@0002
+000fae: 6e20 2600 7000                         |001b: invoke-virtual {v0, v7}, Ljava/io/PrintStream;.println:(F)V // method@0026
+000fb4: 6200 0200                              |001e: sget-object v0, Ljava/lang/System;.out:Ljava/io/PrintStream; // field@0002
+000fb8: 6e30 2800 8009                         |0020: invoke-virtual {v0, v8, v9}, Ljava/io/PrintStream;.println:(J)V // method@0028
+000fbe: 6200 0200                              |0023: sget-object v0, Ljava/lang/System;.out:Ljava/io/PrintStream; // field@0002
+000fc2: 6e30 2500 a00b                         |0025: invoke-virtual {v0, v10, v11}, Ljava/io/PrintStream;.println:(D)V // method@0025
+000fc8: 6200 0200                              |0028: sget-object v0, Ljava/lang/System;.out:Ljava/io/PrintStream; // field@0002
+000fcc: 6e20 2900 c000                         |002a: invoke-virtual {v0, v12}, Ljava/io/PrintStream;.println:(Ljava/lang/String;)V // method@0029
+000fd2: 0e00                                   |002d: return-void
+      catches       : (none)
+      positions     : 
+        0x0000 line=50
+        0x0005 line=51
+        0x000a line=52
+        0x000f line=53
+        0x0014 line=54
+        0x0019 line=55
+        0x001e line=56
+        0x0023 line=57
+        0x0028 line=58
+        0x002d line=59
+      locals        : 
+        0x0000 - 0x002e reg=2 (null) Z 
+        0x0000 - 0x002e reg=3 (null) B 
+        0x0000 - 0x002e reg=4 (null) C 
+        0x0000 - 0x002e reg=5 (null) S 
+        0x0000 - 0x002e reg=6 (null) I 
+        0x0000 - 0x002e reg=7 (null) F 
+        0x0000 - 0x002e reg=8 (null) J 
+        0x0000 - 0x002e reg=10 (null) D 
+        0x0000 - 0x002e reg=12 (null) Ljava/lang/String; 
+
+    #14              : (in Linvokecustom/InvokeCustom;)
+      name          : 'targetMethodTest3'
+      type          : '()V'
+      access        : 0x000a (PRIVATE STATIC)
+      code          -
+      registers     : 2
+      ins           : 0
+      outs          : 2
+      insns size    : 8 16-bit code units
+000fd4:                                        |[000fd4] invokecustom.InvokeCustom.targetMethodTest3:()V
+000fe4: 6200 0200                              |0000: sget-object v0, Ljava/lang/System;.out:Ljava/io/PrintStream; // field@0002
+000fe8: 1a01 8800                              |0002: const-string v1, "targetMethodTest3 from InvokeCustom" // string@0088
+000fec: 6e20 2900 1000                         |0004: invoke-virtual {v0, v1}, Ljava/io/PrintStream;.println:(Ljava/lang/String;)V // method@0029
+000ff2: 0e00                                   |0007: return-void
+      catches       : (none)
+      positions     : 
+        0x0000 line=62
+        0x0007 line=63
+      locals        : 
+
+    #15              : (in Linvokecustom/InvokeCustom;)
+      name          : 'targetMethodTest5'
+      type          : '(III)I'
+      access        : 0x0009 (PUBLIC STATIC)
+      code          -
+      registers     : 7
+      ins           : 3
+      outs          : 2
+      insns size    : 83 16-bit code units
+000ff4:                                        |[000ff4] invokecustom.InvokeCustom.targetMethodTest5:(III)I
+001004: 9000 0405                              |0000: add-int v0, v4, v5
+001008: 6201 0200                              |0002: sget-object v1, Ljava/lang/System;.out:Ljava/io/PrintStream; // field@0002
+00100c: 2202 1000                              |0004: new-instance v2, Ljava/lang/StringBuilder; // type@0010
+001010: 7010 3000 0200                         |0006: invoke-direct {v2}, Ljava/lang/StringBuilder;.<init>:()V // method@0030
+001016: 1a03 8d00                              |0009: const-string v3, "targetMethodTest5 " // string@008d
+00101a: 6e20 3600 3200                         |000b: invoke-virtual {v2, v3}, Ljava/lang/StringBuilder;.append:(Ljava/lang/String;)Ljava/lang/StringBuilder; // method@0036
+001020: 0c02                                   |000e: move-result-object v2
+001022: 6e20 3300 4200                         |000f: invoke-virtual {v2, v4}, Ljava/lang/StringBuilder;.append:(I)Ljava/lang/StringBuilder; // method@0033
+001028: 0c02                                   |0012: move-result-object v2
+00102a: 1a03 0400                              |0013: const-string v3, " + " // string@0004
+00102e: 6e20 3600 3200                         |0015: invoke-virtual {v2, v3}, Ljava/lang/StringBuilder;.append:(Ljava/lang/String;)Ljava/lang/StringBuilder; // method@0036
+001034: 0c02                                   |0018: move-result-object v2
+001036: 6e20 3300 5200                         |0019: invoke-virtual {v2, v5}, Ljava/lang/StringBuilder;.append:(I)Ljava/lang/StringBuilder; // method@0033
+00103c: 0c02                                   |001c: move-result-object v2
+00103e: 1a03 0500                              |001d: const-string v3, " = " // string@0005
+001042: 6e20 3600 3200                         |001f: invoke-virtual {v2, v3}, Ljava/lang/StringBuilder;.append:(Ljava/lang/String;)Ljava/lang/StringBuilder; // method@0036
+001048: 0c02                                   |0022: move-result-object v2
+00104a: 6e20 3300 0200                         |0023: invoke-virtual {v2, v0}, Ljava/lang/StringBuilder;.append:(I)Ljava/lang/StringBuilder; // method@0033
+001050: 0c02                                   |0026: move-result-object v2
+001052: 6e10 3700 0200                         |0027: invoke-virtual {v2}, Ljava/lang/StringBuilder;.toString:()Ljava/lang/String; // method@0037
+001058: 0c02                                   |002a: move-result-object v2
+00105a: 6e20 2900 2100                         |002b: invoke-virtual {v1, v2}, Ljava/io/PrintStream;.println:(Ljava/lang/String;)V // method@0029
+001060: 3260 2400                              |002e: if-eq v0, v6, 0052 // +0024
+001064: 6201 0200                              |0030: sget-object v1, Ljava/lang/System;.out:Ljava/io/PrintStream; // field@0002
+001068: 2202 1000                              |0032: new-instance v2, Ljava/lang/StringBuilder; // type@0010
+00106c: 7010 3000 0200                         |0034: invoke-direct {v2}, Ljava/lang/StringBuilder;.<init>:()V // method@0030
+001072: 1a03 1400                              |0037: const-string v3, "Failed " // string@0014
+001076: 6e20 3600 3200                         |0039: invoke-virtual {v2, v3}, Ljava/lang/StringBuilder;.append:(Ljava/lang/String;)Ljava/lang/StringBuilder; // method@0036
+00107c: 0c02                                   |003c: move-result-object v2
+00107e: 6e20 3300 0200                         |003d: invoke-virtual {v2, v0}, Ljava/lang/StringBuilder;.append:(I)Ljava/lang/StringBuilder; // method@0033
+001084: 0c02                                   |0040: move-result-object v2
+001086: 1a03 0200                              |0041: const-string v3, " != " // string@0002
+00108a: 6e20 3600 3200                         |0043: invoke-virtual {v2, v3}, Ljava/lang/StringBuilder;.append:(Ljava/lang/String;)Ljava/lang/StringBuilder; // method@0036
+001090: 0c02                                   |0046: move-result-object v2
+001092: 6e20 3300 6200                         |0047: invoke-virtual {v2, v6}, Ljava/lang/StringBuilder;.append:(I)Ljava/lang/StringBuilder; // method@0033
+001098: 0c02                                   |004a: move-result-object v2
+00109a: 6e10 3700 0200                         |004b: invoke-virtual {v2}, Ljava/lang/StringBuilder;.toString:()Ljava/lang/String; // method@0037
+0010a0: 0c02                                   |004e: move-result-object v2
+0010a2: 6e20 2900 2100                         |004f: invoke-virtual {v1, v2}, Ljava/io/PrintStream;.println:(Ljava/lang/String;)V // method@0029
+0010a8: 0f00                                   |0052: return v0
+      catches       : (none)
+      positions     : 
+        0x0000 line=72
+        0x0002 line=73
+        0x002e line=74
+        0x0030 line=75
+        0x0052 line=77
+      locals        : 
+        0x0000 - 0x0053 reg=4 (null) I 
+        0x0000 - 0x0053 reg=5 (null) I 
+        0x0000 - 0x0053 reg=6 (null) I 
+
+    #16              : (in Linvokecustom/InvokeCustom;)
+      name          : 'targetMethodTest6'
+      type          : '(JJJ)J'
+      access        : 0x0009 (PUBLIC STATIC)
+      code          -
+      registers     : 12
+      ins           : 6
+      outs          : 3
+      insns size    : 85 16-bit code units
+0010ac:                                        |[0010ac] invokecustom.InvokeCustom.targetMethodTest6:(JJJ)J
+0010bc: 9b00 0608                              |0000: add-long v0, v6, v8
+0010c0: 6202 0200                              |0002: sget-object v2, Ljava/lang/System;.out:Ljava/io/PrintStream; // field@0002
+0010c4: 2203 1000                              |0004: new-instance v3, Ljava/lang/StringBuilder; // type@0010
+0010c8: 7010 3000 0300                         |0006: invoke-direct {v3}, Ljava/lang/StringBuilder;.<init>:()V // method@0030
+0010ce: 1a04 9000                              |0009: const-string v4, "targetMethodTest6 " // string@0090
+0010d2: 6e20 3600 4300                         |000b: invoke-virtual {v3, v4}, Ljava/lang/StringBuilder;.append:(Ljava/lang/String;)Ljava/lang/StringBuilder; // method@0036
+0010d8: 0c03                                   |000e: move-result-object v3
+0010da: 6e30 3400 6307                         |000f: invoke-virtual {v3, v6, v7}, Ljava/lang/StringBuilder;.append:(J)Ljava/lang/StringBuilder; // method@0034
+0010e0: 0c03                                   |0012: move-result-object v3
+0010e2: 1a04 0400                              |0013: const-string v4, " + " // string@0004
+0010e6: 6e20 3600 4300                         |0015: invoke-virtual {v3, v4}, Ljava/lang/StringBuilder;.append:(Ljava/lang/String;)Ljava/lang/StringBuilder; // method@0036
+0010ec: 0c03                                   |0018: move-result-object v3
+0010ee: 6e30 3400 8309                         |0019: invoke-virtual {v3, v8, v9}, Ljava/lang/StringBuilder;.append:(J)Ljava/lang/StringBuilder; // method@0034
+0010f4: 0c03                                   |001c: move-result-object v3
+0010f6: 1a04 0500                              |001d: const-string v4, " = " // string@0005
+0010fa: 6e20 3600 4300                         |001f: invoke-virtual {v3, v4}, Ljava/lang/StringBuilder;.append:(Ljava/lang/String;)Ljava/lang/StringBuilder; // method@0036
+001100: 0c03                                   |0022: move-result-object v3
+001102: 6e30 3400 0301                         |0023: invoke-virtual {v3, v0, v1}, Ljava/lang/StringBuilder;.append:(J)Ljava/lang/StringBuilder; // method@0034
+001108: 0c03                                   |0026: move-result-object v3
+00110a: 6e10 3700 0300                         |0027: invoke-virtual {v3}, Ljava/lang/StringBuilder;.toString:()Ljava/lang/String; // method@0037
+001110: 0c03                                   |002a: move-result-object v3
+001112: 6e20 2900 3200                         |002b: invoke-virtual {v2, v3}, Ljava/io/PrintStream;.println:(Ljava/lang/String;)V // method@0029
+001118: 3102 000a                              |002e: cmp-long v2, v0, v10
+00111c: 3802 2400                              |0030: if-eqz v2, 0054 // +0024
+001120: 6202 0200                              |0032: sget-object v2, Ljava/lang/System;.out:Ljava/io/PrintStream; // field@0002
+001124: 2203 1000                              |0034: new-instance v3, Ljava/lang/StringBuilder; // type@0010
+001128: 7010 3000 0300                         |0036: invoke-direct {v3}, Ljava/lang/StringBuilder;.<init>:()V // method@0030
+00112e: 1a04 1400                              |0039: const-string v4, "Failed " // string@0014
+001132: 6e20 3600 4300                         |003b: invoke-virtual {v3, v4}, Ljava/lang/StringBuilder;.append:(Ljava/lang/String;)Ljava/lang/StringBuilder; // method@0036
+001138: 0c03                                   |003e: move-result-object v3
+00113a: 6e30 3400 0301                         |003f: invoke-virtual {v3, v0, v1}, Ljava/lang/StringBuilder;.append:(J)Ljava/lang/StringBuilder; // method@0034
+001140: 0c03                                   |0042: move-result-object v3
+001142: 1a04 0200                              |0043: const-string v4, " != " // string@0002
+001146: 6e20 3600 4300                         |0045: invoke-virtual {v3, v4}, Ljava/lang/StringBuilder;.append:(Ljava/lang/String;)Ljava/lang/StringBuilder; // method@0036
+00114c: 0c03                                   |0048: move-result-object v3
+00114e: 6e30 3400 a30b                         |0049: invoke-virtual {v3, v10, v11}, Ljava/lang/StringBuilder;.append:(J)Ljava/lang/StringBuilder; // method@0034
+001154: 0c03                                   |004c: move-result-object v3
+001156: 6e10 3700 0300                         |004d: invoke-virtual {v3}, Ljava/lang/StringBuilder;.toString:()Ljava/lang/String; // method@0037
+00115c: 0c03                                   |0050: move-result-object v3
+00115e: 6e20 2900 3200                         |0051: invoke-virtual {v2, v3}, Ljava/io/PrintStream;.println:(Ljava/lang/String;)V // method@0029
+001164: 1000                                   |0054: return-wide v0
+      catches       : (none)
+      positions     : 
+        0x0000 line=81
+        0x0002 line=82
+        0x002e line=83
+        0x0032 line=84
+        0x0054 line=86
+      locals        : 
+        0x0000 - 0x0055 reg=6 (null) J 
+        0x0000 - 0x0055 reg=8 (null) J 
+        0x0000 - 0x0055 reg=10 (null) J 
+
+    #17              : (in Linvokecustom/InvokeCustom;)
+      name          : 'targetMethodTest7'
+      type          : '(FFD)D'
+      access        : 0x0009 (PUBLIC STATIC)
+      code          -
+      registers     : 10
+      ins           : 4
+      outs          : 3
+      insns size    : 86 16-bit code units
+001168:                                        |[001168] invokecustom.InvokeCustom.targetMethodTest7:(FFD)D
+001178: a800 0607                              |0000: mul-float v0, v6, v7
+00117c: 8900                                   |0002: float-to-double v0, v0
+00117e: 6202 0200                              |0003: sget-object v2, Ljava/lang/System;.out:Ljava/io/PrintStream; // field@0002
+001182: 2203 1000                              |0005: new-instance v3, Ljava/lang/StringBuilder; // type@0010
+001186: 7010 3000 0300                         |0007: invoke-direct {v3}, Ljava/lang/StringBuilder;.<init>:()V // method@0030
+00118c: 1a04 9300                              |000a: const-string v4, "targetMethodTest7 " // string@0093
+001190: 6e20 3600 4300                         |000c: invoke-virtual {v3, v4}, Ljava/lang/StringBuilder;.append:(Ljava/lang/String;)Ljava/lang/StringBuilder; // method@0036
+001196: 0c03                                   |000f: move-result-object v3
+001198: 6e20 3200 6300                         |0010: invoke-virtual {v3, v6}, Ljava/lang/StringBuilder;.append:(F)Ljava/lang/StringBuilder; // method@0032
+00119e: 0c03                                   |0013: move-result-object v3
+0011a0: 1a04 0300                              |0014: const-string v4, " * " // string@0003
+0011a4: 6e20 3600 4300                         |0016: invoke-virtual {v3, v4}, Ljava/lang/StringBuilder;.append:(Ljava/lang/String;)Ljava/lang/StringBuilder; // method@0036
+0011aa: 0c03                                   |0019: move-result-object v3
+0011ac: 6e20 3200 7300                         |001a: invoke-virtual {v3, v7}, Ljava/lang/StringBuilder;.append:(F)Ljava/lang/StringBuilder; // method@0032
+0011b2: 0c03                                   |001d: move-result-object v3
+0011b4: 1a04 0500                              |001e: const-string v4, " = " // string@0005
+0011b8: 6e20 3600 4300                         |0020: invoke-virtual {v3, v4}, Ljava/lang/StringBuilder;.append:(Ljava/lang/String;)Ljava/lang/StringBuilder; // method@0036
+0011be: 0c03                                   |0023: move-result-object v3
+0011c0: 6e30 3100 0301                         |0024: invoke-virtual {v3, v0, v1}, Ljava/lang/StringBuilder;.append:(D)Ljava/lang/StringBuilder; // method@0031
+0011c6: 0c03                                   |0027: move-result-object v3
+0011c8: 6e10 3700 0300                         |0028: invoke-virtual {v3}, Ljava/lang/StringBuilder;.toString:()Ljava/lang/String; // method@0037
+0011ce: 0c03                                   |002b: move-result-object v3
+0011d0: 6e20 2900 3200                         |002c: invoke-virtual {v2, v3}, Ljava/io/PrintStream;.println:(Ljava/lang/String;)V // method@0029
+0011d6: 2f02 0008                              |002f: cmpl-double v2, v0, v8
+0011da: 3802 2400                              |0031: if-eqz v2, 0055 // +0024
+0011de: 6202 0200                              |0033: sget-object v2, Ljava/lang/System;.out:Ljava/io/PrintStream; // field@0002
+0011e2: 2203 1000                              |0035: new-instance v3, Ljava/lang/StringBuilder; // type@0010
+0011e6: 7010 3000 0300                         |0037: invoke-direct {v3}, Ljava/lang/StringBuilder;.<init>:()V // method@0030
+0011ec: 1a04 1400                              |003a: const-string v4, "Failed " // string@0014
+0011f0: 6e20 3600 4300                         |003c: invoke-virtual {v3, v4}, Ljava/lang/StringBuilder;.append:(Ljava/lang/String;)Ljava/lang/StringBuilder; // method@0036
+0011f6: 0c03                                   |003f: move-result-object v3
+0011f8: 6e30 3100 0301                         |0040: invoke-virtual {v3, v0, v1}, Ljava/lang/StringBuilder;.append:(D)Ljava/lang/StringBuilder; // method@0031
+0011fe: 0c03                                   |0043: move-result-object v3
+001200: 1a04 0200                              |0044: const-string v4, " != " // string@0002
+001204: 6e20 3600 4300                         |0046: invoke-virtual {v3, v4}, Ljava/lang/StringBuilder;.append:(Ljava/lang/String;)Ljava/lang/StringBuilder; // method@0036
+00120a: 0c03                                   |0049: move-result-object v3
+00120c: 6e30 3100 8309                         |004a: invoke-virtual {v3, v8, v9}, Ljava/lang/StringBuilder;.append:(D)Ljava/lang/StringBuilder; // method@0031
+001212: 0c03                                   |004d: move-result-object v3
+001214: 6e10 3700 0300                         |004e: invoke-virtual {v3}, Ljava/lang/StringBuilder;.toString:()Ljava/lang/String; // method@0037
+00121a: 0c03                                   |0051: move-result-object v3
+00121c: 6e20 2900 3200                         |0052: invoke-virtual {v2, v3}, Ljava/io/PrintStream;.println:(Ljava/lang/String;)V // method@0029
+001222: 1000                                   |0055: return-wide v0
+      catches       : (none)
+      positions     : 
+        0x0000 line=90
+        0x0003 line=91
+        0x002f line=92
+        0x0033 line=93
+        0x0055 line=95
+      locals        : 
+        0x0000 - 0x0056 reg=6 (null) F 
+        0x0000 - 0x0056 reg=7 (null) F 
+        0x0000 - 0x0056 reg=8 (null) D 
+
+    #18              : (in Linvokecustom/InvokeCustom;)
+      name          : 'targetMethodTest8'
+      type          : '(Ljava/lang/String;)V'
+      access        : 0x0009 (PUBLIC STATIC)
+      code          -
+      registers     : 4
+      ins           : 1
+      outs          : 2
+      insns size    : 25 16-bit code units
+001224:                                        |[001224] invokecustom.InvokeCustom.targetMethodTest8:(Ljava/lang/String;)V
+001234: 6200 0200                              |0000: sget-object v0, Ljava/lang/System;.out:Ljava/io/PrintStream; // field@0002
+001238: 2201 1000                              |0002: new-instance v1, Ljava/lang/StringBuilder; // type@0010
+00123c: 7010 3000 0100                         |0004: invoke-direct {v1}, Ljava/lang/StringBuilder;.<init>:()V // method@0030
+001242: 1a02 9500                              |0007: const-string v2, "targetMethodTest8 " // string@0095
+001246: 6e20 3600 2100                         |0009: invoke-virtual {v1, v2}, Ljava/lang/StringBuilder;.append:(Ljava/lang/String;)Ljava/lang/StringBuilder; // method@0036
+00124c: 0c01                                   |000c: move-result-object v1
+00124e: 6e20 3600 3100                         |000d: invoke-virtual {v1, v3}, Ljava/lang/StringBuilder;.append:(Ljava/lang/String;)Ljava/lang/StringBuilder; // method@0036
+001254: 0c01                                   |0010: move-result-object v1
+001256: 6e10 3700 0100                         |0011: invoke-virtual {v1}, Ljava/lang/StringBuilder;.toString:()Ljava/lang/String; // method@0037
+00125c: 0c01                                   |0014: move-result-object v1
+00125e: 6e20 2900 1000                         |0015: invoke-virtual {v0, v1}, Ljava/io/PrintStream;.println:(Ljava/lang/String;)V // method@0029
+001264: 0e00                                   |0018: return-void
+      catches       : (none)
+      positions     : 
+        0x0000 line=99
+        0x0018 line=100
+      locals        : 
+        0x0000 - 0x0019 reg=3 (null) Ljava/lang/String; 
+
+    #19              : (in Linvokecustom/InvokeCustom;)
+      name          : 'targetMethodTest9'
+      type          : '()V'
+      access        : 0x000a (PRIVATE STATIC)
+      code          -
+      registers     : 2
+      ins           : 0
+      outs          : 2
+      insns size    : 8 16-bit code units
+001268:                                        |[001268] invokecustom.InvokeCustom.targetMethodTest9:()V
+001278: 6200 0200                              |0000: sget-object v0, Ljava/lang/System;.out:Ljava/io/PrintStream; // field@0002
+00127c: 1a01 9700                              |0002: const-string v1, "targetMethodTest9()" // string@0097
+001280: 6e20 2900 1000                         |0004: invoke-virtual {v0, v1}, Ljava/io/PrintStream;.println:(Ljava/lang/String;)V // method@0029
+001286: 0e00                                   |0007: return-void
+      catches       : (none)
+      positions     : 
+        0x0000 line=133
+        0x0007 line=134
+      locals        : 
+
+    #20              : (in Linvokecustom/InvokeCustom;)
+      name          : 'test1'
+      type          : '()V'
+      access        : 0x0009 (PUBLIC STATIC)
+      code          -
+      registers     : 0
+      ins           : 0
+      outs          : 0
+      insns size    : 4 16-bit code units
+001288:                                        |[001288] invokecustom.InvokeCustom.test1:()V
+001298: fc00 0300 0000                         |0000: invoke-custom {}, call_site@0003
+00129e: 0e00                                   |0003: return-void
+      catches       : (none)
+      positions     : 
+      locals        : 
+
+    #21              : (in Linvokecustom/InvokeCustom;)
+      name          : 'test2'
+      type          : '()V'
+      access        : 0x0009 (PUBLIC STATIC)
+      code          -
+      registers     : 11
+      ins           : 0
+      outs          : 11
+      insns size    : 27 16-bit code units
+0012a0:                                        |[0012a0] invokecustom.InvokeCustom.test2:()V
+0012b0: 1210                                   |0000: const/4 v0, #int 1 // #1
+0012b2: 1301 7f00                              |0001: const/16 v1, #int 127 // #7f
+0012b6: 1302 6300                              |0003: const/16 v2, #int 99 // #63
+0012ba: 1303 0004                              |0005: const/16 v3, #int 1024 // #400
+0012be: 1404 40e2 0100                         |0007: const v4, #float 1.72999e-40 // #0001e240
+0012c4: 1405 9a99 993f                         |000a: const v5, #float 1.2 // #3f99999a
+0012ca: 1706 15cd 5b07                         |000d: const-wide/32 v6, #float 1.6536e-34 // #075bcd15
+0012d0: 1808 b6fa f8b0 4819 0c40               |0010: const-wide v8, #double 3.51235 // #400c1948b0f8fab6
+0012da: 1a0a 4800                              |0015: const-string v10, "String" // string@0048
+0012de: fd0b 0400 0000                         |0017: invoke-custom/range {v0, v1, v2, v3, v4, v5, v6, v7, v8, v9, v10}, call_site@0004
+0012e4: 0e00                                   |001a: return-void
+      catches       : (none)
+      positions     : 
+      locals        : 
+
+    #22              : (in Linvokecustom/InvokeCustom;)
+      name          : 'test3'
+      type          : '()V'
+      access        : 0x0009 (PUBLIC STATIC)
+      code          -
+      registers     : 0
+      ins           : 0
+      outs          : 0
+      insns size    : 4 16-bit code units
+0012e8:                                        |[0012e8] invokecustom.InvokeCustom.test3:()V
+0012f8: fc00 0b00 0000                         |0000: invoke-custom {}, call_site@000b
+0012fe: 0e00                                   |0003: return-void
+      catches       : (none)
+      positions     : 
+      locals        : 
+
+    #23              : (in Linvokecustom/InvokeCustom;)
+      name          : 'test4'
+      type          : '()V'
+      access        : 0x0009 (PUBLIC STATIC)
+      code          -
+      registers     : 1
+      ins           : 0
+      outs          : 1
+      insns size    : 9 16-bit code units
+001300:                                        |[001300] invokecustom.InvokeCustom.test4:()V
+001310: 2200 0700                              |0000: new-instance v0, Linvokecustom/InvokeCustom; // type@0007
+001314: 7010 0100 0000                         |0002: invoke-direct {v0}, Linvokecustom/InvokeCustom;.<init>:()V // method@0001
+00131a: fc10 0c00 0000                         |0005: invoke-custom {v0}, call_site@000c
+001320: 0e00                                   |0008: return-void
+      catches       : (none)
+      positions     : 
+      locals        : 
+
+    #24              : (in Linvokecustom/InvokeCustom;)
+      name          : 'test5'
+      type          : '()V'
+      access        : 0x0009 (PUBLIC STATIC)
+      code          -
+      registers     : 4
+      ins           : 0
+      outs          : 3
+      insns size    : 35 16-bit code units
+001324:                                        |[001324] invokecustom.InvokeCustom.test5:()V
+001334: 1300 e803                              |0000: const/16 v0, #int 1000 // #3e8
+001338: 1301 65fc                              |0002: const/16 v1, #int -923 // #fc65
+00133c: 1302 4d00                              |0004: const/16 v2, #int 77 // #4d
+001340: fc30 0500 1002                         |0006: invoke-custom {v0, v1, v2}, call_site@0005
+001346: 0a00                                   |0009: move-result v0
+001348: 6201 0200                              |000a: sget-object v1, Ljava/lang/System;.out:Ljava/io/PrintStream; // field@0002
+00134c: 2202 1000                              |000c: new-instance v2, Ljava/lang/StringBuilder; // type@0010
+001350: 7010 3000 0200                         |000e: invoke-direct {v2}, Ljava/lang/StringBuilder;.<init>:()V // method@0030
+001356: 1a03 8e00                              |0011: const-string v3, "targetMethodTest5 returned: " // string@008e
+00135a: 6e20 3600 3200                         |0013: invoke-virtual {v2, v3}, Ljava/lang/StringBuilder;.append:(Ljava/lang/String;)Ljava/lang/StringBuilder; // method@0036
+001360: 0c02                                   |0016: move-result-object v2
+001362: 6e20 3300 0200                         |0017: invoke-virtual {v2, v0}, Ljava/lang/StringBuilder;.append:(I)Ljava/lang/StringBuilder; // method@0033
+001368: 0c00                                   |001a: move-result-object v0
+00136a: 6e10 3700 0000                         |001b: invoke-virtual {v0}, Ljava/lang/StringBuilder;.toString:()Ljava/lang/String; // method@0037
+001370: 0c00                                   |001e: move-result-object v0
+001372: 6e20 2900 0100                         |001f: invoke-virtual {v1, v0}, Ljava/io/PrintStream;.println:(Ljava/lang/String;)V // method@0029
+001378: 0e00                                   |0022: return-void
+      catches       : (none)
+      positions     : 
+      locals        : 
+
+    #25              : (in Linvokecustom/InvokeCustom;)
+      name          : 'test6'
+      type          : '()V'
+      access        : 0x0009 (PUBLIC STATIC)
+      code          -
+      registers     : 6
+      ins           : 0
+      outs          : 6
+      insns size    : 44 16-bit code units
+00137c:                                        |[00137c] invokecustom.InvokeCustom.test6:()V
+00138c: 1800 7777 7777 7707 0000               |0000: const-wide v0, #double 4.05612e-311 // #0000077777777777
+001396: 1802 efee eeee eefe ffff               |0005: const-wide v2, #double -nan // #fffffeeeeeeeeeef
+0013a0: 1804 6666 6666 6606 0000               |000a: const-wide v4, #double 3.47668e-311 // #0000066666666666
+0013aa: fd06 0600 0000                         |000f: invoke-custom/range {v0, v1, v2, v3, v4, v5}, call_site@0006
+0013b0: 0b00                                   |0012: move-result-wide v0
+0013b2: 6202 0200                              |0013: sget-object v2, Ljava/lang/System;.out:Ljava/io/PrintStream; // field@0002
+0013b6: 2203 1000                              |0015: new-instance v3, Ljava/lang/StringBuilder; // type@0010
+0013ba: 7010 3000 0300                         |0017: invoke-direct {v3}, Ljava/lang/StringBuilder;.<init>:()V // method@0030
+0013c0: 1a04 9100                              |001a: const-string v4, "targetMethodTest6 returned: " // string@0091
+0013c4: 6e20 3600 4300                         |001c: invoke-virtual {v3, v4}, Ljava/lang/StringBuilder;.append:(Ljava/lang/String;)Ljava/lang/StringBuilder; // method@0036
+0013ca: 0c03                                   |001f: move-result-object v3
+0013cc: 6e30 3400 0301                         |0020: invoke-virtual {v3, v0, v1}, Ljava/lang/StringBuilder;.append:(J)Ljava/lang/StringBuilder; // method@0034
+0013d2: 0c00                                   |0023: move-result-object v0
+0013d4: 6e10 3700 0000                         |0024: invoke-virtual {v0}, Ljava/lang/StringBuilder;.toString:()Ljava/lang/String; // method@0037
+0013da: 0c00                                   |0027: move-result-object v0
+0013dc: 6e20 2900 0200                         |0028: invoke-virtual {v2, v0}, Ljava/io/PrintStream;.println:(Ljava/lang/String;)V // method@0029
+0013e2: 0e00                                   |002b: return-void
+      catches       : (none)
+      positions     : 
+      locals        : 
+
+    #26              : (in Linvokecustom/InvokeCustom;)
+      name          : 'test7'
+      type          : '()V'
+      access        : 0x0009 (PUBLIC STATIC)
+      code          -
+      registers     : 5
+      ins           : 0
+      outs          : 4
+      insns size    : 40 16-bit code units
+0013e4:                                        |[0013e4] invokecustom.InvokeCustom.test7:()V
+0013f4: 1400 0040 003f                         |0000: const v0, #float 0.500977 // #3f004000
+0013fa: 1401 0040 00bf                         |0003: const v1, #float -0.500977 // #bf004000
+001400: 1802 0000 0000 0410 d0bf               |0006: const-wide v2, #double -0.250978 // #bfd0100400000000
+00140a: fc40 0700 1032                         |000b: invoke-custom {v0, v1, v2, v3}, call_site@0007
+001410: 0b00                                   |000e: move-result-wide v0
+001412: 6202 0200                              |000f: sget-object v2, Ljava/lang/System;.out:Ljava/io/PrintStream; // field@0002
+001416: 2203 1000                              |0011: new-instance v3, Ljava/lang/StringBuilder; // type@0010
+00141a: 7010 3000 0300                         |0013: invoke-direct {v3}, Ljava/lang/StringBuilder;.<init>:()V // method@0030
+001420: 1a04 9100                              |0016: const-string v4, "targetMethodTest6 returned: " // string@0091
+001424: 6e20 3600 4300                         |0018: invoke-virtual {v3, v4}, Ljava/lang/StringBuilder;.append:(Ljava/lang/String;)Ljava/lang/StringBuilder; // method@0036
+00142a: 0c03                                   |001b: move-result-object v3
+00142c: 6e30 3100 0301                         |001c: invoke-virtual {v3, v0, v1}, Ljava/lang/StringBuilder;.append:(D)Ljava/lang/StringBuilder; // method@0031
+001432: 0c00                                   |001f: move-result-object v0
+001434: 6e10 3700 0000                         |0020: invoke-virtual {v0}, Ljava/lang/StringBuilder;.toString:()Ljava/lang/String; // method@0037
+00143a: 0c00                                   |0023: move-result-object v0
+00143c: 6e20 2900 0200                         |0024: invoke-virtual {v2, v0}, Ljava/io/PrintStream;.println:(Ljava/lang/String;)V // method@0029
+001442: 0e00                                   |0027: return-void
+      catches       : (none)
+      positions     : 
+      locals        : 
+
+    #27              : (in Linvokecustom/InvokeCustom;)
+      name          : 'test8'
+      type          : '()V'
+      access        : 0x0009 (PUBLIC STATIC)
+      code          -
+      registers     : 1
+      ins           : 0
+      outs          : 1
+      insns size    : 16 16-bit code units
+001444:                                        |[001444] invokecustom.InvokeCustom.test8:()V
+001454: 1a00 1500                              |0000: const-string v0, "First invokedynamic invocation" // string@0015
+001458: fc10 0800 0000                         |0002: invoke-custom {v0}, call_site@0008
+00145e: 1a00 4700                              |0005: const-string v0, "Second invokedynamic invocation" // string@0047
+001462: fc10 0900 0000                         |0007: invoke-custom {v0}, call_site@0009
+001468: 1a00 1000                              |000a: const-string v0, "Dupe first invokedynamic invocation" // string@0010
+00146c: fc10 0a00 0000                         |000c: invoke-custom {v0}, call_site@000a
+001472: 0e00                                   |000f: return-void
+      catches       : (none)
+      positions     : 
+      locals        : 
+
+    #28              : (in Linvokecustom/InvokeCustom;)
+      name          : 'test9'
+      type          : '()V'
+      access        : 0x0009 (PUBLIC STATIC)
+      code          -
+      registers     : 0
+      ins           : 0
+      outs          : 0
+      insns size    : 4 16-bit code units
+001474:                                        |[001474] invokecustom.InvokeCustom.test9:()V
+001484: fc00 0d00 0000                         |0000: invoke-custom {}, call_site@000d
+00148a: 0e00                                   |0003: return-void
+      catches       : (none)
+      positions     : 
+      locals        : 
+
+  Virtual methods   -
+    #0              : (in Linvokecustom/InvokeCustom;)
+      name          : 'helperMethodTest9'
+      type          : '()V'
+      access        : 0x0001 (PUBLIC)
+      code          -
+      registers     : 4
+      ins           : 1
+      outs          : 2
+      insns size    : 27 16-bit code units
+00148c:                                        |[00148c] invokecustom.InvokeCustom.helperMethodTest9:()V
+00149c: 6200 0200                              |0000: sget-object v0, Ljava/lang/System;.out:Ljava/io/PrintStream; // field@0002
+0014a0: 2201 1000                              |0002: new-instance v1, Ljava/lang/StringBuilder; // type@0010
+0014a4: 7010 3000 0100                         |0004: invoke-direct {v1}, Ljava/lang/StringBuilder;.<init>:()V // method@0030
+0014aa: 1a02 7300                              |0007: const-string v2, "helperMethodTest9 in " // string@0073
+0014ae: 6e20 3600 2100                         |0009: invoke-virtual {v1, v2}, Ljava/lang/StringBuilder;.append:(Ljava/lang/String;)Ljava/lang/StringBuilder; // method@0036
+0014b4: 0c01                                   |000c: move-result-object v1
+0014b6: 1c02 0700                              |000d: const-class v2, Linvokecustom/InvokeCustom; // type@0007
+0014ba: 6e20 3500 2100                         |000f: invoke-virtual {v1, v2}, Ljava/lang/StringBuilder;.append:(Ljava/lang/Object;)Ljava/lang/StringBuilder; // method@0035
+0014c0: 0c01                                   |0012: move-result-object v1
+0014c2: 6e10 3700 0100                         |0013: invoke-virtual {v1}, Ljava/lang/StringBuilder;.toString:()Ljava/lang/String; // method@0037
+0014c8: 0c01                                   |0016: move-result-object v1
+0014ca: 6e20 2900 1000                         |0017: invoke-virtual {v0, v1}, Ljava/io/PrintStream;.println:(Ljava/lang/String;)V // method@0029
+0014d0: 0e00                                   |001a: return-void
+      catches       : (none)
+      positions     : 
+        0x0000 line=129
+        0x001a line=130
+      locals        : 
+        0x0000 - 0x001b reg=3 this Linvokecustom/InvokeCustom; 
+
+    #1              : (in Linvokecustom/InvokeCustom;)
+      name          : 'run'
+      type          : '()V'
+      access        : 0x0001 (PUBLIC)
+      code          -
+      registers     : 3
+      ins           : 1
+      outs          : 2
+      insns size    : 8 16-bit code units
+0014d4:                                        |[0014d4] invokecustom.InvokeCustom.run:()V
+0014e4: 6200 0200                              |0000: sget-object v0, Ljava/lang/System;.out:Ljava/io/PrintStream; // field@0002
+0014e8: 1a01 8200                              |0002: const-string v1, "run() for Test9" // string@0082
+0014ec: 6e20 2900 1000                         |0004: invoke-virtual {v0, v1}, Ljava/io/PrintStream;.println:(Ljava/lang/String;)V // method@0029
+0014f2: 0e00                                   |0007: return-void
+      catches       : (none)
+      positions     : 
+        0x0000 line=137
+        0x0007 line=138
+      locals        : 
+        0x0000 - 0x0008 reg=2 this Linvokecustom/InvokeCustom; 
+
+    #2              : (in Linvokecustom/InvokeCustom;)
+      name          : 'targetMethodTest4'
+      type          : '()V'
+      access        : 0x0001 (PUBLIC)
+      code          -
+      registers     : 3
+      ins           : 1
+      outs          : 2
+      insns size    : 8 16-bit code units
+0014f4:                                        |[0014f4] invokecustom.InvokeCustom.targetMethodTest4:()V
+001504: 6200 0200                              |0000: sget-object v0, Ljava/lang/System;.out:Ljava/io/PrintStream; // field@0002
+001508: 1a01 8a00                              |0002: const-string v1, "targetMethodTest4 from InvokeCustom (oops!)" // string@008a
+00150c: 6e20 2900 1000                         |0004: invoke-virtual {v0, v1}, Ljava/io/PrintStream;.println:(Ljava/lang/String;)V // method@0029
+001512: 0e00                                   |0007: return-void
+      catches       : (none)
+      positions     : 
+        0x0000 line=68
+        0x0007 line=69
+      locals        : 
+        0x0000 - 0x0008 reg=2 this Linvokecustom/InvokeCustom; 
+
+  source_file_idx   : 27 (InvokeCustom.java)
 
 Method handle #0:
+  type        : put-static
+  target      : Linvokecustom/InvokeCustom; staticFieldTest9
+  target_type : I
+Method handle #1:
+  type        : get-static
+  target      : Linvokecustom/InvokeCustom; staticFieldTest9
+  target_type : I
+Method handle #2:
+  type        : put-instance
+  target      : Linvokecustom/InvokeCustom; fieldTest9
+  target_type : (Linvokecustom/InvokeCustom;
+Method handle #3:
+  type        : get-instance
+  target      : Linvokecustom/InvokeCustom; fieldTest9
+  target_type : (Linvokecustom/InvokeCustom;
+Method handle #4:
   type        : invoke-static
-  target      : Lcom/android/jack/java7/invokecustom/test004/Tests; linkerMethod
-  target_type : (Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/invoke/MethodType;ZBCSIFDLjava/lang/String;Ljava/lang/Class;J)Ljava/lang/invoke/CallSite;
-Call site #0:
-  link_argument[0] : 0 (MethodHandle)
-  link_argument[1] : add (String)
-  link_argument[2] : (II)I (MethodType)
+  target      : Linvokecustom/InvokeCustom; bsmCreateCallSite
+  target_type : (Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/invoke/MethodType;Ljava/lang/invoke/MethodHandle;)Ljava/lang/invoke/CallSite;
+Method handle #5:
+  type        : invoke-static
+  target      : Linvokecustom/InvokeCustom; bsmLookupStatic
+  target_type : (Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/invoke/MethodType;)Ljava/lang/invoke/CallSite;
+Method handle #6:
+  type        : invoke-static
+  target      : Linvokecustom/InvokeCustom; bsmLookupStaticWithExtraArgs
+  target_type : (Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/invoke/MethodType;IJFD)Ljava/lang/invoke/CallSite;
+Method handle #7:
+  type        : invoke-static
+  target      : Linvokecustom/InvokeCustom; bsmLookupTest9
+  target_type : (Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/invoke/MethodType;Ljava/lang/invoke/MethodHandle;Ljava/lang/invoke/MethodHandle;Ljava/lang/invoke/MethodHandle;Ljava/lang/invoke/MethodHandle;Ljava/lang/invoke/MethodHandle;Ljava/lang/invoke/MethodHandle;Ljava/lang/invoke/MethodHandle;)Ljava/lang/invoke/CallSite;
+Method handle #8:
+  type        : invoke-static
+  target      : Linvokecustom/InvokeCustom; lambda$lambdaTest$0
+  target_type : (Ljava/lang/String;)Z
+Method handle #9:
+  type        : invoke-static
+  target      : Ljava/lang/invoke/LambdaMetafactory; metafactory
+  target_type : (Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/invoke/MethodType;Ljava/lang/invoke/MethodType;Ljava/lang/invoke/MethodHandle;Ljava/lang/invoke/MethodType;)Ljava/lang/invoke/CallSite;
+Method handle #10:
+  type        : invoke-instance
+  target      : Linvokecustom/InvokeCustom; helperMethodTest9
+  target_type : (Linvokecustom/InvokeCustom;)V
+Method handle #11:
+  type        : invoke-instance
+  target      : Ljava/io/PrintStream; println
+  target_type : (Ljava/io/PrintStream;Ljava/lang/String;)V
+Method handle #12:
+  type        : invoke-instance
+  target      : Ljava/lang/String; trim
+  target_type : (Ljava/lang/String;)Ljava/lang/String;
+Method handle #13:
+  type        : invoke-constructor
+  target      : Linvokecustom/InvokeCustom; <init>
+  target_type : (Linvokecustom/InvokeCustom;I)V
+Method handle #14:
+  type        : invoke-direct
+  target      : Linvokecustom/Super; targetMethodTest4
+  target_type : (Linvokecustom/Super;)V
+Method handle #15:
+  type        : invoke-interface
+  target      : Ljava/lang/Runnable; run
+  target_type : (Ljava/lang/Runnable;)V
+Call site #0: // offset 8450
+  link_argument[0] : 9 (MethodHandle)
+  link_argument[1] : test (String)
+  link_argument[2] : ()Ljava/util/function/Predicate; (MethodType)
+  link_argument[3] : (Ljava/lang/Object;)Z (MethodType)
+  link_argument[4] : 8 (MethodHandle)
+  link_argument[5] : (Ljava/lang/String;)Z (MethodType)
+Call site #1: // offset 8463
+  link_argument[0] : 9 (MethodHandle)
+  link_argument[1] : apply (String)
+  link_argument[2] : ()Ljava/util/function/Function; (MethodType)
+  link_argument[3] : (Ljava/lang/Object;)Ljava/lang/Object; (MethodType)
+  link_argument[4] : 12 (MethodHandle)
+  link_argument[5] : (Ljava/lang/String;)Ljava/lang/String; (MethodType)
+Call site #2: // offset 8476
+  link_argument[0] : 9 (MethodHandle)
+  link_argument[1] : accept (String)
+  link_argument[2] : (Ljava/io/PrintStream;)Ljava/util/function/Consumer; (MethodType)
+  link_argument[3] : (Ljava/lang/Object;)V (MethodType)
+  link_argument[4] : 11 (MethodHandle)
+  link_argument[5] : (Ljava/lang/String;)V (MethodType)
+Call site #3: // offset 8489
+  link_argument[0] : 5 (MethodHandle)
+  link_argument[1] : targetMethodTest1 (String)
+  link_argument[2] : ()V (MethodType)
+Call site #4: // offset 8496
+  link_argument[0] : 5 (MethodHandle)
+  link_argument[1] : targetMethodTest2 (String)
+  link_argument[2] : (ZBCSIFJDLjava/lang/String;)V (MethodType)
+Call site #5: // offset 8503
+  link_argument[0] : 5 (MethodHandle)
+  link_argument[1] : targetMethodTest5 (String)
+  link_argument[2] : (III)I (MethodType)
+Call site #6: // offset 8510
+  link_argument[0] : 5 (MethodHandle)
+  link_argument[1] : targetMethodTest6 (String)
+  link_argument[2] : (JJJ)J (MethodType)
+Call site #7: // offset 8517
+  link_argument[0] : 5 (MethodHandle)
+  link_argument[1] : targetMethodTest7 (String)
+  link_argument[2] : (FFD)D (MethodType)
+Call site #8: // offset 8524
+  link_argument[0] : 5 (MethodHandle)
+  link_argument[1] : targetMethodTest8 (String)
+  link_argument[2] : (Ljava/lang/String;)V (MethodType)
+Call site #9: // offset 8524
+  link_argument[0] : 5 (MethodHandle)
+  link_argument[1] : targetMethodTest8 (String)
+  link_argument[2] : (Ljava/lang/String;)V (MethodType)
+Call site #10: // offset 8524
+  link_argument[0] : 5 (MethodHandle)
+  link_argument[1] : targetMethodTest8 (String)
+  link_argument[2] : (Ljava/lang/String;)V (MethodType)
+Call site #11: // offset 8531
+  link_argument[0] : 6 (MethodHandle)
+  link_argument[1] : targetMethodTest3 (String)
+  link_argument[2] : ()V (MethodType)
   link_argument[3] : 1 (int)
-  link_argument[4] : 1 (int)
-  link_argument[5] : 97 (int)
-  link_argument[6] : 1024 (int)
-  link_argument[7] : 1 (int)
-  link_argument[8] : 11.1 (float)
-  link_argument[9] : 2.2 (double)
-  link_argument[10] : Hello (String)
-  link_argument[11] : Tests (Class)
-  link_argument[12] : 123456789 (long)
-Call site #1:
-  link_argument[0] : 0 (MethodHandle)
-  link_argument[1] : add (String)
-  link_argument[2] : (II)I (MethodType)
-  link_argument[3] : 1 (int)
-  link_argument[4] : 1 (int)
-  link_argument[5] : 97 (int)
-  link_argument[6] : 1024 (int)
-  link_argument[7] : 1 (int)
-  link_argument[8] : 11.1 (float)
-  link_argument[9] : 2.2 (double)
-  link_argument[10] : Hello (String)
-  link_argument[11] : Tests (Class)
-  link_argument[12] : 123456789 (long)
+  link_argument[4] : 123456789 (long)
+  link_argument[5] : 123.456 (float)
+  link_argument[6] : 123457 (double)
+Call site #12: // offset 8559
+  link_argument[0] : 4 (MethodHandle)
+  link_argument[1] : targetMethodTest4 (String)
+  link_argument[2] : (Linvokecustom/InvokeCustom;)V (MethodType)
+  link_argument[3] : 14 (MethodHandle)
+Call site #13: // offset 8568
+  link_argument[0] : 7 (MethodHandle)
+  link_argument[1] : targetMethodTest9 (String)
+  link_argument[2] : ()V (MethodType)
+  link_argument[3] : 1 (MethodHandle)
+  link_argument[4] : 0 (MethodHandle)
+  link_argument[5] : 3 (MethodHandle)
+  link_argument[6] : 2 (MethodHandle)
+  link_argument[7] : 10 (MethodHandle)
+  link_argument[8] : 13 (MethodHandle)
+  link_argument[9] : 15 (MethodHandle)
diff --git a/test/dexdump/invoke-custom.xml b/test/dexdump/invoke-custom.xml
index 2a29667..8b22a9d 100644
--- a/test/dexdump/invoke-custom.xml
+++ b/test/dexdump/invoke-custom.xml
@@ -1,30 +1,130 @@
 <api>
-<package name="com.android.jack.java7.invokecustom.test004"
+<package name="invokecustom"
 >
-<class name="Tests"
- extends="java.lang.Object"
+<class name="InvokeCustom"
+ extends="invokecustom.Super"
  interface="false"
  abstract="false"
  static="false"
  final="false"
  visibility="public"
 >
-<field name="fieldCallSite"
- type="java.lang.invoke.CallSite"
- transient="false"
- volatile="false"
- static="true"
- final="false"
- visibility="public"
->
-</field>
-<constructor name="Tests"
- type="com.android.jack.java7.invokecustom.test004.Tests"
+<implements name="java.lang.Runnable">
+</implements>
+<constructor name="InvokeCustom"
+ type="invokecustom.InvokeCustom"
  static="false"
  final="false"
  visibility="public"
 >
 </constructor>
+<constructor name="InvokeCustom"
+ type="invokecustom.InvokeCustom"
+ static="false"
+ final="false"
+ visibility="public"
+>
+<parameter name="arg0" type="int">
+</parameter>
+</constructor>
+<method name="bsmCreateCallSite"
+ return="java.lang.invoke.CallSite"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="true"
+ final="false"
+ visibility="public"
+>
+<parameter name="arg0" type="java.lang.invoke.MethodHandles.Lookup">
+</parameter>
+<parameter name="arg1" type="java.lang.String">
+</parameter>
+<parameter name="arg2" type="java.lang.invoke.MethodType">
+</parameter>
+<parameter name="arg3" type="java.lang.invoke.MethodHandle">
+</parameter>
+</method>
+<method name="bsmLookupStatic"
+ return="java.lang.invoke.CallSite"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="true"
+ final="false"
+ visibility="public"
+>
+<parameter name="arg0" type="java.lang.invoke.MethodHandles.Lookup">
+</parameter>
+<parameter name="arg1" type="java.lang.String">
+</parameter>
+<parameter name="arg2" type="java.lang.invoke.MethodType">
+</parameter>
+</method>
+<method name="bsmLookupStaticWithExtraArgs"
+ return="java.lang.invoke.CallSite"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="true"
+ final="false"
+ visibility="public"
+>
+<parameter name="arg0" type="java.lang.invoke.MethodHandles.Lookup">
+</parameter>
+<parameter name="arg1" type="java.lang.String">
+</parameter>
+<parameter name="arg2" type="java.lang.invoke.MethodType">
+</parameter>
+<parameter name="arg3" type="int">
+</parameter>
+<parameter name="arg4" type="long">
+</parameter>
+<parameter name="arg5" type="float">
+</parameter>
+<parameter name="arg6" type="double">
+</parameter>
+</method>
+<method name="bsmLookupTest9"
+ return="java.lang.invoke.CallSite"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="true"
+ final="false"
+ visibility="public"
+>
+<parameter name="arg0" type="java.lang.invoke.MethodHandles.Lookup">
+</parameter>
+<parameter name="arg1" type="java.lang.String">
+</parameter>
+<parameter name="arg2" type="java.lang.invoke.MethodType">
+</parameter>
+<parameter name="arg3" type="java.lang.invoke.MethodHandle">
+</parameter>
+<parameter name="arg4" type="java.lang.invoke.MethodHandle">
+</parameter>
+<parameter name="arg5" type="java.lang.invoke.MethodHandle">
+</parameter>
+<parameter name="arg6" type="java.lang.invoke.MethodHandle">
+</parameter>
+<parameter name="arg7" type="java.lang.invoke.MethodHandle">
+</parameter>
+<parameter name="arg8" type="java.lang.invoke.MethodHandle">
+</parameter>
+<parameter name="arg9" type="java.lang.invoke.MethodHandle">
+</parameter>
+</method>
+<method name="lambdaTest"
+ return="void"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="true"
+ final="false"
+ visibility="public"
+>
+</method>
 <method name="main"
  return="void"
  abstract="false"
@@ -37,7 +137,177 @@
 <parameter name="arg0" type="java.lang.String[]">
 </parameter>
 </method>
-<method name="test"
+<method name="targetMethodTest5"
+ return="int"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="true"
+ final="false"
+ visibility="public"
+>
+<parameter name="arg0" type="int">
+</parameter>
+<parameter name="arg1" type="int">
+</parameter>
+<parameter name="arg2" type="int">
+</parameter>
+</method>
+<method name="targetMethodTest6"
+ return="long"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="true"
+ final="false"
+ visibility="public"
+>
+<parameter name="arg0" type="long">
+</parameter>
+<parameter name="arg1" type="long">
+</parameter>
+<parameter name="arg2" type="long">
+</parameter>
+</method>
+<method name="targetMethodTest7"
+ return="double"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="true"
+ final="false"
+ visibility="public"
+>
+<parameter name="arg0" type="float">
+</parameter>
+<parameter name="arg1" type="float">
+</parameter>
+<parameter name="arg2" type="double">
+</parameter>
+</method>
+<method name="targetMethodTest8"
+ return="void"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="true"
+ final="false"
+ visibility="public"
+>
+<parameter name="arg0" type="java.lang.String">
+</parameter>
+</method>
+<method name="test1"
+ return="void"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="true"
+ final="false"
+ visibility="public"
+>
+</method>
+<method name="test2"
+ return="void"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="true"
+ final="false"
+ visibility="public"
+>
+</method>
+<method name="test3"
+ return="void"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="true"
+ final="false"
+ visibility="public"
+>
+</method>
+<method name="test4"
+ return="void"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="true"
+ final="false"
+ visibility="public"
+>
+</method>
+<method name="test5"
+ return="void"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="true"
+ final="false"
+ visibility="public"
+>
+</method>
+<method name="test6"
+ return="void"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="true"
+ final="false"
+ visibility="public"
+>
+</method>
+<method name="test7"
+ return="void"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="true"
+ final="false"
+ visibility="public"
+>
+</method>
+<method name="test8"
+ return="void"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="true"
+ final="false"
+ visibility="public"
+>
+</method>
+<method name="test9"
+ return="void"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="true"
+ final="false"
+ visibility="public"
+>
+</method>
+<method name="helperMethodTest9"
+ return="void"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ visibility="public"
+>
+</method>
+<method name="run"
+ return="void"
+ abstract="false"
+ native="false"
+ synchronized="false"
+ static="false"
+ final="false"
+ visibility="public"
+>
+</method>
+<method name="targetMethodTest4"
  return="void"
  abstract="false"
  native="false"
@@ -49,41 +319,207 @@
 </method>
 </class>
 <method_handle index="0"
- type="invoke-static"
- target_class="Lcom/android/jack/java7/invokecustom/test004/Tests;"
- target_member="linkerMethod"
- target_member_type="(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/invoke/MethodType;ZBCSIFDLjava/lang/String;Ljava/lang/Class;J)Ljava/lang/invoke/CallSite;"
+ type="put-static"
+ target_class="Linvokecustom/InvokeCustom;"
+ target_member="staticFieldTest9"
+ target_member_type="I"
 >
 </method_handle>
-<call_site index="0">
-<link_argument index="0" type="MethodHandle" value="0"/>
-<link_argument index="1" type="String" values="add"/>
-<link_argument index="2" type="MethodType" value="(II)I"/>
-<link_argument index="3" type="int" value="1"/>
-<link_argument index="4" type="int" value="1"/>
-<link_argument index="5" type="int" value="97"/>
-<link_argument index="6" type="int" value="1024"/>
-<link_argument index="7" type="int" value="1"/>
-<link_argument index="8" type="float" value="11.1"/>
-<link_argument index="9" type="double" value="2.2"/>
-<link_argument index="10" type="String" value="Hello"/>
-<link_argument index="11" type="Class" value="Tests"/>
-<link_argument index="12" type="long" value="123456789"/>
+<method_handle index="1"
+ type="get-static"
+ target_class="Linvokecustom/InvokeCustom;"
+ target_member="staticFieldTest9"
+ target_member_type="I"
+>
+</method_handle>
+<method_handle index="2"
+ type="put-instance"
+ target_class="Linvokecustom/InvokeCustom;"
+ target_member="fieldTest9"
+ target_member_type="(Linvokecustom/InvokeCustom;"
+>
+</method_handle>
+<method_handle index="3"
+ type="get-instance"
+ target_class="Linvokecustom/InvokeCustom;"
+ target_member="fieldTest9"
+ target_member_type="(Linvokecustom/InvokeCustom;"
+>
+</method_handle>
+<method_handle index="4"
+ type="invoke-static"
+ target_class="Linvokecustom/InvokeCustom;"
+ target_member="bsmCreateCallSite"
+ target_member_type="(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/invoke/MethodType;Ljava/lang/invoke/MethodHandle;)Ljava/lang/invoke/CallSite;"
+>
+</method_handle>
+<method_handle index="5"
+ type="invoke-static"
+ target_class="Linvokecustom/InvokeCustom;"
+ target_member="bsmLookupStatic"
+ target_member_type="(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/invoke/MethodType;)Ljava/lang/invoke/CallSite;"
+>
+</method_handle>
+<method_handle index="6"
+ type="invoke-static"
+ target_class="Linvokecustom/InvokeCustom;"
+ target_member="bsmLookupStaticWithExtraArgs"
+ target_member_type="(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/invoke/MethodType;IJFD)Ljava/lang/invoke/CallSite;"
+>
+</method_handle>
+<method_handle index="7"
+ type="invoke-static"
+ target_class="Linvokecustom/InvokeCustom;"
+ target_member="bsmLookupTest9"
+ target_member_type="(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/invoke/MethodType;Ljava/lang/invoke/MethodHandle;Ljava/lang/invoke/MethodHandle;Ljava/lang/invoke/MethodHandle;Ljava/lang/invoke/MethodHandle;Ljava/lang/invoke/MethodHandle;Ljava/lang/invoke/MethodHandle;Ljava/lang/invoke/MethodHandle;)Ljava/lang/invoke/CallSite;"
+>
+</method_handle>
+<method_handle index="8"
+ type="invoke-static"
+ target_class="Linvokecustom/InvokeCustom;"
+ target_member="lambda$lambdaTest$0"
+ target_member_type="(Ljava/lang/String;)Z"
+>
+</method_handle>
+<method_handle index="9"
+ type="invoke-static"
+ target_class="Ljava/lang/invoke/LambdaMetafactory;"
+ target_member="metafactory"
+ target_member_type="(Ljava/lang/invoke/MethodHandles$Lookup;Ljava/lang/String;Ljava/lang/invoke/MethodType;Ljava/lang/invoke/MethodType;Ljava/lang/invoke/MethodHandle;Ljava/lang/invoke/MethodType;)Ljava/lang/invoke/CallSite;"
+>
+</method_handle>
+<method_handle index="10"
+ type="invoke-instance"
+ target_class="Linvokecustom/InvokeCustom;"
+ target_member="helperMethodTest9"
+ target_member_type="(Linvokecustom/InvokeCustom;)V"
+>
+</method_handle>
+<method_handle index="11"
+ type="invoke-instance"
+ target_class="Ljava/io/PrintStream;"
+ target_member="println"
+ target_member_type="(Ljava/io/PrintStream;Ljava/lang/String;)V"
+>
+</method_handle>
+<method_handle index="12"
+ type="invoke-instance"
+ target_class="Ljava/lang/String;"
+ target_member="trim"
+ target_member_type="(Ljava/lang/String;)Ljava/lang/String;"
+>
+</method_handle>
+<method_handle index="13"
+ type="invoke-constructor"
+ target_class="Linvokecustom/InvokeCustom;"
+ target_member="<init>"
+ target_member_type="(Linvokecustom/InvokeCustom;I)V"
+>
+</method_handle>
+<method_handle index="14"
+ type="invoke-direct"
+ target_class="Linvokecustom/Super;"
+ target_member="targetMethodTest4"
+ target_member_type="(Linvokecustom/Super;)V"
+>
+</method_handle>
+<method_handle index="15"
+ type="invoke-interface"
+ target_class="Ljava/lang/Runnable;"
+ target_member="run"
+ target_member_type="(Ljava/lang/Runnable;)V"
+>
+</method_handle>
+<call_site index="0" offset="8450">
+<link_argument index="0" type="MethodHandle" value="9"/>
+<link_argument index="1" type="String" values="test"/>
+<link_argument index="2" type="MethodType" value="()Ljava/util/function/Predicate;"/>
+<link_argument index="3" type="MethodType" value="(Ljava/lang/Object;)Z"/>
+<link_argument index="4" type="MethodHandle" value="8"/>
+<link_argument index="5" type="MethodType" value="(Ljava/lang/String;)Z"/>
 </call_site>
-<call_site index="1">
-<link_argument index="0" type="MethodHandle" value="0"/>
-<link_argument index="1" type="String" values="add"/>
-<link_argument index="2" type="MethodType" value="(II)I"/>
+<call_site index="1" offset="8463">
+<link_argument index="0" type="MethodHandle" value="9"/>
+<link_argument index="1" type="String" values="apply"/>
+<link_argument index="2" type="MethodType" value="()Ljava/util/function/Function;"/>
+<link_argument index="3" type="MethodType" value="(Ljava/lang/Object;)Ljava/lang/Object;"/>
+<link_argument index="4" type="MethodHandle" value="12"/>
+<link_argument index="5" type="MethodType" value="(Ljava/lang/String;)Ljava/lang/String;"/>
+</call_site>
+<call_site index="2" offset="8476">
+<link_argument index="0" type="MethodHandle" value="9"/>
+<link_argument index="1" type="String" values="accept"/>
+<link_argument index="2" type="MethodType" value="(Ljava/io/PrintStream;)Ljava/util/function/Consumer;"/>
+<link_argument index="3" type="MethodType" value="(Ljava/lang/Object;)V"/>
+<link_argument index="4" type="MethodHandle" value="11"/>
+<link_argument index="5" type="MethodType" value="(Ljava/lang/String;)V"/>
+</call_site>
+<call_site index="3" offset="8489">
+<link_argument index="0" type="MethodHandle" value="5"/>
+<link_argument index="1" type="String" values="targetMethodTest1"/>
+<link_argument index="2" type="MethodType" value="()V"/>
+</call_site>
+<call_site index="4" offset="8496">
+<link_argument index="0" type="MethodHandle" value="5"/>
+<link_argument index="1" type="String" values="targetMethodTest2"/>
+<link_argument index="2" type="MethodType" value="(ZBCSIFJDLjava/lang/String;)V"/>
+</call_site>
+<call_site index="5" offset="8503">
+<link_argument index="0" type="MethodHandle" value="5"/>
+<link_argument index="1" type="String" values="targetMethodTest5"/>
+<link_argument index="2" type="MethodType" value="(III)I"/>
+</call_site>
+<call_site index="6" offset="8510">
+<link_argument index="0" type="MethodHandle" value="5"/>
+<link_argument index="1" type="String" values="targetMethodTest6"/>
+<link_argument index="2" type="MethodType" value="(JJJ)J"/>
+</call_site>
+<call_site index="7" offset="8517">
+<link_argument index="0" type="MethodHandle" value="5"/>
+<link_argument index="1" type="String" values="targetMethodTest7"/>
+<link_argument index="2" type="MethodType" value="(FFD)D"/>
+</call_site>
+<call_site index="8" offset="8524">
+<link_argument index="0" type="MethodHandle" value="5"/>
+<link_argument index="1" type="String" values="targetMethodTest8"/>
+<link_argument index="2" type="MethodType" value="(Ljava/lang/String;)V"/>
+</call_site>
+<call_site index="9" offset="8524">
+<link_argument index="0" type="MethodHandle" value="5"/>
+<link_argument index="1" type="String" values="targetMethodTest8"/>
+<link_argument index="2" type="MethodType" value="(Ljava/lang/String;)V"/>
+</call_site>
+<call_site index="10" offset="8524">
+<link_argument index="0" type="MethodHandle" value="5"/>
+<link_argument index="1" type="String" values="targetMethodTest8"/>
+<link_argument index="2" type="MethodType" value="(Ljava/lang/String;)V"/>
+</call_site>
+<call_site index="11" offset="8531">
+<link_argument index="0" type="MethodHandle" value="6"/>
+<link_argument index="1" type="String" values="targetMethodTest3"/>
+<link_argument index="2" type="MethodType" value="()V"/>
 <link_argument index="3" type="int" value="1"/>
-<link_argument index="4" type="int" value="1"/>
-<link_argument index="5" type="int" value="97"/>
-<link_argument index="6" type="int" value="1024"/>
-<link_argument index="7" type="int" value="1"/>
-<link_argument index="8" type="float" value="11.1"/>
-<link_argument index="9" type="double" value="2.2"/>
-<link_argument index="10" type="String" value="Hello"/>
-<link_argument index="11" type="Class" value="Tests"/>
-<link_argument index="12" type="long" value="123456789"/>
+<link_argument index="4" type="long" value="123456789"/>
+<link_argument index="5" type="float" value="123.456"/>
+<link_argument index="6" type="double" value="123457"/>
+</call_site>
+<call_site index="12" offset="8559">
+<link_argument index="0" type="MethodHandle" value="4"/>
+<link_argument index="1" type="String" values="targetMethodTest4"/>
+<link_argument index="2" type="MethodType" value="(Linvokecustom/InvokeCustom;)V"/>
+<link_argument index="3" type="MethodHandle" value="14"/>
+</call_site>
+<call_site index="13" offset="8568">
+<link_argument index="0" type="MethodHandle" value="7"/>
+<link_argument index="1" type="String" values="targetMethodTest9"/>
+<link_argument index="2" type="MethodType" value="()V"/>
+<link_argument index="3" type="MethodHandle" value="1"/>
+<link_argument index="4" type="MethodHandle" value="0"/>
+<link_argument index="5" type="MethodHandle" value="3"/>
+<link_argument index="6" type="MethodHandle" value="2"/>
+<link_argument index="7" type="MethodHandle" value="10"/>
+<link_argument index="8" type="MethodHandle" value="13"/>
+<link_argument index="9" type="MethodHandle" value="15"/>
 </call_site>
 </package>
 </api>
diff --git a/test/ti-agent/breakpoint_helper.cc b/test/ti-agent/breakpoint_helper.cc
new file mode 100644
index 0000000..78aab43
--- /dev/null
+++ b/test/ti-agent/breakpoint_helper.cc
@@ -0,0 +1,204 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "common_helper.h"
+
+#include "jni.h"
+#include "jvmti.h"
+
+#include "jvmti_helper.h"
+#include "scoped_local_ref.h"
+#include "test_env.h"
+
+namespace art {
+
+namespace common_breakpoint {
+
+struct BreakpointData {
+  jclass test_klass;
+  jmethodID breakpoint_method;
+  bool in_callback;
+  bool allow_recursive;
+};
+
+extern "C" void breakpointCB(jvmtiEnv* jvmti,
+                             JNIEnv* jnienv,
+                             jthread thread,
+                             jmethodID method,
+                             jlocation location) {
+  BreakpointData* data = nullptr;
+  if (JvmtiErrorToException(jnienv, jvmti,
+                            jvmti->GetEnvironmentLocalStorage(reinterpret_cast<void**>(&data)))) {
+    return;
+  }
+  if (data->in_callback && !data->allow_recursive) {
+    return;
+  }
+  data->in_callback = true;
+  jobject method_arg = GetJavaMethod(jvmti, jnienv, method);
+  jnienv->CallStaticVoidMethod(data->test_klass,
+                               data->breakpoint_method,
+                               thread,
+                               method_arg,
+                               static_cast<jlong>(location));
+  jnienv->DeleteLocalRef(method_arg);
+  data->in_callback = false;
+}
+
+extern "C" JNIEXPORT jobjectArray JNICALL Java_art_Breakpoint_getLineNumberTableNative(
+    JNIEnv* env,
+    jclass k ATTRIBUTE_UNUSED,
+    jobject target) {
+  jmethodID method = env->FromReflectedMethod(target);
+  if (env->ExceptionCheck()) {
+    return nullptr;
+  }
+  jint nlines;
+  jvmtiLineNumberEntry* lines = nullptr;
+  if (JvmtiErrorToException(env, jvmti_env,
+                            jvmti_env->GetLineNumberTable(method, &nlines, &lines))) {
+    return nullptr;
+  }
+  jintArray lines_array = env->NewIntArray(nlines);
+  if (env->ExceptionCheck()) {
+    jvmti_env->Deallocate(reinterpret_cast<unsigned char*>(lines));
+    return nullptr;
+  }
+  jlongArray locs_array = env->NewLongArray(nlines);
+  if (env->ExceptionCheck()) {
+    jvmti_env->Deallocate(reinterpret_cast<unsigned char*>(lines));
+    return nullptr;
+  }
+  ScopedLocalRef<jclass> object_class(env, env->FindClass("java/lang/Object"));
+  if (env->ExceptionCheck()) {
+    jvmti_env->Deallocate(reinterpret_cast<unsigned char*>(lines));
+    return nullptr;
+  }
+  jobjectArray ret = env->NewObjectArray(2, object_class.get(), nullptr);
+  if (env->ExceptionCheck()) {
+    jvmti_env->Deallocate(reinterpret_cast<unsigned char*>(lines));
+    return nullptr;
+  }
+  jint* temp_lines = env->GetIntArrayElements(lines_array, /*isCopy*/nullptr);
+  jlong* temp_locs = env->GetLongArrayElements(locs_array, /*isCopy*/nullptr);
+  for (jint i = 0; i < nlines; i++) {
+    temp_lines[i] = lines[i].line_number;
+    temp_locs[i] = lines[i].start_location;
+  }
+  env->ReleaseIntArrayElements(lines_array, temp_lines, 0);
+  env->ReleaseLongArrayElements(locs_array, temp_locs, 0);
+  env->SetObjectArrayElement(ret, 0, locs_array);
+  env->SetObjectArrayElement(ret, 1, lines_array);
+  jvmti_env->Deallocate(reinterpret_cast<unsigned char*>(lines));
+  return ret;
+}
+
+extern "C" JNIEXPORT jlong JNICALL Java_art_Breakpoint_getStartLocation(JNIEnv* env,
+                                                                        jclass k ATTRIBUTE_UNUSED,
+                                                                        jobject target) {
+  jmethodID method = env->FromReflectedMethod(target);
+  if (env->ExceptionCheck()) {
+    return 0;
+  }
+  jlong start = 0;
+  jlong end = end;
+  JvmtiErrorToException(env, jvmti_env, jvmti_env->GetMethodLocation(method, &start, &end));
+  return start;
+}
+
+extern "C" JNIEXPORT void JNICALL Java_art_Breakpoint_clearBreakpoint(JNIEnv* env,
+                                                                      jclass k ATTRIBUTE_UNUSED,
+                                                                      jobject target,
+                                                                      jlocation location) {
+  jmethodID method = env->FromReflectedMethod(target);
+  if (env->ExceptionCheck()) {
+    return;
+  }
+  JvmtiErrorToException(env, jvmti_env, jvmti_env->ClearBreakpoint(method, location));
+}
+
+extern "C" JNIEXPORT void JNICALL Java_art_Breakpoint_setBreakpoint(JNIEnv* env,
+                                                                    jclass k ATTRIBUTE_UNUSED,
+                                                                    jobject target,
+                                                                    jlocation location) {
+  jmethodID method = env->FromReflectedMethod(target);
+  if (env->ExceptionCheck()) {
+    return;
+  }
+  JvmtiErrorToException(env, jvmti_env, jvmti_env->SetBreakpoint(method, location));
+}
+
+extern "C" JNIEXPORT void JNICALL Java_art_Breakpoint_startBreakpointWatch(
+    JNIEnv* env,
+    jclass k ATTRIBUTE_UNUSED,
+    jclass method_klass,
+    jobject method,
+    jboolean allow_recursive,
+    jthread thr) {
+  BreakpointData* data = nullptr;
+  if (JvmtiErrorToException(env,
+                            jvmti_env,
+                            jvmti_env->Allocate(sizeof(BreakpointData),
+                                                reinterpret_cast<unsigned char**>(&data)))) {
+    return;
+  }
+  memset(data, 0, sizeof(BreakpointData));
+  data->test_klass = reinterpret_cast<jclass>(env->NewGlobalRef(method_klass));
+  data->breakpoint_method = env->FromReflectedMethod(method);
+  data->in_callback = false;
+  data->allow_recursive = allow_recursive;
+
+  void* old_data = nullptr;
+  if (JvmtiErrorToException(env, jvmti_env, jvmti_env->GetEnvironmentLocalStorage(&old_data))) {
+    return;
+  } else if (old_data != nullptr) {
+    ScopedLocalRef<jclass> rt_exception(env, env->FindClass("java/lang/RuntimeException"));
+    env->ThrowNew(rt_exception.get(), "Environment already has local storage set!");
+    return;
+  }
+  if (JvmtiErrorToException(env, jvmti_env, jvmti_env->SetEnvironmentLocalStorage(data))) {
+    return;
+  }
+  jvmtiEventCallbacks cb;
+  memset(&cb, 0, sizeof(cb));
+  cb.Breakpoint = breakpointCB;
+  if (JvmtiErrorToException(env, jvmti_env, jvmti_env->SetEventCallbacks(&cb, sizeof(cb)))) {
+    return;
+  }
+  if (JvmtiErrorToException(env,
+                            jvmti_env,
+                            jvmti_env->SetEventNotificationMode(JVMTI_ENABLE,
+                                                                JVMTI_EVENT_BREAKPOINT,
+                                                                thr))) {
+    return;
+  }
+}
+
+extern "C" JNIEXPORT void JNICALL Java_art_Breakpoint_stopBreakpointWatch(
+    JNIEnv* env,
+    jclass k ATTRIBUTE_UNUSED,
+    jthread thr) {
+  if (JvmtiErrorToException(env, jvmti_env,
+                            jvmti_env->SetEventNotificationMode(JVMTI_DISABLE,
+                                                                JVMTI_EVENT_BREAKPOINT,
+                                                                thr))) {
+    return;
+  }
+}
+
+}  // namespace common_breakpoint
+
+}  // namespace art
diff --git a/test/ti-agent/common_helper.cc b/test/ti-agent/common_helper.cc
index 0eb71f8..e57a493 100644
--- a/test/ti-agent/common_helper.cc
+++ b/test/ti-agent/common_helper.cc
@@ -16,63 +16,18 @@
 
 #include "common_helper.h"
 
-#include <dlfcn.h>
-#include <map>
-#include <stdio.h>
 #include <sstream>
-#include <deque>
-#include <vector>
+#include <string>
 
 #include "android-base/stringprintf.h"
 #include "jni.h"
 #include "jvmti.h"
 
-#include "jni_binder.h"
 #include "jvmti_helper.h"
-#include "scoped_local_ref.h"
-#include "test_env.h"
 
 namespace art {
 
-static void SetupCommonRetransform();
-static void SetupCommonRedefine();
-static void SetupCommonTransform();
-
-// Taken from art/runtime/modifiers.h
-static constexpr uint32_t kAccStatic =       0x0008;  // field, method, ic
-
-template <bool is_redefine>
-static void throwCommonRedefinitionError(jvmtiEnv* jvmti,
-                                         JNIEnv* env,
-                                         jint num_targets,
-                                         jclass* target,
-                                         jvmtiError res) {
-  std::stringstream err;
-  char* error = nullptr;
-  jvmti->GetErrorName(res, &error);
-  err << "Failed to " << (is_redefine ? "redefine" : "retransform") << " class";
-  if (num_targets > 1) {
-    err << "es";
-  }
-  err << " <";
-  for (jint i = 0; i < num_targets; i++) {
-    char* signature = nullptr;
-    char* generic = nullptr;
-    jvmti->GetClassSignature(target[i], &signature, &generic);
-    if (i != 0) {
-      err << ", ";
-    }
-    err << signature;
-    jvmti->Deallocate(reinterpret_cast<unsigned char*>(signature));
-    jvmti->Deallocate(reinterpret_cast<unsigned char*>(generic));
-  }
-  err << "> due to " << error;
-  std::string message = err.str();
-  jvmti->Deallocate(reinterpret_cast<unsigned char*>(error));
-  env->ThrowNew(env->FindClass("java/lang/Exception"), message.c_str());
-}
-
-static jobject GetJavaField(jvmtiEnv* jvmti, JNIEnv* env, jclass field_klass, jfieldID f) {
+jobject GetJavaField(jvmtiEnv* jvmti, JNIEnv* env, jclass field_klass, jfieldID f) {
   jint mods = 0;
   if (JvmtiErrorToException(env, jvmti, jvmti->GetFieldModifiers(field_klass, f, &mods))) {
     return nullptr;
@@ -82,7 +37,7 @@
   return env->ToReflectedField(field_klass, f, is_static);
 }
 
-static jobject GetJavaMethod(jvmtiEnv* jvmti, JNIEnv* env, jmethodID m) {
+jobject GetJavaMethod(jvmtiEnv* jvmti, JNIEnv* env, jmethodID m) {
   jint mods = 0;
   if (JvmtiErrorToException(env, jvmti, jvmti->GetMethodModifiers(m, &mods))) {
     return nullptr;
@@ -98,7 +53,7 @@
   return res;
 }
 
-static jobject GetJavaValueByType(JNIEnv* env, char type, jvalue value) {
+jobject GetJavaValueByType(JNIEnv* env, char type, jvalue value) {
   std::string name;
   switch (type) {
     case 'V':
@@ -146,10 +101,7 @@
   return res;
 }
 
-static jobject GetJavaValue(jvmtiEnv* jvmtienv,
-                            JNIEnv* env,
-                            jmethodID m,
-                            jvalue value) {
+jobject GetJavaValue(jvmtiEnv* jvmtienv, JNIEnv* env, jmethodID m, jvalue value) {
   char *fname, *fsig, *fgen;
   if (JvmtiErrorToException(env, jvmtienv, jvmtienv->GetMethodName(m, &fname, &fsig, &fgen))) {
     return nullptr;
@@ -162,985 +114,4 @@
   return GetJavaValueByType(env, type[0], value);
 }
 
-namespace common_breakpoint {
-
-struct BreakpointData {
-  jclass test_klass;
-  jmethodID breakpoint_method;
-  bool in_callback;
-  bool allow_recursive;
-};
-
-extern "C" void breakpointCB(jvmtiEnv* jvmti,
-                             JNIEnv* jnienv,
-                             jthread thread,
-                             jmethodID method,
-                             jlocation location) {
-  BreakpointData* data = nullptr;
-  if (JvmtiErrorToException(jnienv, jvmti,
-                            jvmti->GetEnvironmentLocalStorage(reinterpret_cast<void**>(&data)))) {
-    return;
-  }
-  if (data->in_callback && !data->allow_recursive) {
-    return;
-  }
-  data->in_callback = true;
-  jobject method_arg = GetJavaMethod(jvmti, jnienv, method);
-  jnienv->CallStaticVoidMethod(data->test_klass,
-                               data->breakpoint_method,
-                               thread,
-                               method_arg,
-                               static_cast<jlong>(location));
-  jnienv->DeleteLocalRef(method_arg);
-  data->in_callback = false;
-}
-
-extern "C" JNIEXPORT jobjectArray JNICALL Java_art_Breakpoint_getLineNumberTableNative(
-    JNIEnv* env,
-    jclass k ATTRIBUTE_UNUSED,
-    jobject target) {
-  jmethodID method = env->FromReflectedMethod(target);
-  if (env->ExceptionCheck()) {
-    return nullptr;
-  }
-  jint nlines;
-  jvmtiLineNumberEntry* lines = nullptr;
-  if (JvmtiErrorToException(env, jvmti_env,
-                            jvmti_env->GetLineNumberTable(method, &nlines, &lines))) {
-    return nullptr;
-  }
-  jintArray lines_array = env->NewIntArray(nlines);
-  if (env->ExceptionCheck()) {
-    jvmti_env->Deallocate(reinterpret_cast<unsigned char*>(lines));
-    return nullptr;
-  }
-  jlongArray locs_array = env->NewLongArray(nlines);
-  if (env->ExceptionCheck()) {
-    jvmti_env->Deallocate(reinterpret_cast<unsigned char*>(lines));
-    return nullptr;
-  }
-  ScopedLocalRef<jclass> object_class(env, env->FindClass("java/lang/Object"));
-  if (env->ExceptionCheck()) {
-    jvmti_env->Deallocate(reinterpret_cast<unsigned char*>(lines));
-    return nullptr;
-  }
-  jobjectArray ret = env->NewObjectArray(2, object_class.get(), nullptr);
-  if (env->ExceptionCheck()) {
-    jvmti_env->Deallocate(reinterpret_cast<unsigned char*>(lines));
-    return nullptr;
-  }
-  jint* temp_lines = env->GetIntArrayElements(lines_array, /*isCopy*/nullptr);
-  jlong* temp_locs = env->GetLongArrayElements(locs_array, /*isCopy*/nullptr);
-  for (jint i = 0; i < nlines; i++) {
-    temp_lines[i] = lines[i].line_number;
-    temp_locs[i] = lines[i].start_location;
-  }
-  env->ReleaseIntArrayElements(lines_array, temp_lines, 0);
-  env->ReleaseLongArrayElements(locs_array, temp_locs, 0);
-  env->SetObjectArrayElement(ret, 0, locs_array);
-  env->SetObjectArrayElement(ret, 1, lines_array);
-  jvmti_env->Deallocate(reinterpret_cast<unsigned char*>(lines));
-  return ret;
-}
-
-extern "C" JNIEXPORT jlong JNICALL Java_art_Breakpoint_getStartLocation(JNIEnv* env,
-                                                                        jclass k ATTRIBUTE_UNUSED,
-                                                                        jobject target) {
-  jmethodID method = env->FromReflectedMethod(target);
-  if (env->ExceptionCheck()) {
-    return 0;
-  }
-  jlong start = 0;
-  jlong end = end;
-  JvmtiErrorToException(env, jvmti_env, jvmti_env->GetMethodLocation(method, &start, &end));
-  return start;
-}
-
-extern "C" JNIEXPORT void JNICALL Java_art_Breakpoint_clearBreakpoint(JNIEnv* env,
-                                                                      jclass k ATTRIBUTE_UNUSED,
-                                                                      jobject target,
-                                                                      jlocation location) {
-  jmethodID method = env->FromReflectedMethod(target);
-  if (env->ExceptionCheck()) {
-    return;
-  }
-  JvmtiErrorToException(env, jvmti_env, jvmti_env->ClearBreakpoint(method, location));
-}
-
-extern "C" JNIEXPORT void JNICALL Java_art_Breakpoint_setBreakpoint(JNIEnv* env,
-                                                                    jclass k ATTRIBUTE_UNUSED,
-                                                                    jobject target,
-                                                                    jlocation location) {
-  jmethodID method = env->FromReflectedMethod(target);
-  if (env->ExceptionCheck()) {
-    return;
-  }
-  JvmtiErrorToException(env, jvmti_env, jvmti_env->SetBreakpoint(method, location));
-}
-
-extern "C" JNIEXPORT void JNICALL Java_art_Breakpoint_startBreakpointWatch(
-    JNIEnv* env,
-    jclass k ATTRIBUTE_UNUSED,
-    jclass method_klass,
-    jobject method,
-    jboolean allow_recursive,
-    jthread thr) {
-  BreakpointData* data = nullptr;
-  if (JvmtiErrorToException(env,
-                            jvmti_env,
-                            jvmti_env->Allocate(sizeof(BreakpointData),
-                                                reinterpret_cast<unsigned char**>(&data)))) {
-    return;
-  }
-  memset(data, 0, sizeof(BreakpointData));
-  data->test_klass = reinterpret_cast<jclass>(env->NewGlobalRef(method_klass));
-  data->breakpoint_method = env->FromReflectedMethod(method);
-  data->in_callback = false;
-  data->allow_recursive = allow_recursive;
-
-  void* old_data = nullptr;
-  if (JvmtiErrorToException(env, jvmti_env, jvmti_env->GetEnvironmentLocalStorage(&old_data))) {
-    return;
-  } else if (old_data != nullptr) {
-    ScopedLocalRef<jclass> rt_exception(env, env->FindClass("java/lang/RuntimeException"));
-    env->ThrowNew(rt_exception.get(), "Environment already has local storage set!");
-    return;
-  }
-  if (JvmtiErrorToException(env, jvmti_env, jvmti_env->SetEnvironmentLocalStorage(data))) {
-    return;
-  }
-  jvmtiEventCallbacks cb;
-  memset(&cb, 0, sizeof(cb));
-  cb.Breakpoint = breakpointCB;
-  if (JvmtiErrorToException(env, jvmti_env, jvmti_env->SetEventCallbacks(&cb, sizeof(cb)))) {
-    return;
-  }
-  if (JvmtiErrorToException(env,
-                            jvmti_env,
-                            jvmti_env->SetEventNotificationMode(JVMTI_ENABLE,
-                                                                JVMTI_EVENT_BREAKPOINT,
-                                                                thr))) {
-    return;
-  }
-}
-
-extern "C" JNIEXPORT void JNICALL Java_art_Breakpoint_stopBreakpointWatch(
-    JNIEnv* env,
-    jclass k ATTRIBUTE_UNUSED,
-    jthread thr) {
-  if (JvmtiErrorToException(env, jvmti_env,
-                            jvmti_env->SetEventNotificationMode(JVMTI_DISABLE,
-                                                                JVMTI_EVENT_BREAKPOINT,
-                                                                thr))) {
-    return;
-  }
-}
-
-}  // namespace common_breakpoint
-
-namespace common_trace {
-
-struct TraceData {
-  jclass test_klass;
-  jmethodID enter_method;
-  jmethodID exit_method;
-  jmethodID field_access;
-  jmethodID field_modify;
-  jmethodID single_step;
-  bool in_callback;
-  bool access_watch_on_load;
-  bool modify_watch_on_load;
-};
-
-static void singleStepCB(jvmtiEnv* jvmti,
-                         JNIEnv* jnienv,
-                         jthread thread,
-                         jmethodID method,
-                         jlocation location) {
-  TraceData* data = nullptr;
-  if (JvmtiErrorToException(jnienv, jvmti,
-                            jvmti->GetEnvironmentLocalStorage(reinterpret_cast<void**>(&data)))) {
-    return;
-  }
-  if (data->in_callback) {
-    return;
-  }
-  CHECK(data->single_step != nullptr);
-  data->in_callback = true;
-  jobject method_arg = GetJavaMethod(jvmti, jnienv, method);
-  jnienv->CallStaticVoidMethod(data->test_klass,
-                               data->single_step,
-                               thread,
-                               method_arg,
-                               static_cast<jlong>(location));
-  jnienv->DeleteLocalRef(method_arg);
-  data->in_callback = false;
-}
-
-static void fieldAccessCB(jvmtiEnv* jvmti,
-                          JNIEnv* jnienv,
-                          jthread thr ATTRIBUTE_UNUSED,
-                          jmethodID method,
-                          jlocation location,
-                          jclass field_klass,
-                          jobject object,
-                          jfieldID field) {
-  TraceData* data = nullptr;
-  if (JvmtiErrorToException(jnienv, jvmti,
-                            jvmti->GetEnvironmentLocalStorage(reinterpret_cast<void**>(&data)))) {
-    return;
-  }
-  if (data->in_callback) {
-    // Don't do callback for either of these to prevent an infinite loop.
-    return;
-  }
-  CHECK(data->field_access != nullptr);
-  data->in_callback = true;
-  jobject method_arg = GetJavaMethod(jvmti, jnienv, method);
-  jobject field_arg = GetJavaField(jvmti, jnienv, field_klass, field);
-  jnienv->CallStaticVoidMethod(data->test_klass,
-                               data->field_access,
-                               method_arg,
-                               static_cast<jlong>(location),
-                               field_klass,
-                               object,
-                               field_arg);
-  jnienv->DeleteLocalRef(method_arg);
-  jnienv->DeleteLocalRef(field_arg);
-  data->in_callback = false;
-}
-
-static void fieldModificationCB(jvmtiEnv* jvmti,
-                                JNIEnv* jnienv,
-                                jthread thr ATTRIBUTE_UNUSED,
-                                jmethodID method,
-                                jlocation location,
-                                jclass field_klass,
-                                jobject object,
-                                jfieldID field,
-                                char type_char,
-                                jvalue new_value) {
-  TraceData* data = nullptr;
-  if (JvmtiErrorToException(jnienv, jvmti,
-                            jvmti->GetEnvironmentLocalStorage(reinterpret_cast<void**>(&data)))) {
-    return;
-  }
-  if (data->in_callback) {
-    // Don't do callback recursively to prevent an infinite loop.
-    return;
-  }
-  CHECK(data->field_modify != nullptr);
-  data->in_callback = true;
-  jobject method_arg = GetJavaMethod(jvmti, jnienv, method);
-  jobject field_arg = GetJavaField(jvmti, jnienv, field_klass, field);
-  jobject value = GetJavaValueByType(jnienv, type_char, new_value);
-  if (jnienv->ExceptionCheck()) {
-    data->in_callback = false;
-    jnienv->DeleteLocalRef(method_arg);
-    jnienv->DeleteLocalRef(field_arg);
-    return;
-  }
-  jnienv->CallStaticVoidMethod(data->test_klass,
-                               data->field_modify,
-                               method_arg,
-                               static_cast<jlong>(location),
-                               field_klass,
-                               object,
-                               field_arg,
-                               value);
-  jnienv->DeleteLocalRef(method_arg);
-  jnienv->DeleteLocalRef(field_arg);
-  data->in_callback = false;
-}
-
-static void methodExitCB(jvmtiEnv* jvmti,
-                         JNIEnv* jnienv,
-                         jthread thr ATTRIBUTE_UNUSED,
-                         jmethodID method,
-                         jboolean was_popped_by_exception,
-                         jvalue return_value) {
-  TraceData* data = nullptr;
-  if (JvmtiErrorToException(jnienv, jvmti,
-                            jvmti->GetEnvironmentLocalStorage(reinterpret_cast<void**>(&data)))) {
-    return;
-  }
-  if (method == data->exit_method || method == data->enter_method || data->in_callback) {
-    // Don't do callback for either of these to prevent an infinite loop.
-    return;
-  }
-  CHECK(data->exit_method != nullptr);
-  data->in_callback = true;
-  jobject method_arg = GetJavaMethod(jvmti, jnienv, method);
-  jobject result =
-      was_popped_by_exception ? nullptr : GetJavaValue(jvmti, jnienv, method, return_value);
-  if (jnienv->ExceptionCheck()) {
-    data->in_callback = false;
-    return;
-  }
-  jnienv->CallStaticVoidMethod(data->test_klass,
-                               data->exit_method,
-                               method_arg,
-                               was_popped_by_exception,
-                               result);
-  jnienv->DeleteLocalRef(method_arg);
-  data->in_callback = false;
-}
-
-static void methodEntryCB(jvmtiEnv* jvmti,
-                          JNIEnv* jnienv,
-                          jthread thr ATTRIBUTE_UNUSED,
-                          jmethodID method) {
-  TraceData* data = nullptr;
-  if (JvmtiErrorToException(jnienv, jvmti,
-                            jvmti->GetEnvironmentLocalStorage(reinterpret_cast<void**>(&data)))) {
-    return;
-  }
-  CHECK(data->enter_method != nullptr);
-  if (method == data->exit_method || method == data->enter_method || data->in_callback) {
-    // Don't do callback for either of these to prevent an infinite loop.
-    return;
-  }
-  data->in_callback = true;
-  jobject method_arg = GetJavaMethod(jvmti, jnienv, method);
-  if (jnienv->ExceptionCheck()) {
-    return;
-  }
-  jnienv->CallStaticVoidMethod(data->test_klass, data->enter_method, method_arg);
-  jnienv->DeleteLocalRef(method_arg);
-  data->in_callback = false;
-}
-
-static void classPrepareCB(jvmtiEnv* jvmti,
-                           JNIEnv* jnienv,
-                           jthread thr ATTRIBUTE_UNUSED,
-                           jclass klass) {
-  TraceData* data = nullptr;
-  if (JvmtiErrorToException(jnienv, jvmti,
-                            jvmti->GetEnvironmentLocalStorage(reinterpret_cast<void**>(&data)))) {
-    return;
-  }
-  if (data->access_watch_on_load || data->modify_watch_on_load) {
-    jint nfields;
-    jfieldID* fields;
-    if (JvmtiErrorToException(jnienv, jvmti, jvmti->GetClassFields(klass, &nfields, &fields))) {
-      return;
-    }
-    for (jint i = 0; i < nfields; i++) {
-      jfieldID f = fields[i];
-      // Ignore errors
-      if (data->access_watch_on_load) {
-        jvmti->SetFieldAccessWatch(klass, f);
-      }
-
-      if (data->modify_watch_on_load) {
-        jvmti->SetFieldModificationWatch(klass, f);
-      }
-    }
-    jvmti->Deallocate(reinterpret_cast<unsigned char*>(fields));
-  }
-}
-
-extern "C" JNIEXPORT void JNICALL Java_art_Trace_watchAllFieldAccesses(JNIEnv* env) {
-  TraceData* data = nullptr;
-  if (JvmtiErrorToException(
-      env, jvmti_env, jvmti_env->GetEnvironmentLocalStorage(reinterpret_cast<void**>(&data)))) {
-    return;
-  }
-  data->access_watch_on_load = true;
-  // We need the classPrepareCB to watch new fields as the classes are loaded/prepared.
-  if (JvmtiErrorToException(env,
-                            jvmti_env,
-                            jvmti_env->SetEventNotificationMode(JVMTI_ENABLE,
-                                                                JVMTI_EVENT_CLASS_PREPARE,
-                                                                nullptr))) {
-    return;
-  }
-  jint nklasses;
-  jclass* klasses;
-  if (JvmtiErrorToException(env, jvmti_env, jvmti_env->GetLoadedClasses(&nklasses, &klasses))) {
-    return;
-  }
-  for (jint i = 0; i < nklasses; i++) {
-    jclass k = klasses[i];
-
-    jint nfields;
-    jfieldID* fields;
-    jvmtiError err = jvmti_env->GetClassFields(k, &nfields, &fields);
-    if (err == JVMTI_ERROR_CLASS_NOT_PREPARED) {
-      continue;
-    } else if (JvmtiErrorToException(env, jvmti_env, err)) {
-      jvmti_env->Deallocate(reinterpret_cast<unsigned char*>(klasses));
-      return;
-    }
-    for (jint j = 0; j < nfields; j++) {
-      jvmti_env->SetFieldAccessWatch(k, fields[j]);
-    }
-    jvmti_env->Deallocate(reinterpret_cast<unsigned char*>(fields));
-  }
-  jvmti_env->Deallocate(reinterpret_cast<unsigned char*>(klasses));
-}
-
-extern "C" JNIEXPORT void JNICALL Java_art_Trace_watchAllFieldModifications(JNIEnv* env) {
-  TraceData* data = nullptr;
-  if (JvmtiErrorToException(
-      env, jvmti_env, jvmti_env->GetEnvironmentLocalStorage(reinterpret_cast<void**>(&data)))) {
-    return;
-  }
-  data->modify_watch_on_load = true;
-  // We need the classPrepareCB to watch new fields as the classes are loaded/prepared.
-  if (JvmtiErrorToException(env,
-                            jvmti_env,
-                            jvmti_env->SetEventNotificationMode(JVMTI_ENABLE,
-                                                                JVMTI_EVENT_CLASS_PREPARE,
-                                                                nullptr))) {
-    return;
-  }
-  jint nklasses;
-  jclass* klasses;
-  if (JvmtiErrorToException(env, jvmti_env, jvmti_env->GetLoadedClasses(&nklasses, &klasses))) {
-    return;
-  }
-  for (jint i = 0; i < nklasses; i++) {
-    jclass k = klasses[i];
-
-    jint nfields;
-    jfieldID* fields;
-    jvmtiError err = jvmti_env->GetClassFields(k, &nfields, &fields);
-    if (err == JVMTI_ERROR_CLASS_NOT_PREPARED) {
-      continue;
-    } else if (JvmtiErrorToException(env, jvmti_env, err)) {
-      jvmti_env->Deallocate(reinterpret_cast<unsigned char*>(klasses));
-      return;
-    }
-    for (jint j = 0; j < nfields; j++) {
-      jvmti_env->SetFieldModificationWatch(k, fields[j]);
-    }
-    jvmti_env->Deallocate(reinterpret_cast<unsigned char*>(fields));
-  }
-  jvmti_env->Deallocate(reinterpret_cast<unsigned char*>(klasses));
-}
-
-static bool GetFieldAndClass(JNIEnv* env,
-                             jobject ref_field,
-                             jclass* out_klass,
-                             jfieldID* out_field) {
-  *out_field = env->FromReflectedField(ref_field);
-  if (env->ExceptionCheck()) {
-    return false;
-  }
-  jclass field_klass = env->FindClass("java/lang/reflect/Field");
-  if (env->ExceptionCheck()) {
-    return false;
-  }
-  jmethodID get_declaring_class_method =
-      env->GetMethodID(field_klass, "getDeclaringClass", "()Ljava/lang/Class;");
-  if (env->ExceptionCheck()) {
-    env->DeleteLocalRef(field_klass);
-    return false;
-  }
-  *out_klass = static_cast<jclass>(env->CallObjectMethod(ref_field, get_declaring_class_method));
-  if (env->ExceptionCheck()) {
-    *out_klass = nullptr;
-    env->DeleteLocalRef(field_klass);
-    return false;
-  }
-  env->DeleteLocalRef(field_klass);
-  return true;
-}
-
-extern "C" JNIEXPORT void JNICALL Java_art_Trace_watchFieldModification(
-    JNIEnv* env,
-    jclass trace ATTRIBUTE_UNUSED,
-    jobject field_obj) {
-  jfieldID field;
-  jclass klass;
-  if (!GetFieldAndClass(env, field_obj, &klass, &field)) {
-    return;
-  }
-
-  JvmtiErrorToException(env, jvmti_env, jvmti_env->SetFieldModificationWatch(klass, field));
-  env->DeleteLocalRef(klass);
-}
-
-extern "C" JNIEXPORT void JNICALL Java_art_Trace_watchFieldAccess(
-    JNIEnv* env,
-    jclass trace ATTRIBUTE_UNUSED,
-    jobject field_obj) {
-  jfieldID field;
-  jclass klass;
-  if (!GetFieldAndClass(env, field_obj, &klass, &field)) {
-    return;
-  }
-  JvmtiErrorToException(env, jvmti_env, jvmti_env->SetFieldAccessWatch(klass, field));
-  env->DeleteLocalRef(klass);
-}
-
-extern "C" JNIEXPORT void JNICALL Java_art_Trace_enableTracing(
-    JNIEnv* env,
-    jclass trace ATTRIBUTE_UNUSED,
-    jclass klass,
-    jobject enter,
-    jobject exit,
-    jobject field_access,
-    jobject field_modify,
-    jobject single_step,
-    jthread thr) {
-  TraceData* data = nullptr;
-  if (JvmtiErrorToException(env,
-                            jvmti_env,
-                            jvmti_env->Allocate(sizeof(TraceData),
-                                                reinterpret_cast<unsigned char**>(&data)))) {
-    return;
-  }
-  memset(data, 0, sizeof(TraceData));
-  data->test_klass = reinterpret_cast<jclass>(env->NewGlobalRef(klass));
-  data->enter_method = enter != nullptr ? env->FromReflectedMethod(enter) : nullptr;
-  data->exit_method = exit != nullptr ? env->FromReflectedMethod(exit) : nullptr;
-  data->field_access = field_access != nullptr ? env->FromReflectedMethod(field_access) : nullptr;
-  data->field_modify = field_modify != nullptr ? env->FromReflectedMethod(field_modify) : nullptr;
-  data->single_step = single_step != nullptr ? env->FromReflectedMethod(single_step) : nullptr;
-  data->in_callback = false;
-
-  void* old_data = nullptr;
-  if (JvmtiErrorToException(env, jvmti_env, jvmti_env->GetEnvironmentLocalStorage(&old_data))) {
-    return;
-  } else if (old_data != nullptr) {
-    ScopedLocalRef<jclass> rt_exception(env, env->FindClass("java/lang/RuntimeException"));
-    env->ThrowNew(rt_exception.get(), "Environment already has local storage set!");
-    return;
-  }
-  if (JvmtiErrorToException(env, jvmti_env, jvmti_env->SetEnvironmentLocalStorage(data))) {
-    return;
-  }
-
-  jvmtiEventCallbacks cb;
-  memset(&cb, 0, sizeof(cb));
-  cb.MethodEntry = methodEntryCB;
-  cb.MethodExit = methodExitCB;
-  cb.FieldAccess = fieldAccessCB;
-  cb.FieldModification = fieldModificationCB;
-  cb.ClassPrepare = classPrepareCB;
-  cb.SingleStep = singleStepCB;
-  if (JvmtiErrorToException(env, jvmti_env, jvmti_env->SetEventCallbacks(&cb, sizeof(cb)))) {
-    return;
-  }
-  if (enter != nullptr &&
-      JvmtiErrorToException(env,
-                            jvmti_env,
-                            jvmti_env->SetEventNotificationMode(JVMTI_ENABLE,
-                                                                JVMTI_EVENT_METHOD_ENTRY,
-                                                                thr))) {
-    return;
-  }
-  if (exit != nullptr &&
-      JvmtiErrorToException(env,
-                            jvmti_env,
-                            jvmti_env->SetEventNotificationMode(JVMTI_ENABLE,
-                                                                JVMTI_EVENT_METHOD_EXIT,
-                                                                thr))) {
-    return;
-  }
-  if (field_access != nullptr &&
-      JvmtiErrorToException(env,
-                            jvmti_env,
-                            jvmti_env->SetEventNotificationMode(JVMTI_ENABLE,
-                                                                JVMTI_EVENT_FIELD_ACCESS,
-                                                                thr))) {
-    return;
-  }
-  if (field_modify != nullptr &&
-      JvmtiErrorToException(env,
-                            jvmti_env,
-                            jvmti_env->SetEventNotificationMode(JVMTI_ENABLE,
-                                                                JVMTI_EVENT_FIELD_MODIFICATION,
-                                                                thr))) {
-    return;
-  }
-  if (single_step != nullptr &&
-      JvmtiErrorToException(env,
-                            jvmti_env,
-                            jvmti_env->SetEventNotificationMode(JVMTI_ENABLE,
-                                                                JVMTI_EVENT_SINGLE_STEP,
-                                                                thr))) {
-    return;
-  }
-}
-
-extern "C" JNIEXPORT void JNICALL Java_art_Trace_disableTracing(
-    JNIEnv* env, jclass klass ATTRIBUTE_UNUSED, jthread thr) {
-  if (JvmtiErrorToException(env, jvmti_env,
-                            jvmti_env->SetEventNotificationMode(JVMTI_DISABLE,
-                                                                JVMTI_EVENT_FIELD_ACCESS,
-                                                                thr))) {
-    return;
-  }
-  if (JvmtiErrorToException(env, jvmti_env,
-                            jvmti_env->SetEventNotificationMode(JVMTI_DISABLE,
-                                                                JVMTI_EVENT_FIELD_MODIFICATION,
-                                                                thr))) {
-    return;
-  }
-  if (JvmtiErrorToException(env, jvmti_env,
-                            jvmti_env->SetEventNotificationMode(JVMTI_DISABLE,
-                                                                JVMTI_EVENT_METHOD_ENTRY,
-                                                                thr))) {
-    return;
-  }
-  if (JvmtiErrorToException(env, jvmti_env,
-                            jvmti_env->SetEventNotificationMode(JVMTI_DISABLE,
-                                                                JVMTI_EVENT_METHOD_EXIT,
-                                                                thr))) {
-    return;
-  }
-  if (JvmtiErrorToException(env, jvmti_env,
-                            jvmti_env->SetEventNotificationMode(JVMTI_DISABLE,
-                                                                JVMTI_EVENT_SINGLE_STEP,
-                                                                thr))) {
-    return;
-  }
-}
-
-}  // namespace common_trace
-
-namespace common_redefine {
-
-static void throwRedefinitionError(jvmtiEnv* jvmti,
-                                   JNIEnv* env,
-                                   jint num_targets,
-                                   jclass* target,
-                                   jvmtiError res) {
-  return throwCommonRedefinitionError<true>(jvmti, env, num_targets, target, res);
-}
-
-static void DoMultiClassRedefine(jvmtiEnv* jvmti_env,
-                                 JNIEnv* env,
-                                 jint num_redefines,
-                                 jclass* targets,
-                                 jbyteArray* class_file_bytes,
-                                 jbyteArray* dex_file_bytes) {
-  std::vector<jvmtiClassDefinition> defs;
-  for (jint i = 0; i < num_redefines; i++) {
-    jbyteArray desired_array = IsJVM() ? class_file_bytes[i] : dex_file_bytes[i];
-    jint len = static_cast<jint>(env->GetArrayLength(desired_array));
-    const unsigned char* redef_bytes = reinterpret_cast<const unsigned char*>(
-        env->GetByteArrayElements(desired_array, nullptr));
-    defs.push_back({targets[i], static_cast<jint>(len), redef_bytes});
-  }
-  jvmtiError res = jvmti_env->RedefineClasses(num_redefines, defs.data());
-  if (res != JVMTI_ERROR_NONE) {
-    throwRedefinitionError(jvmti_env, env, num_redefines, targets, res);
-  }
-}
-
-static void DoClassRedefine(jvmtiEnv* jvmti_env,
-                            JNIEnv* env,
-                            jclass target,
-                            jbyteArray class_file_bytes,
-                            jbyteArray dex_file_bytes) {
-  return DoMultiClassRedefine(jvmti_env, env, 1, &target, &class_file_bytes, &dex_file_bytes);
-}
-
-// Magic JNI export that classes can use for redefining classes.
-// To use classes should declare this as a native function with signature (Ljava/lang/Class;[B[B)V
-extern "C" JNIEXPORT void JNICALL Java_art_Redefinition_doCommonClassRedefinition(
-    JNIEnv* env, jclass, jclass target, jbyteArray class_file_bytes, jbyteArray dex_file_bytes) {
-  DoClassRedefine(jvmti_env, env, target, class_file_bytes, dex_file_bytes);
-}
-
-// Magic JNI export that classes can use for redefining classes.
-// To use classes should declare this as a native function with signature
-// ([Ljava/lang/Class;[[B[[B)V
-extern "C" JNIEXPORT void JNICALL Java_art_Redefinition_doCommonMultiClassRedefinition(
-    JNIEnv* env,
-    jclass,
-    jobjectArray targets,
-    jobjectArray class_file_bytes,
-    jobjectArray dex_file_bytes) {
-  std::vector<jclass> classes;
-  std::vector<jbyteArray> class_files;
-  std::vector<jbyteArray> dex_files;
-  jint len = env->GetArrayLength(targets);
-  if (len != env->GetArrayLength(class_file_bytes) || len != env->GetArrayLength(dex_file_bytes)) {
-    env->ThrowNew(env->FindClass("java/lang/IllegalArgumentException"),
-                  "the three array arguments passed to this function have different lengths!");
-    return;
-  }
-  for (jint i = 0; i < len; i++) {
-    classes.push_back(static_cast<jclass>(env->GetObjectArrayElement(targets, i)));
-    dex_files.push_back(static_cast<jbyteArray>(env->GetObjectArrayElement(dex_file_bytes, i)));
-    class_files.push_back(static_cast<jbyteArray>(env->GetObjectArrayElement(class_file_bytes, i)));
-  }
-  return DoMultiClassRedefine(jvmti_env,
-                              env,
-                              len,
-                              classes.data(),
-                              class_files.data(),
-                              dex_files.data());
-}
-
-// Get all capabilities except those related to retransformation.
-jint OnLoad(JavaVM* vm,
-            char* options ATTRIBUTE_UNUSED,
-            void* reserved ATTRIBUTE_UNUSED) {
-  if (vm->GetEnv(reinterpret_cast<void**>(&jvmti_env), JVMTI_VERSION_1_0)) {
-    printf("Unable to get jvmti env!\n");
-    return 1;
-  }
-  SetupCommonRedefine();
-  return 0;
-}
-
-}  // namespace common_redefine
-
-namespace common_retransform {
-
-struct CommonTransformationResult {
-  std::vector<unsigned char> class_bytes;
-  std::vector<unsigned char> dex_bytes;
-
-  CommonTransformationResult(size_t class_size, size_t dex_size)
-      : class_bytes(class_size), dex_bytes(dex_size) {}
-
-  CommonTransformationResult() = default;
-  CommonTransformationResult(CommonTransformationResult&&) = default;
-  CommonTransformationResult(CommonTransformationResult&) = default;
-};
-
-// Map from class name to transformation result.
-std::map<std::string, std::deque<CommonTransformationResult>> gTransformations;
-bool gPopTransformations = true;
-
-extern "C" JNIEXPORT void JNICALL Java_art_Redefinition_addCommonTransformationResult(
-    JNIEnv* env, jclass, jstring class_name, jbyteArray class_array, jbyteArray dex_array) {
-  const char* name_chrs = env->GetStringUTFChars(class_name, nullptr);
-  std::string name_str(name_chrs);
-  env->ReleaseStringUTFChars(class_name, name_chrs);
-  CommonTransformationResult trans(env->GetArrayLength(class_array),
-                                   env->GetArrayLength(dex_array));
-  if (env->ExceptionOccurred()) {
-    return;
-  }
-  env->GetByteArrayRegion(class_array,
-                          0,
-                          env->GetArrayLength(class_array),
-                          reinterpret_cast<jbyte*>(trans.class_bytes.data()));
-  if (env->ExceptionOccurred()) {
-    return;
-  }
-  env->GetByteArrayRegion(dex_array,
-                          0,
-                          env->GetArrayLength(dex_array),
-                          reinterpret_cast<jbyte*>(trans.dex_bytes.data()));
-  if (env->ExceptionOccurred()) {
-    return;
-  }
-  if (gTransformations.find(name_str) == gTransformations.end()) {
-    std::deque<CommonTransformationResult> list;
-    gTransformations[name_str] = std::move(list);
-  }
-  gTransformations[name_str].push_back(std::move(trans));
-}
-
-// The hook we are using.
-void JNICALL CommonClassFileLoadHookRetransformable(jvmtiEnv* jvmti_env,
-                                                    JNIEnv* jni_env ATTRIBUTE_UNUSED,
-                                                    jclass class_being_redefined ATTRIBUTE_UNUSED,
-                                                    jobject loader ATTRIBUTE_UNUSED,
-                                                    const char* name,
-                                                    jobject protection_domain ATTRIBUTE_UNUSED,
-                                                    jint class_data_len ATTRIBUTE_UNUSED,
-                                                    const unsigned char* class_dat ATTRIBUTE_UNUSED,
-                                                    jint* new_class_data_len,
-                                                    unsigned char** new_class_data) {
-  std::string name_str(name);
-  if (gTransformations.find(name_str) != gTransformations.end() &&
-      gTransformations[name_str].size() > 0) {
-    CommonTransformationResult& res = gTransformations[name_str][0];
-    const std::vector<unsigned char>& desired_array = IsJVM() ? res.class_bytes : res.dex_bytes;
-    unsigned char* new_data;
-    CHECK_EQ(JVMTI_ERROR_NONE, jvmti_env->Allocate(desired_array.size(), &new_data));
-    memcpy(new_data, desired_array.data(), desired_array.size());
-    *new_class_data = new_data;
-    *new_class_data_len = desired_array.size();
-    if (gPopTransformations) {
-      gTransformations[name_str].pop_front();
-    }
-  }
-}
-
-extern "C" JNIEXPORT void Java_art_Redefinition_setPopRetransformations(JNIEnv*,
-                                                                        jclass,
-                                                                        jboolean enable) {
-  gPopTransformations = enable;
-}
-
-extern "C" JNIEXPORT void Java_art_Redefinition_popTransformationFor(JNIEnv* env,
-                                                                         jclass,
-                                                                         jstring class_name) {
-  const char* name_chrs = env->GetStringUTFChars(class_name, nullptr);
-  std::string name_str(name_chrs);
-  env->ReleaseStringUTFChars(class_name, name_chrs);
-  if (gTransformations.find(name_str) != gTransformations.end() &&
-      gTransformations[name_str].size() > 0) {
-    gTransformations[name_str].pop_front();
-  } else {
-    std::stringstream err;
-    err << "No transformations found for class " << name_str;
-    std::string message = err.str();
-    env->ThrowNew(env->FindClass("java/lang/Exception"), message.c_str());
-  }
-}
-
-extern "C" JNIEXPORT void Java_art_Redefinition_enableCommonRetransformation(JNIEnv* env,
-                                                                                 jclass,
-                                                                                 jboolean enable) {
-  jvmtiError res = jvmti_env->SetEventNotificationMode(enable ? JVMTI_ENABLE : JVMTI_DISABLE,
-                                                       JVMTI_EVENT_CLASS_FILE_LOAD_HOOK,
-                                                       nullptr);
-  if (res != JVMTI_ERROR_NONE) {
-    JvmtiErrorToException(env, jvmti_env, res);
-  }
-}
-
-static void throwRetransformationError(jvmtiEnv* jvmti,
-                                       JNIEnv* env,
-                                       jint num_targets,
-                                       jclass* targets,
-                                       jvmtiError res) {
-  return throwCommonRedefinitionError<false>(jvmti, env, num_targets, targets, res);
-}
-
-static void DoClassRetransformation(jvmtiEnv* jvmti_env, JNIEnv* env, jobjectArray targets) {
-  std::vector<jclass> classes;
-  jint len = env->GetArrayLength(targets);
-  for (jint i = 0; i < len; i++) {
-    classes.push_back(static_cast<jclass>(env->GetObjectArrayElement(targets, i)));
-  }
-  jvmtiError res = jvmti_env->RetransformClasses(len, classes.data());
-  if (res != JVMTI_ERROR_NONE) {
-    throwRetransformationError(jvmti_env, env, len, classes.data(), res);
-  }
-}
-
-extern "C" JNIEXPORT void JNICALL Java_art_Redefinition_doCommonClassRetransformation(
-    JNIEnv* env, jclass, jobjectArray targets) {
-  jvmtiCapabilities caps;
-  jvmtiError caps_err = jvmti_env->GetCapabilities(&caps);
-  if (caps_err != JVMTI_ERROR_NONE) {
-    env->ThrowNew(env->FindClass("java/lang/Exception"),
-                  "Unable to get current jvmtiEnv capabilities");
-    return;
-  }
-
-  // Allocate a new environment if we don't have the can_retransform_classes capability needed to
-  // call the RetransformClasses function.
-  jvmtiEnv* real_env = nullptr;
-  if (caps.can_retransform_classes != 1) {
-    JavaVM* vm = nullptr;
-    if (env->GetJavaVM(&vm) != 0 ||
-        vm->GetEnv(reinterpret_cast<void**>(&real_env), JVMTI_VERSION_1_0) != 0) {
-      env->ThrowNew(env->FindClass("java/lang/Exception"),
-                    "Unable to create temporary jvmtiEnv for RetransformClasses call.");
-      return;
-    }
-    SetAllCapabilities(real_env);
-  } else {
-    real_env = jvmti_env;
-  }
-  DoClassRetransformation(real_env, env, targets);
-  if (caps.can_retransform_classes != 1) {
-    real_env->DisposeEnvironment();
-  }
-}
-
-// Get all capabilities except those related to retransformation.
-jint OnLoad(JavaVM* vm,
-            char* options ATTRIBUTE_UNUSED,
-            void* reserved ATTRIBUTE_UNUSED) {
-  if (vm->GetEnv(reinterpret_cast<void**>(&jvmti_env), JVMTI_VERSION_1_0)) {
-    printf("Unable to get jvmti env!\n");
-    return 1;
-  }
-  SetupCommonRetransform();
-  return 0;
-}
-
-}  // namespace common_retransform
-
-namespace common_transform {
-
-// Get all capabilities except those related to retransformation.
-jint OnLoad(JavaVM* vm,
-            char* options ATTRIBUTE_UNUSED,
-            void* reserved ATTRIBUTE_UNUSED) {
-  if (vm->GetEnv(reinterpret_cast<void**>(&jvmti_env), JVMTI_VERSION_1_0)) {
-    printf("Unable to get jvmti env!\n");
-    return 1;
-  }
-  SetupCommonTransform();
-  return 0;
-}
-
-}  // namespace common_transform
-
-#define CONFIGURATION_COMMON_REDEFINE 0
-#define CONFIGURATION_COMMON_RETRANSFORM 1
-#define CONFIGURATION_COMMON_TRANSFORM 2
-
-static void SetupCommonRedefine() {
-  jvmtiCapabilities caps;
-  jvmti_env->GetPotentialCapabilities(&caps);
-  caps.can_retransform_classes = 0;
-  caps.can_retransform_any_class = 0;
-  jvmti_env->AddCapabilities(&caps);
-}
-
-static void SetupCommonRetransform() {
-  SetAllCapabilities(jvmti_env);
-  jvmtiEventCallbacks cb;
-  memset(&cb, 0, sizeof(cb));
-  cb.ClassFileLoadHook = common_retransform::CommonClassFileLoadHookRetransformable;
-  jvmtiError res = jvmti_env->SetEventCallbacks(&cb, sizeof(cb));
-  CHECK_EQ(res, JVMTI_ERROR_NONE);
-  common_retransform::gTransformations.clear();
-}
-
-static void SetupCommonTransform() {
-  // Don't set the retransform caps
-  jvmtiCapabilities caps;
-  jvmti_env->GetPotentialCapabilities(&caps);
-  caps.can_retransform_classes = 0;
-  caps.can_retransform_any_class = 0;
-  jvmti_env->AddCapabilities(&caps);
-
-  // Use the same callback as the retransform test.
-  jvmtiEventCallbacks cb;
-  memset(&cb, 0, sizeof(cb));
-  cb.ClassFileLoadHook = common_retransform::CommonClassFileLoadHookRetransformable;
-  jvmtiError res = jvmti_env->SetEventCallbacks(&cb, sizeof(cb));
-  CHECK_EQ(res, JVMTI_ERROR_NONE);
-  common_retransform::gTransformations.clear();
-}
-
-extern "C" JNIEXPORT void JNICALL Java_art_Redefinition_nativeSetTestConfiguration(JNIEnv*,
-                                                                                   jclass,
-                                                                                   jint type) {
-  switch (type) {
-    case CONFIGURATION_COMMON_REDEFINE: {
-      SetupCommonRedefine();
-      return;
-    }
-    case CONFIGURATION_COMMON_RETRANSFORM: {
-      SetupCommonRetransform();
-      return;
-    }
-    case CONFIGURATION_COMMON_TRANSFORM: {
-      SetupCommonTransform();
-      return;
-    }
-    default: {
-      LOG(FATAL) << "Unknown test configuration: " << type;
-    }
-  }
-}
 }  // namespace art
diff --git a/test/ti-agent/common_helper.h b/test/ti-agent/common_helper.h
index 610019e..fafa1af 100644
--- a/test/ti-agent/common_helper.h
+++ b/test/ti-agent/common_helper.h
@@ -22,17 +22,13 @@
 
 namespace art {
 
-namespace common_redefine {
-jint OnLoad(JavaVM* vm, char* options, void* reserved);
-}  // namespace common_redefine
+// Taken from art/runtime/modifiers.h
+static constexpr uint32_t kAccStatic =       0x0008;  // field, method, ic
 
-namespace common_retransform {
-jint OnLoad(JavaVM* vm, char* options, void* reserved);
-}  // namespace common_retransform
-
-namespace common_transform {
-jint OnLoad(JavaVM* vm, char* options, void* reserved);
-}  // namespace common_transform
+jobject GetJavaField(jvmtiEnv* jvmti, JNIEnv* env, jclass field_klass, jfieldID f);
+jobject GetJavaMethod(jvmtiEnv* jvmti, JNIEnv* env, jmethodID m);
+jobject GetJavaValueByType(JNIEnv* env, char type, jvalue value);
+jobject GetJavaValue(jvmtiEnv* jvmtienv, JNIEnv* env, jmethodID m, jvalue value);
 
 }  // namespace art
 
diff --git a/test/ti-agent/common_load.cc b/test/ti-agent/common_load.cc
index fd47f59..0679c1b 100644
--- a/test/ti-agent/common_load.cc
+++ b/test/ti-agent/common_load.cc
@@ -20,7 +20,6 @@
 #include "base/logging.h"
 #include "base/macros.h"
 
-#include "common_helper.h"
 #include "jni_binder.h"
 #include "jvmti_helper.h"
 #include "test_env.h"
@@ -32,6 +31,18 @@
 
 namespace art {
 
+namespace common_redefine {
+jint OnLoad(JavaVM* vm, char* options, void* reserved);
+}  // namespace common_redefine
+
+namespace common_retransform {
+jint OnLoad(JavaVM* vm, char* options, void* reserved);
+}  // namespace common_retransform
+
+namespace common_transform {
+jint OnLoad(JavaVM* vm, char* options, void* reserved);
+}  // namespace common_transform
+
 namespace {
 
 using OnLoad   = jint (*)(JavaVM* vm, char* options, void* reserved);
diff --git a/test/ti-agent/redefinition_helper.cc b/test/ti-agent/redefinition_helper.cc
new file mode 100644
index 0000000..3b18879
--- /dev/null
+++ b/test/ti-agent/redefinition_helper.cc
@@ -0,0 +1,410 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "common_helper.h"
+
+#include <deque>
+#include <map>
+#include <stdio.h>
+#include <sstream>
+#include <string>
+#include <vector>
+
+#include "jni.h"
+#include "jvmti.h"
+
+#include "jvmti_helper.h"
+#include "test_env.h"
+
+namespace art {
+
+static void SetupCommonRedefine();
+static void SetupCommonRetransform();
+static void SetupCommonTransform();
+template <bool is_redefine>
+static void throwCommonRedefinitionError(jvmtiEnv* jvmti,
+                                         JNIEnv* env,
+                                         jint num_targets,
+                                         jclass* target,
+                                         jvmtiError res) {
+  std::stringstream err;
+  char* error = nullptr;
+  jvmti->GetErrorName(res, &error);
+  err << "Failed to " << (is_redefine ? "redefine" : "retransform") << " class";
+  if (num_targets > 1) {
+    err << "es";
+  }
+  err << " <";
+  for (jint i = 0; i < num_targets; i++) {
+    char* signature = nullptr;
+    char* generic = nullptr;
+    jvmti->GetClassSignature(target[i], &signature, &generic);
+    if (i != 0) {
+      err << ", ";
+    }
+    err << signature;
+    jvmti->Deallocate(reinterpret_cast<unsigned char*>(signature));
+    jvmti->Deallocate(reinterpret_cast<unsigned char*>(generic));
+  }
+  err << "> due to " << error;
+  std::string message = err.str();
+  jvmti->Deallocate(reinterpret_cast<unsigned char*>(error));
+  env->ThrowNew(env->FindClass("java/lang/Exception"), message.c_str());
+}
+
+#define CONFIGURATION_COMMON_REDEFINE 0
+#define CONFIGURATION_COMMON_RETRANSFORM 1
+#define CONFIGURATION_COMMON_TRANSFORM 2
+
+extern "C" JNIEXPORT void JNICALL Java_art_Redefinition_nativeSetTestConfiguration(JNIEnv*,
+                                                                                   jclass,
+                                                                                   jint type) {
+  switch (type) {
+    case CONFIGURATION_COMMON_REDEFINE: {
+      SetupCommonRedefine();
+      return;
+    }
+    case CONFIGURATION_COMMON_RETRANSFORM: {
+      SetupCommonRetransform();
+      return;
+    }
+    case CONFIGURATION_COMMON_TRANSFORM: {
+      SetupCommonTransform();
+      return;
+    }
+    default: {
+      LOG(FATAL) << "Unknown test configuration: " << type;
+    }
+  }
+}
+
+namespace common_redefine {
+
+static void throwRedefinitionError(jvmtiEnv* jvmti,
+                                   JNIEnv* env,
+                                   jint num_targets,
+                                   jclass* target,
+                                   jvmtiError res) {
+  return throwCommonRedefinitionError<true>(jvmti, env, num_targets, target, res);
+}
+
+static void DoMultiClassRedefine(jvmtiEnv* jvmti_env,
+                                 JNIEnv* env,
+                                 jint num_redefines,
+                                 jclass* targets,
+                                 jbyteArray* class_file_bytes,
+                                 jbyteArray* dex_file_bytes) {
+  std::vector<jvmtiClassDefinition> defs;
+  for (jint i = 0; i < num_redefines; i++) {
+    jbyteArray desired_array = IsJVM() ? class_file_bytes[i] : dex_file_bytes[i];
+    jint len = static_cast<jint>(env->GetArrayLength(desired_array));
+    const unsigned char* redef_bytes = reinterpret_cast<const unsigned char*>(
+        env->GetByteArrayElements(desired_array, nullptr));
+    defs.push_back({targets[i], static_cast<jint>(len), redef_bytes});
+  }
+  jvmtiError res = jvmti_env->RedefineClasses(num_redefines, defs.data());
+  if (res != JVMTI_ERROR_NONE) {
+    throwRedefinitionError(jvmti_env, env, num_redefines, targets, res);
+  }
+}
+
+static void DoClassRedefine(jvmtiEnv* jvmti_env,
+                            JNIEnv* env,
+                            jclass target,
+                            jbyteArray class_file_bytes,
+                            jbyteArray dex_file_bytes) {
+  return DoMultiClassRedefine(jvmti_env, env, 1, &target, &class_file_bytes, &dex_file_bytes);
+}
+
+// Magic JNI export that classes can use for redefining classes.
+// To use classes should declare this as a native function with signature (Ljava/lang/Class;[B[B)V
+extern "C" JNIEXPORT void JNICALL Java_art_Redefinition_doCommonClassRedefinition(
+    JNIEnv* env, jclass, jclass target, jbyteArray class_file_bytes, jbyteArray dex_file_bytes) {
+  DoClassRedefine(jvmti_env, env, target, class_file_bytes, dex_file_bytes);
+}
+
+// Magic JNI export that classes can use for redefining classes.
+// To use classes should declare this as a native function with signature
+// ([Ljava/lang/Class;[[B[[B)V
+extern "C" JNIEXPORT void JNICALL Java_art_Redefinition_doCommonMultiClassRedefinition(
+    JNIEnv* env,
+    jclass,
+    jobjectArray targets,
+    jobjectArray class_file_bytes,
+    jobjectArray dex_file_bytes) {
+  std::vector<jclass> classes;
+  std::vector<jbyteArray> class_files;
+  std::vector<jbyteArray> dex_files;
+  jint len = env->GetArrayLength(targets);
+  if (len != env->GetArrayLength(class_file_bytes) || len != env->GetArrayLength(dex_file_bytes)) {
+    env->ThrowNew(env->FindClass("java/lang/IllegalArgumentException"),
+                  "the three array arguments passed to this function have different lengths!");
+    return;
+  }
+  for (jint i = 0; i < len; i++) {
+    classes.push_back(static_cast<jclass>(env->GetObjectArrayElement(targets, i)));
+    dex_files.push_back(static_cast<jbyteArray>(env->GetObjectArrayElement(dex_file_bytes, i)));
+    class_files.push_back(static_cast<jbyteArray>(env->GetObjectArrayElement(class_file_bytes, i)));
+  }
+  return DoMultiClassRedefine(jvmti_env,
+                              env,
+                              len,
+                              classes.data(),
+                              class_files.data(),
+                              dex_files.data());
+}
+
+// Get all capabilities except those related to retransformation.
+jint OnLoad(JavaVM* vm,
+            char* options ATTRIBUTE_UNUSED,
+            void* reserved ATTRIBUTE_UNUSED) {
+  if (vm->GetEnv(reinterpret_cast<void**>(&jvmti_env), JVMTI_VERSION_1_0)) {
+    printf("Unable to get jvmti env!\n");
+    return 1;
+  }
+  SetupCommonRedefine();
+  return 0;
+}
+
+}  // namespace common_redefine
+
+namespace common_retransform {
+
+struct CommonTransformationResult {
+  std::vector<unsigned char> class_bytes;
+  std::vector<unsigned char> dex_bytes;
+
+  CommonTransformationResult(size_t class_size, size_t dex_size)
+      : class_bytes(class_size), dex_bytes(dex_size) {}
+
+  CommonTransformationResult() = default;
+  CommonTransformationResult(CommonTransformationResult&&) = default;
+  CommonTransformationResult(CommonTransformationResult&) = default;
+};
+
+// Map from class name to transformation result.
+std::map<std::string, std::deque<CommonTransformationResult>> gTransformations;
+bool gPopTransformations = true;
+
+extern "C" JNIEXPORT void JNICALL Java_art_Redefinition_addCommonTransformationResult(
+    JNIEnv* env, jclass, jstring class_name, jbyteArray class_array, jbyteArray dex_array) {
+  const char* name_chrs = env->GetStringUTFChars(class_name, nullptr);
+  std::string name_str(name_chrs);
+  env->ReleaseStringUTFChars(class_name, name_chrs);
+  CommonTransformationResult trans(env->GetArrayLength(class_array),
+                                   env->GetArrayLength(dex_array));
+  if (env->ExceptionOccurred()) {
+    return;
+  }
+  env->GetByteArrayRegion(class_array,
+                          0,
+                          env->GetArrayLength(class_array),
+                          reinterpret_cast<jbyte*>(trans.class_bytes.data()));
+  if (env->ExceptionOccurred()) {
+    return;
+  }
+  env->GetByteArrayRegion(dex_array,
+                          0,
+                          env->GetArrayLength(dex_array),
+                          reinterpret_cast<jbyte*>(trans.dex_bytes.data()));
+  if (env->ExceptionOccurred()) {
+    return;
+  }
+  if (gTransformations.find(name_str) == gTransformations.end()) {
+    std::deque<CommonTransformationResult> list;
+    gTransformations[name_str] = std::move(list);
+  }
+  gTransformations[name_str].push_back(std::move(trans));
+}
+
+// The hook we are using.
+void JNICALL CommonClassFileLoadHookRetransformable(jvmtiEnv* jvmti_env,
+                                                    JNIEnv* jni_env ATTRIBUTE_UNUSED,
+                                                    jclass class_being_redefined ATTRIBUTE_UNUSED,
+                                                    jobject loader ATTRIBUTE_UNUSED,
+                                                    const char* name,
+                                                    jobject protection_domain ATTRIBUTE_UNUSED,
+                                                    jint class_data_len ATTRIBUTE_UNUSED,
+                                                    const unsigned char* class_dat ATTRIBUTE_UNUSED,
+                                                    jint* new_class_data_len,
+                                                    unsigned char** new_class_data) {
+  std::string name_str(name);
+  if (gTransformations.find(name_str) != gTransformations.end() &&
+      gTransformations[name_str].size() > 0) {
+    CommonTransformationResult& res = gTransformations[name_str][0];
+    const std::vector<unsigned char>& desired_array = IsJVM() ? res.class_bytes : res.dex_bytes;
+    unsigned char* new_data;
+    CHECK_EQ(JVMTI_ERROR_NONE, jvmti_env->Allocate(desired_array.size(), &new_data));
+    memcpy(new_data, desired_array.data(), desired_array.size());
+    *new_class_data = new_data;
+    *new_class_data_len = desired_array.size();
+    if (gPopTransformations) {
+      gTransformations[name_str].pop_front();
+    }
+  }
+}
+
+extern "C" JNIEXPORT void Java_art_Redefinition_setPopRetransformations(JNIEnv*,
+                                                                        jclass,
+                                                                        jboolean enable) {
+  gPopTransformations = enable;
+}
+
+extern "C" JNIEXPORT void Java_art_Redefinition_popTransformationFor(JNIEnv* env,
+                                                                         jclass,
+                                                                         jstring class_name) {
+  const char* name_chrs = env->GetStringUTFChars(class_name, nullptr);
+  std::string name_str(name_chrs);
+  env->ReleaseStringUTFChars(class_name, name_chrs);
+  if (gTransformations.find(name_str) != gTransformations.end() &&
+      gTransformations[name_str].size() > 0) {
+    gTransformations[name_str].pop_front();
+  } else {
+    std::stringstream err;
+    err << "No transformations found for class " << name_str;
+    std::string message = err.str();
+    env->ThrowNew(env->FindClass("java/lang/Exception"), message.c_str());
+  }
+}
+
+extern "C" JNIEXPORT void Java_art_Redefinition_enableCommonRetransformation(JNIEnv* env,
+                                                                                 jclass,
+                                                                                 jboolean enable) {
+  jvmtiError res = jvmti_env->SetEventNotificationMode(enable ? JVMTI_ENABLE : JVMTI_DISABLE,
+                                                       JVMTI_EVENT_CLASS_FILE_LOAD_HOOK,
+                                                       nullptr);
+  if (res != JVMTI_ERROR_NONE) {
+    JvmtiErrorToException(env, jvmti_env, res);
+  }
+}
+
+static void throwRetransformationError(jvmtiEnv* jvmti,
+                                       JNIEnv* env,
+                                       jint num_targets,
+                                       jclass* targets,
+                                       jvmtiError res) {
+  return throwCommonRedefinitionError<false>(jvmti, env, num_targets, targets, res);
+}
+
+static void DoClassRetransformation(jvmtiEnv* jvmti_env, JNIEnv* env, jobjectArray targets) {
+  std::vector<jclass> classes;
+  jint len = env->GetArrayLength(targets);
+  for (jint i = 0; i < len; i++) {
+    classes.push_back(static_cast<jclass>(env->GetObjectArrayElement(targets, i)));
+  }
+  jvmtiError res = jvmti_env->RetransformClasses(len, classes.data());
+  if (res != JVMTI_ERROR_NONE) {
+    throwRetransformationError(jvmti_env, env, len, classes.data(), res);
+  }
+}
+
+extern "C" JNIEXPORT void JNICALL Java_art_Redefinition_doCommonClassRetransformation(
+    JNIEnv* env, jclass, jobjectArray targets) {
+  jvmtiCapabilities caps;
+  jvmtiError caps_err = jvmti_env->GetCapabilities(&caps);
+  if (caps_err != JVMTI_ERROR_NONE) {
+    env->ThrowNew(env->FindClass("java/lang/Exception"),
+                  "Unable to get current jvmtiEnv capabilities");
+    return;
+  }
+
+  // Allocate a new environment if we don't have the can_retransform_classes capability needed to
+  // call the RetransformClasses function.
+  jvmtiEnv* real_env = nullptr;
+  if (caps.can_retransform_classes != 1) {
+    JavaVM* vm = nullptr;
+    if (env->GetJavaVM(&vm) != 0 ||
+        vm->GetEnv(reinterpret_cast<void**>(&real_env), JVMTI_VERSION_1_0) != 0) {
+      env->ThrowNew(env->FindClass("java/lang/Exception"),
+                    "Unable to create temporary jvmtiEnv for RetransformClasses call.");
+      return;
+    }
+    SetAllCapabilities(real_env);
+  } else {
+    real_env = jvmti_env;
+  }
+  DoClassRetransformation(real_env, env, targets);
+  if (caps.can_retransform_classes != 1) {
+    real_env->DisposeEnvironment();
+  }
+}
+
+// Get all capabilities except those related to retransformation.
+jint OnLoad(JavaVM* vm,
+            char* options ATTRIBUTE_UNUSED,
+            void* reserved ATTRIBUTE_UNUSED) {
+  if (vm->GetEnv(reinterpret_cast<void**>(&jvmti_env), JVMTI_VERSION_1_0)) {
+    printf("Unable to get jvmti env!\n");
+    return 1;
+  }
+  SetupCommonRetransform();
+  return 0;
+}
+
+}  // namespace common_retransform
+
+namespace common_transform {
+
+// Get all capabilities except those related to retransformation.
+jint OnLoad(JavaVM* vm,
+            char* options ATTRIBUTE_UNUSED,
+            void* reserved ATTRIBUTE_UNUSED) {
+  if (vm->GetEnv(reinterpret_cast<void**>(&jvmti_env), JVMTI_VERSION_1_0)) {
+    printf("Unable to get jvmti env!\n");
+    return 1;
+  }
+  SetupCommonTransform();
+  return 0;
+}
+
+}  // namespace common_transform
+
+static void SetupCommonRedefine() {
+  jvmtiCapabilities caps;
+  jvmti_env->GetPotentialCapabilities(&caps);
+  caps.can_retransform_classes = 0;
+  caps.can_retransform_any_class = 0;
+  jvmti_env->AddCapabilities(&caps);
+}
+
+static void SetupCommonRetransform() {
+  SetAllCapabilities(jvmti_env);
+  jvmtiEventCallbacks cb;
+  memset(&cb, 0, sizeof(cb));
+  cb.ClassFileLoadHook = common_retransform::CommonClassFileLoadHookRetransformable;
+  jvmtiError res = jvmti_env->SetEventCallbacks(&cb, sizeof(cb));
+  CHECK_EQ(res, JVMTI_ERROR_NONE);
+  common_retransform::gTransformations.clear();
+}
+
+static void SetupCommonTransform() {
+  // Don't set the retransform caps
+  jvmtiCapabilities caps;
+  jvmti_env->GetPotentialCapabilities(&caps);
+  caps.can_retransform_classes = 0;
+  caps.can_retransform_any_class = 0;
+  jvmti_env->AddCapabilities(&caps);
+
+  // Use the same callback as the retransform test.
+  jvmtiEventCallbacks cb;
+  memset(&cb, 0, sizeof(cb));
+  cb.ClassFileLoadHook = common_retransform::CommonClassFileLoadHookRetransformable;
+  jvmtiError res = jvmti_env->SetEventCallbacks(&cb, sizeof(cb));
+  CHECK_EQ(res, JVMTI_ERROR_NONE);
+  common_retransform::gTransformations.clear();
+}
+
+}  // namespace art
diff --git a/test/ti-agent/trace_helper.cc b/test/ti-agent/trace_helper.cc
new file mode 100644
index 0000000..7a9d1e0
--- /dev/null
+++ b/test/ti-agent/trace_helper.cc
@@ -0,0 +1,493 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "common_helper.h"
+
+#include "jni.h"
+#include "jvmti.h"
+
+#include "jvmti_helper.h"
+#include "scoped_local_ref.h"
+#include "test_env.h"
+
+namespace art {
+
+namespace common_trace {
+
+struct TraceData {
+  jclass test_klass;
+  jmethodID enter_method;
+  jmethodID exit_method;
+  jmethodID field_access;
+  jmethodID field_modify;
+  jmethodID single_step;
+  bool in_callback;
+  bool access_watch_on_load;
+  bool modify_watch_on_load;
+};
+
+static void singleStepCB(jvmtiEnv* jvmti,
+                         JNIEnv* jnienv,
+                         jthread thread,
+                         jmethodID method,
+                         jlocation location) {
+  TraceData* data = nullptr;
+  if (JvmtiErrorToException(jnienv, jvmti,
+                            jvmti->GetEnvironmentLocalStorage(reinterpret_cast<void**>(&data)))) {
+    return;
+  }
+  if (data->in_callback) {
+    return;
+  }
+  CHECK(data->single_step != nullptr);
+  data->in_callback = true;
+  jobject method_arg = GetJavaMethod(jvmti, jnienv, method);
+  jnienv->CallStaticVoidMethod(data->test_klass,
+                               data->single_step,
+                               thread,
+                               method_arg,
+                               static_cast<jlong>(location));
+  jnienv->DeleteLocalRef(method_arg);
+  data->in_callback = false;
+}
+
+static void fieldAccessCB(jvmtiEnv* jvmti,
+                          JNIEnv* jnienv,
+                          jthread thr ATTRIBUTE_UNUSED,
+                          jmethodID method,
+                          jlocation location,
+                          jclass field_klass,
+                          jobject object,
+                          jfieldID field) {
+  TraceData* data = nullptr;
+  if (JvmtiErrorToException(jnienv, jvmti,
+                            jvmti->GetEnvironmentLocalStorage(reinterpret_cast<void**>(&data)))) {
+    return;
+  }
+  if (data->in_callback) {
+    // Don't do callback for either of these to prevent an infinite loop.
+    return;
+  }
+  CHECK(data->field_access != nullptr);
+  data->in_callback = true;
+  jobject method_arg = GetJavaMethod(jvmti, jnienv, method);
+  jobject field_arg = GetJavaField(jvmti, jnienv, field_klass, field);
+  jnienv->CallStaticVoidMethod(data->test_klass,
+                               data->field_access,
+                               method_arg,
+                               static_cast<jlong>(location),
+                               field_klass,
+                               object,
+                               field_arg);
+  jnienv->DeleteLocalRef(method_arg);
+  jnienv->DeleteLocalRef(field_arg);
+  data->in_callback = false;
+}
+
+static void fieldModificationCB(jvmtiEnv* jvmti,
+                                JNIEnv* jnienv,
+                                jthread thr ATTRIBUTE_UNUSED,
+                                jmethodID method,
+                                jlocation location,
+                                jclass field_klass,
+                                jobject object,
+                                jfieldID field,
+                                char type_char,
+                                jvalue new_value) {
+  TraceData* data = nullptr;
+  if (JvmtiErrorToException(jnienv, jvmti,
+                            jvmti->GetEnvironmentLocalStorage(reinterpret_cast<void**>(&data)))) {
+    return;
+  }
+  if (data->in_callback) {
+    // Don't do callback recursively to prevent an infinite loop.
+    return;
+  }
+  CHECK(data->field_modify != nullptr);
+  data->in_callback = true;
+  jobject method_arg = GetJavaMethod(jvmti, jnienv, method);
+  jobject field_arg = GetJavaField(jvmti, jnienv, field_klass, field);
+  jobject value = GetJavaValueByType(jnienv, type_char, new_value);
+  if (jnienv->ExceptionCheck()) {
+    data->in_callback = false;
+    jnienv->DeleteLocalRef(method_arg);
+    jnienv->DeleteLocalRef(field_arg);
+    return;
+  }
+  jnienv->CallStaticVoidMethod(data->test_klass,
+                               data->field_modify,
+                               method_arg,
+                               static_cast<jlong>(location),
+                               field_klass,
+                               object,
+                               field_arg,
+                               value);
+  jnienv->DeleteLocalRef(method_arg);
+  jnienv->DeleteLocalRef(field_arg);
+  data->in_callback = false;
+}
+
+static void methodExitCB(jvmtiEnv* jvmti,
+                         JNIEnv* jnienv,
+                         jthread thr ATTRIBUTE_UNUSED,
+                         jmethodID method,
+                         jboolean was_popped_by_exception,
+                         jvalue return_value) {
+  TraceData* data = nullptr;
+  if (JvmtiErrorToException(jnienv, jvmti,
+                            jvmti->GetEnvironmentLocalStorage(reinterpret_cast<void**>(&data)))) {
+    return;
+  }
+  if (method == data->exit_method || method == data->enter_method || data->in_callback) {
+    // Don't do callback for either of these to prevent an infinite loop.
+    return;
+  }
+  CHECK(data->exit_method != nullptr);
+  data->in_callback = true;
+  jobject method_arg = GetJavaMethod(jvmti, jnienv, method);
+  jobject result =
+      was_popped_by_exception ? nullptr : GetJavaValue(jvmti, jnienv, method, return_value);
+  if (jnienv->ExceptionCheck()) {
+    data->in_callback = false;
+    return;
+  }
+  jnienv->CallStaticVoidMethod(data->test_klass,
+                               data->exit_method,
+                               method_arg,
+                               was_popped_by_exception,
+                               result);
+  jnienv->DeleteLocalRef(method_arg);
+  data->in_callback = false;
+}
+
+static void methodEntryCB(jvmtiEnv* jvmti,
+                          JNIEnv* jnienv,
+                          jthread thr ATTRIBUTE_UNUSED,
+                          jmethodID method) {
+  TraceData* data = nullptr;
+  if (JvmtiErrorToException(jnienv, jvmti,
+                            jvmti->GetEnvironmentLocalStorage(reinterpret_cast<void**>(&data)))) {
+    return;
+  }
+  CHECK(data->enter_method != nullptr);
+  if (method == data->exit_method || method == data->enter_method || data->in_callback) {
+    // Don't do callback for either of these to prevent an infinite loop.
+    return;
+  }
+  data->in_callback = true;
+  jobject method_arg = GetJavaMethod(jvmti, jnienv, method);
+  if (jnienv->ExceptionCheck()) {
+    return;
+  }
+  jnienv->CallStaticVoidMethod(data->test_klass, data->enter_method, method_arg);
+  jnienv->DeleteLocalRef(method_arg);
+  data->in_callback = false;
+}
+
+static void classPrepareCB(jvmtiEnv* jvmti,
+                           JNIEnv* jnienv,
+                           jthread thr ATTRIBUTE_UNUSED,
+                           jclass klass) {
+  TraceData* data = nullptr;
+  if (JvmtiErrorToException(jnienv, jvmti,
+                            jvmti->GetEnvironmentLocalStorage(reinterpret_cast<void**>(&data)))) {
+    return;
+  }
+  if (data->access_watch_on_load || data->modify_watch_on_load) {
+    jint nfields;
+    jfieldID* fields;
+    if (JvmtiErrorToException(jnienv, jvmti, jvmti->GetClassFields(klass, &nfields, &fields))) {
+      return;
+    }
+    for (jint i = 0; i < nfields; i++) {
+      jfieldID f = fields[i];
+      // Ignore errors
+      if (data->access_watch_on_load) {
+        jvmti->SetFieldAccessWatch(klass, f);
+      }
+
+      if (data->modify_watch_on_load) {
+        jvmti->SetFieldModificationWatch(klass, f);
+      }
+    }
+    jvmti->Deallocate(reinterpret_cast<unsigned char*>(fields));
+  }
+}
+
+extern "C" JNIEXPORT void JNICALL Java_art_Trace_watchAllFieldAccesses(JNIEnv* env) {
+  TraceData* data = nullptr;
+  if (JvmtiErrorToException(
+      env, jvmti_env, jvmti_env->GetEnvironmentLocalStorage(reinterpret_cast<void**>(&data)))) {
+    return;
+  }
+  data->access_watch_on_load = true;
+  // We need the classPrepareCB to watch new fields as the classes are loaded/prepared.
+  if (JvmtiErrorToException(env,
+                            jvmti_env,
+                            jvmti_env->SetEventNotificationMode(JVMTI_ENABLE,
+                                                                JVMTI_EVENT_CLASS_PREPARE,
+                                                                nullptr))) {
+    return;
+  }
+  jint nklasses;
+  jclass* klasses;
+  if (JvmtiErrorToException(env, jvmti_env, jvmti_env->GetLoadedClasses(&nklasses, &klasses))) {
+    return;
+  }
+  for (jint i = 0; i < nklasses; i++) {
+    jclass k = klasses[i];
+
+    jint nfields;
+    jfieldID* fields;
+    jvmtiError err = jvmti_env->GetClassFields(k, &nfields, &fields);
+    if (err == JVMTI_ERROR_CLASS_NOT_PREPARED) {
+      continue;
+    } else if (JvmtiErrorToException(env, jvmti_env, err)) {
+      jvmti_env->Deallocate(reinterpret_cast<unsigned char*>(klasses));
+      return;
+    }
+    for (jint j = 0; j < nfields; j++) {
+      jvmti_env->SetFieldAccessWatch(k, fields[j]);
+    }
+    jvmti_env->Deallocate(reinterpret_cast<unsigned char*>(fields));
+  }
+  jvmti_env->Deallocate(reinterpret_cast<unsigned char*>(klasses));
+}
+
+extern "C" JNIEXPORT void JNICALL Java_art_Trace_watchAllFieldModifications(JNIEnv* env) {
+  TraceData* data = nullptr;
+  if (JvmtiErrorToException(
+      env, jvmti_env, jvmti_env->GetEnvironmentLocalStorage(reinterpret_cast<void**>(&data)))) {
+    return;
+  }
+  data->modify_watch_on_load = true;
+  // We need the classPrepareCB to watch new fields as the classes are loaded/prepared.
+  if (JvmtiErrorToException(env,
+                            jvmti_env,
+                            jvmti_env->SetEventNotificationMode(JVMTI_ENABLE,
+                                                                JVMTI_EVENT_CLASS_PREPARE,
+                                                                nullptr))) {
+    return;
+  }
+  jint nklasses;
+  jclass* klasses;
+  if (JvmtiErrorToException(env, jvmti_env, jvmti_env->GetLoadedClasses(&nklasses, &klasses))) {
+    return;
+  }
+  for (jint i = 0; i < nklasses; i++) {
+    jclass k = klasses[i];
+
+    jint nfields;
+    jfieldID* fields;
+    jvmtiError err = jvmti_env->GetClassFields(k, &nfields, &fields);
+    if (err == JVMTI_ERROR_CLASS_NOT_PREPARED) {
+      continue;
+    } else if (JvmtiErrorToException(env, jvmti_env, err)) {
+      jvmti_env->Deallocate(reinterpret_cast<unsigned char*>(klasses));
+      return;
+    }
+    for (jint j = 0; j < nfields; j++) {
+      jvmti_env->SetFieldModificationWatch(k, fields[j]);
+    }
+    jvmti_env->Deallocate(reinterpret_cast<unsigned char*>(fields));
+  }
+  jvmti_env->Deallocate(reinterpret_cast<unsigned char*>(klasses));
+}
+
+static bool GetFieldAndClass(JNIEnv* env,
+                             jobject ref_field,
+                             jclass* out_klass,
+                             jfieldID* out_field) {
+  *out_field = env->FromReflectedField(ref_field);
+  if (env->ExceptionCheck()) {
+    return false;
+  }
+  jclass field_klass = env->FindClass("java/lang/reflect/Field");
+  if (env->ExceptionCheck()) {
+    return false;
+  }
+  jmethodID get_declaring_class_method =
+      env->GetMethodID(field_klass, "getDeclaringClass", "()Ljava/lang/Class;");
+  if (env->ExceptionCheck()) {
+    env->DeleteLocalRef(field_klass);
+    return false;
+  }
+  *out_klass = static_cast<jclass>(env->CallObjectMethod(ref_field, get_declaring_class_method));
+  if (env->ExceptionCheck()) {
+    *out_klass = nullptr;
+    env->DeleteLocalRef(field_klass);
+    return false;
+  }
+  env->DeleteLocalRef(field_klass);
+  return true;
+}
+
+extern "C" JNIEXPORT void JNICALL Java_art_Trace_watchFieldModification(
+    JNIEnv* env,
+    jclass trace ATTRIBUTE_UNUSED,
+    jobject field_obj) {
+  jfieldID field;
+  jclass klass;
+  if (!GetFieldAndClass(env, field_obj, &klass, &field)) {
+    return;
+  }
+
+  JvmtiErrorToException(env, jvmti_env, jvmti_env->SetFieldModificationWatch(klass, field));
+  env->DeleteLocalRef(klass);
+}
+
+extern "C" JNIEXPORT void JNICALL Java_art_Trace_watchFieldAccess(
+    JNIEnv* env,
+    jclass trace ATTRIBUTE_UNUSED,
+    jobject field_obj) {
+  jfieldID field;
+  jclass klass;
+  if (!GetFieldAndClass(env, field_obj, &klass, &field)) {
+    return;
+  }
+  JvmtiErrorToException(env, jvmti_env, jvmti_env->SetFieldAccessWatch(klass, field));
+  env->DeleteLocalRef(klass);
+}
+
+extern "C" JNIEXPORT void JNICALL Java_art_Trace_enableTracing(
+    JNIEnv* env,
+    jclass trace ATTRIBUTE_UNUSED,
+    jclass klass,
+    jobject enter,
+    jobject exit,
+    jobject field_access,
+    jobject field_modify,
+    jobject single_step,
+    jthread thr) {
+  TraceData* data = nullptr;
+  if (JvmtiErrorToException(env,
+                            jvmti_env,
+                            jvmti_env->Allocate(sizeof(TraceData),
+                                                reinterpret_cast<unsigned char**>(&data)))) {
+    return;
+  }
+  memset(data, 0, sizeof(TraceData));
+  data->test_klass = reinterpret_cast<jclass>(env->NewGlobalRef(klass));
+  data->enter_method = enter != nullptr ? env->FromReflectedMethod(enter) : nullptr;
+  data->exit_method = exit != nullptr ? env->FromReflectedMethod(exit) : nullptr;
+  data->field_access = field_access != nullptr ? env->FromReflectedMethod(field_access) : nullptr;
+  data->field_modify = field_modify != nullptr ? env->FromReflectedMethod(field_modify) : nullptr;
+  data->single_step = single_step != nullptr ? env->FromReflectedMethod(single_step) : nullptr;
+  data->in_callback = false;
+
+  void* old_data = nullptr;
+  if (JvmtiErrorToException(env, jvmti_env, jvmti_env->GetEnvironmentLocalStorage(&old_data))) {
+    return;
+  } else if (old_data != nullptr) {
+    ScopedLocalRef<jclass> rt_exception(env, env->FindClass("java/lang/RuntimeException"));
+    env->ThrowNew(rt_exception.get(), "Environment already has local storage set!");
+    return;
+  }
+  if (JvmtiErrorToException(env, jvmti_env, jvmti_env->SetEnvironmentLocalStorage(data))) {
+    return;
+  }
+
+  jvmtiEventCallbacks cb;
+  memset(&cb, 0, sizeof(cb));
+  cb.MethodEntry = methodEntryCB;
+  cb.MethodExit = methodExitCB;
+  cb.FieldAccess = fieldAccessCB;
+  cb.FieldModification = fieldModificationCB;
+  cb.ClassPrepare = classPrepareCB;
+  cb.SingleStep = singleStepCB;
+  if (JvmtiErrorToException(env, jvmti_env, jvmti_env->SetEventCallbacks(&cb, sizeof(cb)))) {
+    return;
+  }
+  if (enter != nullptr &&
+      JvmtiErrorToException(env,
+                            jvmti_env,
+                            jvmti_env->SetEventNotificationMode(JVMTI_ENABLE,
+                                                                JVMTI_EVENT_METHOD_ENTRY,
+                                                                thr))) {
+    return;
+  }
+  if (exit != nullptr &&
+      JvmtiErrorToException(env,
+                            jvmti_env,
+                            jvmti_env->SetEventNotificationMode(JVMTI_ENABLE,
+                                                                JVMTI_EVENT_METHOD_EXIT,
+                                                                thr))) {
+    return;
+  }
+  if (field_access != nullptr &&
+      JvmtiErrorToException(env,
+                            jvmti_env,
+                            jvmti_env->SetEventNotificationMode(JVMTI_ENABLE,
+                                                                JVMTI_EVENT_FIELD_ACCESS,
+                                                                thr))) {
+    return;
+  }
+  if (field_modify != nullptr &&
+      JvmtiErrorToException(env,
+                            jvmti_env,
+                            jvmti_env->SetEventNotificationMode(JVMTI_ENABLE,
+                                                                JVMTI_EVENT_FIELD_MODIFICATION,
+                                                                thr))) {
+    return;
+  }
+  if (single_step != nullptr &&
+      JvmtiErrorToException(env,
+                            jvmti_env,
+                            jvmti_env->SetEventNotificationMode(JVMTI_ENABLE,
+                                                                JVMTI_EVENT_SINGLE_STEP,
+                                                                thr))) {
+    return;
+  }
+}
+
+extern "C" JNIEXPORT void JNICALL Java_art_Trace_disableTracing(
+    JNIEnv* env, jclass klass ATTRIBUTE_UNUSED, jthread thr) {
+  if (JvmtiErrorToException(env, jvmti_env,
+                            jvmti_env->SetEventNotificationMode(JVMTI_DISABLE,
+                                                                JVMTI_EVENT_FIELD_ACCESS,
+                                                                thr))) {
+    return;
+  }
+  if (JvmtiErrorToException(env, jvmti_env,
+                            jvmti_env->SetEventNotificationMode(JVMTI_DISABLE,
+                                                                JVMTI_EVENT_FIELD_MODIFICATION,
+                                                                thr))) {
+    return;
+  }
+  if (JvmtiErrorToException(env, jvmti_env,
+                            jvmti_env->SetEventNotificationMode(JVMTI_DISABLE,
+                                                                JVMTI_EVENT_METHOD_ENTRY,
+                                                                thr))) {
+    return;
+  }
+  if (JvmtiErrorToException(env, jvmti_env,
+                            jvmti_env->SetEventNotificationMode(JVMTI_DISABLE,
+                                                                JVMTI_EVENT_METHOD_EXIT,
+                                                                thr))) {
+    return;
+  }
+  if (JvmtiErrorToException(env, jvmti_env,
+                            jvmti_env->SetEventNotificationMode(JVMTI_DISABLE,
+                                                                JVMTI_EVENT_SINGLE_STEP,
+                                                                thr))) {
+    return;
+  }
+}
+
+}  // namespace common_trace
+
+
+}  // namespace art
diff --git a/tools/libcore_gcstress_failures.txt b/tools/libcore_gcstress_failures.txt
new file mode 100644
index 0000000..e049cb3
--- /dev/null
+++ b/tools/libcore_gcstress_failures.txt
@@ -0,0 +1,13 @@
+/*
+ * This file contains expectations for ART's buildbot when running gcstress.
+ * The script that uses this file is art/tools/run-libcore-tests.sh.
+ */
+
+[
+{
+  description: "Timeouts on target with gcstress.",
+  result: EXEC_FAILED,
+  modes: [device],
+  names: ["libcore.javax.crypto.CipherBasicsTest#testGcmEncryption"]
+}
+]
diff --git a/tools/run-libcore-tests.sh b/tools/run-libcore-tests.sh
index 6dcc23a..eef74d2 100755
--- a/tools/run-libcore-tests.sh
+++ b/tools/run-libcore-tests.sh
@@ -158,9 +158,12 @@
 fi
 vogar_args="$vogar_args --vm-arg -Xusejit:$use_jit"
 
-# gcstress and debug may lead to timeouts, so we need a dedicated expectations file for it.
-if [[ $gcstress && $debug ]]; then
-  expectations="$expectations --expectations art/tools/libcore_gcstress_debug_failures.txt"
+# gcstress may lead to timeouts, so we need dedicated expectations files for it.
+if [[ $gcstress ]]; then
+  expectations="$expectations --expectations art/tools/libcore_gcstress_failures.txt"
+  if [[ $debug ]]; then
+    expectations="$expectations --expectations art/tools/libcore_gcstress_debug_failures.txt"
+  fi
 fi
 
 # Run the tests using vogar.