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.