From 11edec7e7e8ac93f826d687b644fe700fab68993 Mon Sep 17 00:00:00 2001 From: David Brazdil Date: Thu, 24 Mar 2016 12:40:52 +0000 Subject: ART: Loosen a GraphChecker rule on Boolean inputs GraphChecker tries to verify that Boolean inputs are properly typed. This is non-trivial in the presence of simplifying optimizations which capitalize on the fact that a Boolean value is internally represented as an integer. This patch removes the test from GraphChecker. Bug: 27625564 Change-Id: Ic61ea2193765b4578550538e965ca4f80fa4b287 --- compiler/optimizing/graph_visualizer.cc | 14 ++++++++++++++ 1 file changed, 14 insertions(+) (limited to 'compiler/optimizing/graph_visualizer.cc') diff --git a/compiler/optimizing/graph_visualizer.cc b/compiler/optimizing/graph_visualizer.cc index 3a9d242df2..4b5b919b68 100644 --- a/compiler/optimizing/graph_visualizer.cc +++ b/compiler/optimizing/graph_visualizer.cc @@ -418,6 +418,20 @@ class HGraphVisualizerPrinter : public HGraphDelegateVisitor { StartAttributeStream("intrinsic") << invoke->GetIntrinsic(); } + void VisitInstanceFieldGet(HInstanceFieldGet* iget) OVERRIDE { + StartAttributeStream("field_name") << PrettyField(iget->GetFieldInfo().GetFieldIndex(), + iget->GetFieldInfo().GetDexFile(), + /* with type */ false); + StartAttributeStream("field_type") << iget->GetFieldType(); + } + + void VisitInstanceFieldSet(HInstanceFieldSet* iset) OVERRIDE { + StartAttributeStream("field_name") << PrettyField(iset->GetFieldInfo().GetFieldIndex(), + iset->GetFieldInfo().GetDexFile(), + /* with type */ false); + StartAttributeStream("field_type") << iset->GetFieldType(); + } + void VisitUnresolvedInstanceFieldGet(HUnresolvedInstanceFieldGet* field_access) OVERRIDE { StartAttributeStream("field_type") << field_access->GetFieldType(); } -- cgit v1.2.3-59-g8ed1b From cac5a7e871f1f346b317894359ad06fa7bd67fba Mon Sep 17 00:00:00 2001 From: Vladimir Marko Date: Mon, 22 Feb 2016 10:39:50 +0000 Subject: Optimizing: Improve const-string code generation. For strings in the boot image, use either direct pointers or pc-relative addresses. For other strings, use PC-relative access to the dex cache arrays for AOT and direct address of the string's dex cache slot for JIT. For aosp_flounder-userdebug: - 32-bit boot.oat: -692KiB (-0.9%) - 64-bit boot.oat: -948KiB (-1.1%) - 32-bit dalvik cache total: -900KiB (-0.9%) - 64-bit dalvik cache total: -3672KiB (-1.5%) (contains more files than the 32-bit dalvik cache) For aosp_flounder-userdebug forced to compile PIC: - 32-bit boot.oat: -380KiB (-0.5%) - 64-bit boot.oat: -928KiB (-1.0%) - 32-bit dalvik cache total: -468KiB (-0.4%) - 64-bit dalvik cache total: -1928KiB (-0.8%) (contains more files than the 32-bit dalvik cache) Bug: 26884697 Change-Id: Iec7266ce67e6fedc107be78fab2e742a8dab2696 --- compiler/Android.mk | 1 + compiler/compiled_method.h | 54 ++- compiler/linker/arm/relative_patcher_thumb2.cc | 8 +- compiler/linker/arm/relative_patcher_thumb2.h | 8 +- .../linker/arm/relative_patcher_thumb2_test.cc | 144 +++++--- compiler/linker/arm64/relative_patcher_arm64.cc | 45 ++- compiler/linker/arm64/relative_patcher_arm64.h | 8 +- .../linker/arm64/relative_patcher_arm64_test.cc | 362 ++++++++++++++++----- compiler/linker/multi_oat_relative_patcher.h | 10 +- compiler/linker/multi_oat_relative_patcher_test.cc | 10 +- compiler/linker/relative_patcher.cc | 8 +- compiler/linker/relative_patcher.h | 8 +- compiler/linker/relative_patcher_test.h | 18 +- compiler/linker/x86/relative_patcher_x86.cc | 8 +- compiler/linker/x86/relative_patcher_x86.h | 8 +- compiler/linker/x86/relative_patcher_x86_test.cc | 56 +++- compiler/linker/x86_64/relative_patcher_x86_64.cc | 8 +- compiler/linker/x86_64/relative_patcher_x86_64.h | 8 +- .../linker/x86_64/relative_patcher_x86_64_test.cc | 58 +++- compiler/oat_writer.cc | 96 ++++-- compiler/optimizing/builder.cc | 8 +- compiler/optimizing/code_generator.h | 17 + compiler/optimizing/code_generator_arm.cc | 256 ++++++++++++--- compiler/optimizing/code_generator_arm.h | 63 ++-- compiler/optimizing/code_generator_arm64.cc | 285 +++++++++++++--- compiler/optimizing/code_generator_arm64.h | 66 +++- compiler/optimizing/code_generator_mips.cc | 12 +- compiler/optimizing/code_generator_mips.h | 5 + compiler/optimizing/code_generator_mips64.cc | 12 +- compiler/optimizing/code_generator_mips64.h | 5 + compiler/optimizing/code_generator_x86.cc | 201 ++++++++++-- compiler/optimizing/code_generator_x86.h | 27 +- compiler/optimizing/code_generator_x86_64.cc | 181 +++++++++-- compiler/optimizing/code_generator_x86_64.h | 27 +- compiler/optimizing/dex_cache_array_fixups_arm.cc | 15 + compiler/optimizing/graph_visualizer.cc | 4 + compiler/optimizing/nodes.cc | 72 +++- compiler/optimizing/nodes.h | 179 +++++++++- compiler/optimizing/pc_relative_fixups_x86.cc | 9 + compiler/optimizing/sharpening.cc | 114 ++++++- compiler/optimizing/sharpening.h | 1 + compiler/utils/string_reference.h | 64 ++++ runtime/class_linker.cc | 17 + runtime/class_linker.h | 6 + runtime/intern_table.cc | 36 ++ runtime/intern_table.h | 26 ++ runtime/intern_table_test.cc | 43 ++- runtime/runtime.cc | 21 +- runtime/safe_map.h | 13 + runtime/utf.cc | 17 + runtime/utf.h | 1 + .../src/Main.java | 3 +- test/552-checker-sharpening/src/Main.java | 68 ++++ 53 files changed, 2332 insertions(+), 468 deletions(-) create mode 100644 compiler/utils/string_reference.h (limited to 'compiler/optimizing/graph_visualizer.cc') diff --git a/compiler/Android.mk b/compiler/Android.mk index e6ff8f600c..9a416e25a1 100644 --- a/compiler/Android.mk +++ b/compiler/Android.mk @@ -148,6 +148,7 @@ LIBART_COMPILER_SRC_FILES_x86_64 := \ LIBART_COMPILER_CFLAGS := LIBART_COMPILER_ENUM_OPERATOR_OUT_HEADER_FILES := \ + compiled_method.h \ dex/compiler_enums.h \ dex/dex_to_dex_compiler.h \ driver/compiler_driver.h \ diff --git a/compiler/compiled_method.h b/compiler/compiled_method.h index 58876200ca..acd508997d 100644 --- a/compiler/compiled_method.h +++ b/compiler/compiled_method.h @@ -18,6 +18,7 @@ #define ART_COMPILER_COMPILED_METHOD_H_ #include +#include #include #include @@ -160,15 +161,23 @@ using DefaultSrcMap = SrcMap>; enum LinkerPatchType { + kLinkerPatchRecordPosition, // Just record patch position for patchoat. kLinkerPatchMethod, kLinkerPatchCall, - kLinkerPatchCallRelative, // NOTE: Actual patching is instruction_set-dependent. + kLinkerPatchCallRelative, // NOTE: Actual patching is instruction_set-dependent. kLinkerPatchType, - kLinkerPatchDexCacheArray, // NOTE: Actual patching is instruction_set-dependent. + kLinkerPatchString, + kLinkerPatchStringRelative, // NOTE: Actual patching is instruction_set-dependent. + kLinkerPatchDexCacheArray, // NOTE: Actual patching is instruction_set-dependent. }; +std::ostream& operator<<(std::ostream& os, const LinkerPatchType& type); class LinkerPatch { public: + static LinkerPatch RecordPosition(size_t literal_offset) { + return LinkerPatch(literal_offset, kLinkerPatchRecordPosition, /* target_dex_file */ nullptr); + } + static LinkerPatch MethodPatch(size_t literal_offset, const DexFile* target_dex_file, uint32_t target_method_idx) { @@ -201,6 +210,24 @@ class LinkerPatch { return patch; } + static LinkerPatch StringPatch(size_t literal_offset, + const DexFile* target_dex_file, + uint32_t target_string_idx) { + LinkerPatch patch(literal_offset, kLinkerPatchString, target_dex_file); + patch.string_idx_ = target_string_idx; + return patch; + } + + static LinkerPatch RelativeStringPatch(size_t literal_offset, + const DexFile* target_dex_file, + uint32_t pc_insn_offset, + uint32_t target_string_idx) { + LinkerPatch patch(literal_offset, kLinkerPatchStringRelative, target_dex_file); + patch.string_idx_ = target_string_idx; + patch.pc_insn_offset_ = pc_insn_offset; + return patch; + } + static LinkerPatch DexCacheArrayPatch(size_t literal_offset, const DexFile* target_dex_file, uint32_t pc_insn_offset, @@ -224,7 +251,14 @@ class LinkerPatch { } bool IsPcRelative() const { - return Type() == kLinkerPatchCallRelative || Type() == kLinkerPatchDexCacheArray; + switch (Type()) { + case kLinkerPatchCallRelative: + case kLinkerPatchStringRelative: + case kLinkerPatchDexCacheArray: + return true; + default: + return false; + } } MethodReference TargetMethod() const { @@ -243,6 +277,16 @@ class LinkerPatch { return type_idx_; } + const DexFile* TargetStringDexFile() const { + DCHECK(patch_type_ == kLinkerPatchString || patch_type_ == kLinkerPatchStringRelative); + return target_dex_file_; + } + + uint32_t TargetStringIndex() const { + DCHECK(patch_type_ == kLinkerPatchString || patch_type_ == kLinkerPatchStringRelative); + return string_idx_; + } + const DexFile* TargetDexCacheDexFile() const { DCHECK(patch_type_ == kLinkerPatchDexCacheArray); return target_dex_file_; @@ -254,7 +298,7 @@ class LinkerPatch { } uint32_t PcInsnOffset() const { - DCHECK(patch_type_ == kLinkerPatchDexCacheArray); + DCHECK(patch_type_ == kLinkerPatchStringRelative || patch_type_ == kLinkerPatchDexCacheArray); return pc_insn_offset_; } @@ -277,9 +321,11 @@ class LinkerPatch { uint32_t cmp1_; // Used for relational operators. uint32_t method_idx_; // Method index for Call/Method patches. uint32_t type_idx_; // Type index for Type patches. + uint32_t string_idx_; // String index for String patches. uint32_t element_offset_; // Element offset in the dex cache arrays. static_assert(sizeof(method_idx_) == sizeof(cmp1_), "needed by relational operators"); static_assert(sizeof(type_idx_) == sizeof(cmp1_), "needed by relational operators"); + static_assert(sizeof(string_idx_) == sizeof(cmp1_), "needed by relational operators"); static_assert(sizeof(element_offset_) == sizeof(cmp1_), "needed by relational operators"); }; union { diff --git a/compiler/linker/arm/relative_patcher_thumb2.cc b/compiler/linker/arm/relative_patcher_thumb2.cc index c090dffc55..582ecb3bbf 100644 --- a/compiler/linker/arm/relative_patcher_thumb2.cc +++ b/compiler/linker/arm/relative_patcher_thumb2.cc @@ -56,10 +56,10 @@ void Thumb2RelativePatcher::PatchCall(std::vector* code, SetInsn32(code, literal_offset, value); } -void Thumb2RelativePatcher::PatchDexCacheReference(std::vector* code, - const LinkerPatch& patch, - uint32_t patch_offset, - uint32_t target_offset) { +void Thumb2RelativePatcher::PatchPcRelativeReference(std::vector* code, + const LinkerPatch& patch, + uint32_t patch_offset, + uint32_t target_offset) { uint32_t literal_offset = patch.LiteralOffset(); uint32_t pc_literal_offset = patch.PcInsnOffset(); uint32_t pc_base = patch_offset + (pc_literal_offset - literal_offset) + 4u /* PC adjustment */; diff --git a/compiler/linker/arm/relative_patcher_thumb2.h b/compiler/linker/arm/relative_patcher_thumb2.h index 0d903c0b41..d85739c51f 100644 --- a/compiler/linker/arm/relative_patcher_thumb2.h +++ b/compiler/linker/arm/relative_patcher_thumb2.h @@ -30,10 +30,10 @@ class Thumb2RelativePatcher FINAL : public ArmBaseRelativePatcher { uint32_t literal_offset, uint32_t patch_offset, uint32_t target_offset) OVERRIDE; - void PatchDexCacheReference(std::vector* code, - const LinkerPatch& patch, - uint32_t patch_offset, - uint32_t target_offset) OVERRIDE; + void PatchPcRelativeReference(std::vector* code, + const LinkerPatch& patch, + uint32_t patch_offset, + uint32_t target_offset) OVERRIDE; private: static std::vector CompileThunkCode(); diff --git a/compiler/linker/arm/relative_patcher_thumb2_test.cc b/compiler/linker/arm/relative_patcher_thumb2_test.cc index a259cda986..a8078e3049 100644 --- a/compiler/linker/arm/relative_patcher_thumb2_test.cc +++ b/compiler/linker/arm/relative_patcher_thumb2_test.cc @@ -30,6 +30,9 @@ class Thumb2RelativePatcherTest : public RelativePatcherTest { static const ArrayRef kCallCode; static const uint8_t kNopRawCode[]; static const ArrayRef kNopCode; + static const uint8_t kUnpatchedPcRelativeRawCode[]; + static const ArrayRef kUnpatchedPcRelativeCode; + static const uint32_t kPcInsnOffset; // Branches within range [-256, 256) can be created from these by adding the low 8 bits. static constexpr uint32_t kBlPlus0 = 0xf000f800; @@ -123,47 +126,9 @@ class Thumb2RelativePatcherTest : public RelativePatcherTest { return result; } - void TestDexCachereference(uint32_t dex_cache_arrays_begin, uint32_t element_offset) { - dex_cache_arrays_begin_ = dex_cache_arrays_begin; - static const uint8_t raw_code[] = { - 0x40, 0xf2, 0x00, 0x00, // MOVW r0, #0 (placeholder) - 0xc0, 0xf2, 0x00, 0x00, // MOVT r0, #0 (placeholder) - 0x78, 0x44, // ADD r0, pc - }; - constexpr uint32_t pc_insn_offset = 8u; - const ArrayRef code(raw_code); - LinkerPatch patches[] = { - LinkerPatch::DexCacheArrayPatch(0u, nullptr, pc_insn_offset, element_offset), - LinkerPatch::DexCacheArrayPatch(4u, nullptr, pc_insn_offset, element_offset), - }; - AddCompiledMethod(MethodRef(1u), code, ArrayRef(patches)); - Link(); - - uint32_t method1_offset = GetMethodOffset(1u); - uint32_t pc_base_offset = method1_offset + pc_insn_offset + 4u /* PC adjustment */; - uint32_t diff = dex_cache_arrays_begin_ + element_offset - pc_base_offset; - // Distribute the bits of the diff between the MOVW and MOVT: - uint32_t diffw = diff & 0xffffu; - uint32_t difft = diff >> 16; - uint32_t movw = 0xf2400000u | // MOVW r0, #0 (placeholder), - ((diffw & 0xf000u) << (16 - 12)) | // move imm4 from bits 12-15 to bits 16-19, - ((diffw & 0x0800u) << (26 - 11)) | // move imm from bit 11 to bit 26, - ((diffw & 0x0700u) << (12 - 8)) | // move imm3 from bits 8-10 to bits 12-14, - ((diffw & 0x00ffu)); // keep imm8 at bits 0-7. - uint32_t movt = 0xf2c00000u | // MOVT r0, #0 (placeholder), - ((difft & 0xf000u) << (16 - 12)) | // move imm4 from bits 12-15 to bits 16-19, - ((difft & 0x0800u) << (26 - 11)) | // move imm from bit 11 to bit 26, - ((difft & 0x0700u) << (12 - 8)) | // move imm3 from bits 8-10 to bits 12-14, - ((difft & 0x00ffu)); // keep imm8 at bits 0-7. - const uint8_t expected_code[] = { - static_cast(movw >> 16), static_cast(movw >> 24), - static_cast(movw >> 0), static_cast(movw >> 8), - static_cast(movt >> 16), static_cast(movt >> 24), - static_cast(movt >> 0), static_cast(movt >> 8), - 0x78, 0x44, - }; - EXPECT_TRUE(CheckLinkedMethod(MethodRef(1u), ArrayRef(expected_code))); - } + void TestDexCacheReference(uint32_t dex_cache_arrays_begin, uint32_t element_offset); + void TestStringReference(uint32_t string_offset); + void CheckPcRelativePatch(const ArrayRef& patches, uint32_t target_offset); }; const uint8_t Thumb2RelativePatcherTest::kCallRawCode[] = { @@ -178,6 +143,67 @@ const uint8_t Thumb2RelativePatcherTest::kNopRawCode[] = { const ArrayRef Thumb2RelativePatcherTest::kNopCode(kNopRawCode); +const uint8_t Thumb2RelativePatcherTest::kUnpatchedPcRelativeRawCode[] = { + 0x40, 0xf2, 0x00, 0x00, // MOVW r0, #0 (placeholder) + 0xc0, 0xf2, 0x00, 0x00, // MOVT r0, #0 (placeholder) + 0x78, 0x44, // ADD r0, pc +}; +const ArrayRef Thumb2RelativePatcherTest::kUnpatchedPcRelativeCode( + kUnpatchedPcRelativeRawCode); +const uint32_t Thumb2RelativePatcherTest::kPcInsnOffset = 8u; + +void Thumb2RelativePatcherTest::TestDexCacheReference(uint32_t dex_cache_arrays_begin, + uint32_t element_offset) { + dex_cache_arrays_begin_ = dex_cache_arrays_begin; + LinkerPatch patches[] = { + LinkerPatch::DexCacheArrayPatch(0u, nullptr, kPcInsnOffset, element_offset), + LinkerPatch::DexCacheArrayPatch(4u, nullptr, kPcInsnOffset, element_offset), + }; + CheckPcRelativePatch(ArrayRef(patches), + dex_cache_arrays_begin_ + element_offset); +} + +void Thumb2RelativePatcherTest::TestStringReference(uint32_t string_offset) { + constexpr uint32_t kStringIndex = 1u; + string_index_to_offset_map_.Put(kStringIndex, string_offset); + LinkerPatch patches[] = { + LinkerPatch::RelativeStringPatch(0u, nullptr, kPcInsnOffset, kStringIndex), + LinkerPatch::RelativeStringPatch(4u, nullptr, kPcInsnOffset, kStringIndex), + }; + CheckPcRelativePatch(ArrayRef(patches), string_offset); +} + +void Thumb2RelativePatcherTest::CheckPcRelativePatch(const ArrayRef& patches, + uint32_t target_offset) { + AddCompiledMethod(MethodRef(1u), kUnpatchedPcRelativeCode, ArrayRef(patches)); + Link(); + + uint32_t method1_offset = GetMethodOffset(1u); + uint32_t pc_base_offset = method1_offset + kPcInsnOffset + 4u /* PC adjustment */; + uint32_t diff = target_offset - pc_base_offset; + // Distribute the bits of the diff between the MOVW and MOVT: + uint32_t diffw = diff & 0xffffu; + uint32_t difft = diff >> 16; + uint32_t movw = 0xf2400000u | // MOVW r0, #0 (placeholder), + ((diffw & 0xf000u) << (16 - 12)) | // move imm4 from bits 12-15 to bits 16-19, + ((diffw & 0x0800u) << (26 - 11)) | // move imm from bit 11 to bit 26, + ((diffw & 0x0700u) << (12 - 8)) | // move imm3 from bits 8-10 to bits 12-14, + ((diffw & 0x00ffu)); // keep imm8 at bits 0-7. + uint32_t movt = 0xf2c00000u | // MOVT r0, #0 (placeholder), + ((difft & 0xf000u) << (16 - 12)) | // move imm4 from bits 12-15 to bits 16-19, + ((difft & 0x0800u) << (26 - 11)) | // move imm from bit 11 to bit 26, + ((difft & 0x0700u) << (12 - 8)) | // move imm3 from bits 8-10 to bits 12-14, + ((difft & 0x00ffu)); // keep imm8 at bits 0-7. + const uint8_t expected_code[] = { + static_cast(movw >> 16), static_cast(movw >> 24), + static_cast(movw >> 0), static_cast(movw >> 8), + static_cast(movt >> 16), static_cast(movt >> 24), + static_cast(movt >> 0), static_cast(movt >> 8), + 0x78, 0x44, + }; + EXPECT_TRUE(CheckLinkedMethod(MethodRef(1u), ArrayRef(expected_code))); +} + TEST_F(Thumb2RelativePatcherTest, CallSelf) { LinkerPatch patches[] = { LinkerPatch::RelativeCodePatch(0u, nullptr, 1u), @@ -366,23 +392,43 @@ TEST_F(Thumb2RelativePatcherTest, CallOtherJustTooFarBefore) { EXPECT_TRUE(CheckThunk(thunk_offset)); } -TEST_F(Thumb2RelativePatcherTest, DexCacheReferenceImm8) { - TestDexCachereference(0x00ff0000u, 0x00fcu); +TEST_F(Thumb2RelativePatcherTest, DexCacheReference1) { + TestDexCacheReference(0x00ff0000u, 0x00fcu); + ASSERT_LT(GetMethodOffset(1u), 0xfcu); +} + +TEST_F(Thumb2RelativePatcherTest, DexCacheReference2) { + TestDexCacheReference(0x02ff0000u, 0x05fcu); + ASSERT_LT(GetMethodOffset(1u), 0xfcu); +} + +TEST_F(Thumb2RelativePatcherTest, DexCacheReference3) { + TestDexCacheReference(0x08ff0000u, 0x08fcu); + ASSERT_LT(GetMethodOffset(1u), 0xfcu); +} + +TEST_F(Thumb2RelativePatcherTest, DexCacheReference4) { + TestDexCacheReference(0xd0ff0000u, 0x60fcu); + ASSERT_LT(GetMethodOffset(1u), 0xfcu); +} + +TEST_F(Thumb2RelativePatcherTest, StringReference1) { + TestStringReference(0x00ff00fcu); ASSERT_LT(GetMethodOffset(1u), 0xfcu); } -TEST_F(Thumb2RelativePatcherTest, DexCacheReferenceImm3) { - TestDexCachereference(0x02ff0000u, 0x05fcu); +TEST_F(Thumb2RelativePatcherTest, StringReference2) { + TestStringReference(0x02ff05fcu); ASSERT_LT(GetMethodOffset(1u), 0xfcu); } -TEST_F(Thumb2RelativePatcherTest, DexCacheReferenceImm) { - TestDexCachereference(0x08ff0000u, 0x08fcu); +TEST_F(Thumb2RelativePatcherTest, StringReference3) { + TestStringReference(0x08ff08fcu); ASSERT_LT(GetMethodOffset(1u), 0xfcu); } -TEST_F(Thumb2RelativePatcherTest, DexCacheReferenceimm4) { - TestDexCachereference(0xd0ff0000u, 0x60fcu); +TEST_F(Thumb2RelativePatcherTest, StringReference4) { + TestStringReference(0xd0ff60fcu); ASSERT_LT(GetMethodOffset(1u), 0xfcu); } diff --git a/compiler/linker/arm64/relative_patcher_arm64.cc b/compiler/linker/arm64/relative_patcher_arm64.cc index a81c85c707..0549327e7a 100644 --- a/compiler/linker/arm64/relative_patcher_arm64.cc +++ b/compiler/linker/arm64/relative_patcher_arm64.cc @@ -28,6 +28,16 @@ namespace art { namespace linker { +namespace { + +inline bool IsAdrpPatch(const LinkerPatch& patch) { + LinkerPatchType type = patch.Type(); + return (type == kLinkerPatchStringRelative || type == kLinkerPatchDexCacheArray) && + patch.LiteralOffset() == patch.PcInsnOffset(); +} + +} // anonymous namespace + Arm64RelativePatcher::Arm64RelativePatcher(RelativePatcherTargetProvider* provider, const Arm64InstructionSetFeatures* features) : ArmBaseRelativePatcher(provider, kArm64, CompileThunkCode(), @@ -61,8 +71,7 @@ uint32_t Arm64RelativePatcher::ReserveSpace(uint32_t offset, size_t num_adrp = 0u; DCHECK(compiled_method != nullptr); for (const LinkerPatch& patch : compiled_method->GetPatches()) { - if (patch.Type() == kLinkerPatchDexCacheArray && - patch.LiteralOffset() == patch.PcInsnOffset()) { // ADRP patch + if (IsAdrpPatch(patch)) { ++num_adrp; } } @@ -78,8 +87,7 @@ uint32_t Arm64RelativePatcher::ReserveSpace(uint32_t offset, uint32_t thunk_offset = compiled_method->AlignCode(quick_code_offset + code.size()); DCHECK(compiled_method != nullptr); for (const LinkerPatch& patch : compiled_method->GetPatches()) { - if (patch.Type() == kLinkerPatchDexCacheArray && - patch.LiteralOffset() == patch.PcInsnOffset()) { // ADRP patch + if (IsAdrpPatch(patch)) { uint32_t patch_offset = quick_code_offset + patch.LiteralOffset(); if (NeedsErratum843419Thunk(code, patch.LiteralOffset(), patch_offset)) { adrp_thunk_locations_.emplace_back(patch_offset, thunk_offset); @@ -151,10 +159,10 @@ void Arm64RelativePatcher::PatchCall(std::vector* code, SetInsn(code, literal_offset, insn); } -void Arm64RelativePatcher::PatchDexCacheReference(std::vector* code, - const LinkerPatch& patch, - uint32_t patch_offset, - uint32_t target_offset) { +void Arm64RelativePatcher::PatchPcRelativeReference(std::vector* code, + const LinkerPatch& patch, + uint32_t patch_offset, + uint32_t target_offset) { DCHECK_EQ(patch_offset & 3u, 0u); DCHECK_EQ(target_offset & 3u, 0u); uint32_t literal_offset = patch.LiteralOffset(); @@ -199,8 +207,15 @@ void Arm64RelativePatcher::PatchDexCacheReference(std::vector* code, // Write the new ADRP (or B to the erratum 843419 thunk). SetInsn(code, literal_offset, insn); } else { - // LDR 32-bit or 64-bit with imm12 == 0 (unset). - DCHECK_EQ(insn & 0xbffffc00, 0xb9400000) << insn; + if ((insn & 0xfffffc00) == 0x91000000) { + // ADD immediate, 64-bit with imm12 == 0 (unset). + DCHECK(patch.Type() == kLinkerPatchStringRelative) << patch.Type(); + shift = 0u; // No shift for ADD. + } else { + // LDR 32-bit or 64-bit with imm12 == 0 (unset). + DCHECK(patch.Type() == kLinkerPatchDexCacheArray) << patch.Type(); + DCHECK_EQ(insn & 0xbffffc00, 0xb9400000) << std::hex << insn; + } if (kIsDebugBuild) { uint32_t adrp = GetInsn(code, pc_insn_offset); if ((adrp & 0x9f000000u) != 0x90000000u) { @@ -263,7 +278,7 @@ bool Arm64RelativePatcher::NeedsErratum843419Thunk(ArrayRef code, DCHECK_EQ(patch_offset & 0x3u, 0u); if ((patch_offset & 0xff8) == 0xff8) { // ...ff8 or ...ffc uint32_t adrp = GetInsn(code, literal_offset); - DCHECK_EQ(adrp & 0xff000000, 0x90000000); + DCHECK_EQ(adrp & 0x9f000000, 0x90000000); uint32_t next_offset = patch_offset + 4u; uint32_t next_insn = GetInsn(code, literal_offset + 4u); @@ -277,6 +292,14 @@ bool Arm64RelativePatcher::NeedsErratum843419Thunk(ArrayRef code, return false; } + // And since kLinkerPatchStringRelative is using the result of the ADRP for an ADD immediate, + // check for that as well. We generalize a bit to include ADD/ADDS/SUB/SUBS immediate that + // either uses the ADRP destination or stores the result to a different register. + if ((next_insn & 0x1f000000) == 0x11000000 && + ((((next_insn >> 5) ^ adrp) & 0x1f) == 0 || ((next_insn ^ adrp) & 0x1f) != 0)) { + return false; + } + // LDR ,