diff options
author | 2017-05-15 13:39:18 +0100 | |
---|---|---|
committer | 2017-06-07 15:39:24 +0100 | |
commit | 0eb882bfc5d260e8014c26adfda11602065aa5d8 (patch) | |
tree | e66dbebfb1e9a254c20954a2f2f98541aebfd5af | |
parent | b5f5d746ac3f2c3088292395603cb1470e7749d2 (diff) |
Use ArtMethod* .bss entries for HInvokeStaticOrDirect.
Test: m test-art-host-gtest
Test: testrunner.py --host
Test: testrunner.py --target
Test: Nexus 6P boots.
Test: Build aosp_mips64-userdebug.
Bug: 30627598
Change-Id: I0e54fdd2e91e983d475b7a04d40815ba89ae3d4f
56 files changed, 1187 insertions, 1129 deletions
diff --git a/compiler/Android.bp b/compiler/Android.bp index 307a42cbba..a1269dcaf9 100644 --- a/compiler/Android.bp +++ b/compiler/Android.bp @@ -110,7 +110,6 @@ art_cc_defaults { "optimizing/code_generator_vector_arm.cc", "optimizing/code_generator_arm_vixl.cc", "optimizing/code_generator_vector_arm_vixl.cc", - "optimizing/dex_cache_array_fixups_arm.cc", "optimizing/instruction_simplifier_arm.cc", "optimizing/instruction_simplifier_shared.cc", "optimizing/intrinsics_arm.cc", @@ -145,7 +144,6 @@ art_cc_defaults { "linker/mips/relative_patcher_mips.cc", "optimizing/code_generator_mips.cc", "optimizing/code_generator_vector_mips.cc", - "optimizing/dex_cache_array_fixups_mips.cc", "optimizing/intrinsics_mips.cc", "optimizing/pc_relative_fixups_mips.cc", "utils/mips/assembler_mips.cc", @@ -342,6 +340,7 @@ art_cc_test { "image_test.cc", "image_write_read_test.cc", "jni/jni_compiler_test.cc", + "linker/method_bss_mapping_encoder_test.cc", "linker/multi_oat_relative_patcher_test.cc", "linker/output_stream_test.cc", "oat_test.cc", diff --git a/compiler/compiled_method.h b/compiler/compiled_method.h index 0ca23a5c50..761e9e19a8 100644 --- a/compiler/compiled_method.h +++ b/compiler/compiled_method.h @@ -120,13 +120,13 @@ class LinkerPatch { // patch_type_ as an uintN_t and do explicit static_cast<>s. enum class Type : uint8_t { kMethodRelative, // NOTE: Actual patching is instruction_set-dependent. + kMethodBssEntry, // NOTE: Actual patching is instruction_set-dependent. kCall, kCallRelative, // NOTE: Actual patching is instruction_set-dependent. kTypeRelative, // NOTE: Actual patching is instruction_set-dependent. kTypeBssEntry, // NOTE: Actual patching is instruction_set-dependent. kStringRelative, // NOTE: Actual patching is instruction_set-dependent. kStringBssEntry, // NOTE: Actual patching is instruction_set-dependent. - kDexCacheArray, // NOTE: Actual patching is instruction_set-dependent. kBakerReadBarrierBranch, // NOTE: Actual patching is instruction_set-dependent. }; @@ -140,6 +140,16 @@ class LinkerPatch { return patch; } + static LinkerPatch MethodBssEntryPatch(size_t literal_offset, + const DexFile* target_dex_file, + uint32_t pc_insn_offset, + uint32_t target_method_idx) { + LinkerPatch patch(literal_offset, Type::kMethodBssEntry, target_dex_file); + patch.method_idx_ = target_method_idx; + patch.pc_insn_offset_ = pc_insn_offset; + return patch; + } + static LinkerPatch CodePatch(size_t literal_offset, const DexFile* target_dex_file, uint32_t target_method_idx) { @@ -196,16 +206,6 @@ class LinkerPatch { return patch; } - static LinkerPatch DexCacheArrayPatch(size_t literal_offset, - const DexFile* target_dex_file, - uint32_t pc_insn_offset, - uint32_t element_offset) { - LinkerPatch patch(literal_offset, Type::kDexCacheArray, target_dex_file); - patch.pc_insn_offset_ = pc_insn_offset; - patch.element_offset_ = element_offset; - return patch; - } - static LinkerPatch BakerReadBarrierBranchPatch(size_t literal_offset, uint32_t custom_value1 = 0u, uint32_t custom_value2 = 0u) { @@ -229,12 +229,12 @@ class LinkerPatch { bool IsPcRelative() const { switch (GetType()) { case Type::kMethodRelative: + case Type::kMethodBssEntry: case Type::kCallRelative: case Type::kTypeRelative: case Type::kTypeBssEntry: case Type::kStringRelative: case Type::kStringBssEntry: - case Type::kDexCacheArray: case Type::kBakerReadBarrierBranch: return true; default: @@ -244,6 +244,7 @@ class LinkerPatch { MethodReference TargetMethod() const { DCHECK(patch_type_ == Type::kMethodRelative || + patch_type_ == Type::kMethodBssEntry || patch_type_ == Type::kCall || patch_type_ == Type::kCallRelative); return MethodReference(target_dex_file_, method_idx_); @@ -273,23 +274,13 @@ class LinkerPatch { return dex::StringIndex(string_idx_); } - const DexFile* TargetDexCacheDexFile() const { - DCHECK(patch_type_ == Type::kDexCacheArray); - return target_dex_file_; - } - - size_t TargetDexCacheElementOffset() const { - DCHECK(patch_type_ == Type::kDexCacheArray); - return element_offset_; - } - uint32_t PcInsnOffset() const { DCHECK(patch_type_ == Type::kMethodRelative || + patch_type_ == Type::kMethodBssEntry || patch_type_ == Type::kTypeRelative || patch_type_ == Type::kTypeBssEntry || patch_type_ == Type::kStringRelative || - patch_type_ == Type::kStringBssEntry || - patch_type_ == Type::kDexCacheArray); + patch_type_ == Type::kStringBssEntry); return pc_insn_offset_; } @@ -324,12 +315,10 @@ class LinkerPatch { 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. uint32_t baker_custom_value1_; 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"); static_assert(sizeof(baker_custom_value1_) == sizeof(cmp1_), "needed by relational operators"); }; union { diff --git a/compiler/compiled_method_test.cc b/compiler/compiled_method_test.cc index 72b2282ade..f4a72cf2cc 100644 --- a/compiler/compiled_method_test.cc +++ b/compiler/compiled_method_test.cc @@ -58,6 +58,14 @@ TEST(CompiledMethod, LinkerPatchOperators) { LinkerPatch::RelativeMethodPatch(16u, dex_file2, 3001u, 1000u), LinkerPatch::RelativeMethodPatch(16u, dex_file2, 3000u, 1001u), LinkerPatch::RelativeMethodPatch(16u, dex_file2, 3001u, 1001u), + LinkerPatch::MethodBssEntryPatch(16u, dex_file1, 3000u, 1000u), + LinkerPatch::MethodBssEntryPatch(16u, dex_file1, 3001u, 1000u), + LinkerPatch::MethodBssEntryPatch(16u, dex_file1, 3000u, 1001u), + LinkerPatch::MethodBssEntryPatch(16u, dex_file1, 3001u, 1001u), + LinkerPatch::MethodBssEntryPatch(16u, dex_file2, 3000u, 1000u), + LinkerPatch::MethodBssEntryPatch(16u, dex_file2, 3001u, 1000u), + LinkerPatch::MethodBssEntryPatch(16u, dex_file2, 3000u, 1001u), + LinkerPatch::MethodBssEntryPatch(16u, dex_file2, 3001u, 1001u), LinkerPatch::CodePatch(16u, dex_file1, 1000u), LinkerPatch::CodePatch(16u, dex_file1, 1001u), LinkerPatch::CodePatch(16u, dex_file2, 1000u), @@ -98,14 +106,6 @@ TEST(CompiledMethod, LinkerPatchOperators) { LinkerPatch::StringBssEntryPatch(16u, dex_file2, 3001u, 1000u), LinkerPatch::StringBssEntryPatch(16u, dex_file2, 3000u, 1001u), LinkerPatch::StringBssEntryPatch(16u, dex_file2, 3001u, 1001u), - LinkerPatch::DexCacheArrayPatch(16u, dex_file1, 3000u, 2000u), - LinkerPatch::DexCacheArrayPatch(16u, dex_file1, 3001u, 2000u), - LinkerPatch::DexCacheArrayPatch(16u, dex_file1, 3000u, 2001u), - LinkerPatch::DexCacheArrayPatch(16u, dex_file1, 3001u, 2001u), - LinkerPatch::DexCacheArrayPatch(16u, dex_file2, 3000u, 2000u), - LinkerPatch::DexCacheArrayPatch(16u, dex_file2, 3001u, 2000u), - LinkerPatch::DexCacheArrayPatch(16u, dex_file2, 3000u, 2001u), - LinkerPatch::DexCacheArrayPatch(16u, dex_file2, 3001u, 2001u), LinkerPatch::BakerReadBarrierBranchPatch(16u, 0u, 0u), LinkerPatch::BakerReadBarrierBranchPatch(16u, 0u, 1u), LinkerPatch::BakerReadBarrierBranchPatch(16u, 1u, 0u), @@ -119,6 +119,14 @@ TEST(CompiledMethod, LinkerPatchOperators) { LinkerPatch::RelativeMethodPatch(32u, dex_file2, 3001u, 1000u), LinkerPatch::RelativeMethodPatch(32u, dex_file2, 3000u, 1001u), LinkerPatch::RelativeMethodPatch(32u, dex_file2, 3001u, 1001u), + LinkerPatch::MethodBssEntryPatch(32u, dex_file1, 3000u, 1000u), + LinkerPatch::MethodBssEntryPatch(32u, dex_file1, 3001u, 1000u), + LinkerPatch::MethodBssEntryPatch(32u, dex_file1, 3000u, 1001u), + LinkerPatch::MethodBssEntryPatch(32u, dex_file1, 3001u, 1001u), + LinkerPatch::MethodBssEntryPatch(32u, dex_file2, 3000u, 1000u), + LinkerPatch::MethodBssEntryPatch(32u, dex_file2, 3001u, 1000u), + LinkerPatch::MethodBssEntryPatch(32u, dex_file2, 3000u, 1001u), + LinkerPatch::MethodBssEntryPatch(32u, dex_file2, 3001u, 1001u), LinkerPatch::CodePatch(32u, dex_file1, 1000u), LinkerPatch::CodePatch(32u, dex_file1, 1001u), LinkerPatch::CodePatch(32u, dex_file2, 1000u), @@ -159,14 +167,6 @@ TEST(CompiledMethod, LinkerPatchOperators) { LinkerPatch::StringBssEntryPatch(32u, dex_file2, 3001u, 1000u), LinkerPatch::StringBssEntryPatch(32u, dex_file2, 3000u, 1001u), LinkerPatch::StringBssEntryPatch(32u, dex_file2, 3001u, 1001u), - LinkerPatch::DexCacheArrayPatch(32u, dex_file1, 3000u, 2000u), - LinkerPatch::DexCacheArrayPatch(32u, dex_file1, 3001u, 2000u), - LinkerPatch::DexCacheArrayPatch(32u, dex_file1, 3000u, 2001u), - LinkerPatch::DexCacheArrayPatch(32u, dex_file1, 3001u, 2001u), - LinkerPatch::DexCacheArrayPatch(32u, dex_file2, 3000u, 2000u), - LinkerPatch::DexCacheArrayPatch(32u, dex_file2, 3001u, 2000u), - LinkerPatch::DexCacheArrayPatch(32u, dex_file2, 3000u, 2001u), - LinkerPatch::DexCacheArrayPatch(32u, dex_file2, 3001u, 2001u), LinkerPatch::BakerReadBarrierBranchPatch(32u, 0u, 0u), LinkerPatch::BakerReadBarrierBranchPatch(32u, 0u, 1u), LinkerPatch::BakerReadBarrierBranchPatch(32u, 1u, 0u), diff --git a/compiler/elf_builder.h b/compiler/elf_builder.h index 7c02384ff2..2ef9fa1ccb 100644 --- a/compiler/elf_builder.h +++ b/compiler/elf_builder.h @@ -670,6 +670,7 @@ class ElfBuilder FINAL { Elf_Word rodata_size, Elf_Word text_size, Elf_Word bss_size, + Elf_Word bss_methods_offset, Elf_Word bss_roots_offset) { std::string soname(elf_file_path); size_t directory_separator_pos = soname.rfind('/'); @@ -715,9 +716,18 @@ class ElfBuilder FINAL { Elf_Word bss_index = rodata_index + 1u + (text_size != 0 ? 1u : 0u); Elf_Word oatbss = dynstr_.Add("oatbss"); dynsym_.Add(oatbss, bss_index, bss_address, bss_roots_offset, STB_GLOBAL, STT_OBJECT); + DCHECK_LE(bss_methods_offset, bss_roots_offset); + DCHECK_LE(bss_roots_offset, bss_size); + // Add a symbol marking the start of the methods part of the .bss, if not empty. + if (bss_methods_offset != bss_roots_offset) { + Elf_Word bss_methods_address = bss_address + bss_methods_offset; + Elf_Word bss_methods_size = bss_roots_offset - bss_methods_offset; + Elf_Word oatbssroots = dynstr_.Add("oatbssmethods"); + dynsym_.Add( + oatbssroots, bss_index, bss_methods_address, bss_methods_size, STB_GLOBAL, STT_OBJECT); + } // Add a symbol marking the start of the GC roots part of the .bss, if not empty. if (bss_roots_offset != bss_size) { - DCHECK_LT(bss_roots_offset, bss_size); Elf_Word bss_roots_address = bss_address + bss_roots_offset; Elf_Word bss_roots_size = bss_size - bss_roots_offset; Elf_Word oatbssroots = dynstr_.Add("oatbssroots"); diff --git a/compiler/elf_writer.h b/compiler/elf_writer.h index 7baae527ff..a8a5bc32b7 100644 --- a/compiler/elf_writer.h +++ b/compiler/elf_writer.h @@ -55,6 +55,7 @@ class ElfWriter { virtual void PrepareDynamicSection(size_t rodata_size, size_t text_size, size_t bss_size, + size_t bss_methods_offset, size_t bss_roots_offset) = 0; virtual void PrepareDebugInfo(const ArrayRef<const debug::MethodDebugInfo>& method_infos) = 0; virtual OutputStream* StartRoData() = 0; diff --git a/compiler/elf_writer_quick.cc b/compiler/elf_writer_quick.cc index 738f5a2b29..38bd9bec23 100644 --- a/compiler/elf_writer_quick.cc +++ b/compiler/elf_writer_quick.cc @@ -97,6 +97,7 @@ class ElfWriterQuick FINAL : public ElfWriter { void PrepareDynamicSection(size_t rodata_size, size_t text_size, size_t bss_size, + size_t bss_methods_offset, size_t bss_roots_offset) OVERRIDE; void PrepareDebugInfo(const ArrayRef<const debug::MethodDebugInfo>& method_infos) OVERRIDE; OutputStream* StartRoData() OVERRIDE; @@ -178,6 +179,7 @@ template <typename ElfTypes> void ElfWriterQuick<ElfTypes>::PrepareDynamicSection(size_t rodata_size, size_t text_size, size_t bss_size, + size_t bss_methods_offset, size_t bss_roots_offset) { DCHECK_EQ(rodata_size_, 0u); rodata_size_ = rodata_size; @@ -189,6 +191,7 @@ void ElfWriterQuick<ElfTypes>::PrepareDynamicSection(size_t rodata_size, rodata_size_, text_size_, bss_size_, + bss_methods_offset, bss_roots_offset); } diff --git a/compiler/image_test.h b/compiler/image_test.h index 2f15ff4815..394b7f1818 100644 --- a/compiler/image_test.h +++ b/compiler/image_test.h @@ -311,6 +311,7 @@ inline void CompilationHelper::Compile(CompilerDriver* driver, elf_writer->PrepareDynamicSection(rodata_size, text_size, oat_writer->GetBssSize(), + oat_writer->GetBssMethodsOffset(), oat_writer->GetBssRootsOffset()); writer->UpdateOatFileLayout(i, diff --git a/compiler/image_writer.h b/compiler/image_writer.h index 2283b39773..3db4fab128 100644 --- a/compiler/image_writer.h +++ b/compiler/image_writer.h @@ -106,19 +106,6 @@ class ImageWriter FINAL { ArtMethod* GetImageMethodAddress(ArtMethod* method) REQUIRES_SHARED(Locks::mutator_lock_); - template <typename PtrType> - PtrType GetDexCacheArrayElementImageAddress(const DexFile* dex_file, uint32_t offset) - const REQUIRES_SHARED(Locks::mutator_lock_) { - auto oat_it = dex_file_oat_index_map_.find(dex_file); - DCHECK(oat_it != dex_file_oat_index_map_.end()); - const ImageInfo& image_info = GetImageInfo(oat_it->second); - auto it = image_info.dex_cache_array_starts_.find(dex_file); - DCHECK(it != image_info.dex_cache_array_starts_.end()); - return reinterpret_cast<PtrType>( - image_info.image_begin_ + image_info.bin_slot_offsets_[kBinDexCacheArray] + - it->second + offset); - } - size_t GetOatFileOffset(size_t oat_index) const { return GetImageInfo(oat_index).oat_offset_; } diff --git a/compiler/linker/arm64/relative_patcher_arm64.cc b/compiler/linker/arm64/relative_patcher_arm64.cc index 117684a66b..bc21607c5b 100644 --- a/compiler/linker/arm64/relative_patcher_arm64.cc +++ b/compiler/linker/arm64/relative_patcher_arm64.cc @@ -59,11 +59,11 @@ inline bool IsAdrpPatch(const LinkerPatch& patch) { case LinkerPatch::Type::kBakerReadBarrierBranch: return false; case LinkerPatch::Type::kMethodRelative: + case LinkerPatch::Type::kMethodBssEntry: case LinkerPatch::Type::kTypeRelative: case LinkerPatch::Type::kTypeBssEntry: case LinkerPatch::Type::kStringRelative: case LinkerPatch::Type::kStringBssEntry: - case LinkerPatch::Type::kDexCacheArray: return patch.LiteralOffset() == patch.PcInsnOffset(); } } @@ -251,20 +251,20 @@ void Arm64RelativePatcher::PatchPcRelativeReference(std::vector<uint8_t>* code, // ADD immediate, 64-bit with imm12 == 0 (unset). if (!kEmitCompilerReadBarrier) { DCHECK(patch.GetType() == LinkerPatch::Type::kMethodRelative || - patch.GetType() == LinkerPatch::Type::kStringRelative || - patch.GetType() == LinkerPatch::Type::kTypeRelative) << patch.GetType(); + patch.GetType() == LinkerPatch::Type::kTypeRelative || + patch.GetType() == LinkerPatch::Type::kStringRelative) << patch.GetType(); } else { // With the read barrier (non-Baker) enabled, it could be kStringBssEntry or kTypeBssEntry. DCHECK(patch.GetType() == LinkerPatch::Type::kMethodRelative || - patch.GetType() == LinkerPatch::Type::kStringRelative || patch.GetType() == LinkerPatch::Type::kTypeRelative || - patch.GetType() == LinkerPatch::Type::kStringBssEntry || - patch.GetType() == LinkerPatch::Type::kTypeBssEntry) << patch.GetType(); + patch.GetType() == LinkerPatch::Type::kStringRelative || + patch.GetType() == LinkerPatch::Type::kTypeBssEntry || + patch.GetType() == LinkerPatch::Type::kStringBssEntry) << patch.GetType(); } shift = 0u; // No shift for ADD. } else { // LDR/STR 32-bit or 64-bit with imm12 == 0 (unset). - DCHECK(patch.GetType() == LinkerPatch::Type::kDexCacheArray || + DCHECK(patch.GetType() == LinkerPatch::Type::kMethodBssEntry || patch.GetType() == LinkerPatch::Type::kTypeBssEntry || patch.GetType() == LinkerPatch::Type::kStringBssEntry) << patch.GetType(); DCHECK_EQ(insn & 0xbfbffc00, 0xb9000000) << std::hex << insn; diff --git a/compiler/linker/method_bss_mapping_encoder.h b/compiler/linker/method_bss_mapping_encoder.h new file mode 100644 index 0000000000..b2922ec6d2 --- /dev/null +++ b/compiler/linker/method_bss_mapping_encoder.h @@ -0,0 +1,79 @@ +/* + * 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_COMPILER_LINKER_METHOD_BSS_MAPPING_ENCODER_H_ +#define ART_COMPILER_LINKER_METHOD_BSS_MAPPING_ENCODER_H_ + +#include "base/enums.h" +#include "base/logging.h" +#include "dex_file.h" +#include "method_bss_mapping.h" + +namespace art { +namespace linker { + +// Helper class for encoding compressed MethodBssMapping. +class MethodBssMappingEncoder { + public: + explicit MethodBssMappingEncoder(PointerSize pointer_size) + : pointer_size_(static_cast<size_t>(pointer_size)) { + entry_.method_index = DexFile::kDexNoIndex16; + entry_.index_mask = 0u; + entry_.bss_offset = static_cast<uint32_t>(-1); + } + + // Try to merge the next method_index -> bss_offset mapping into the current entry. + // Return true on success, false on failure. + bool TryMerge(uint32_t method_index, uint32_t bss_offset) { + DCHECK_NE(method_index, entry_.method_index); + if (entry_.bss_offset + pointer_size_ != bss_offset) { + return false; + } + uint32_t diff = method_index - entry_.method_index; + if (diff > 16u) { + return false; + } + if ((entry_.index_mask & ~(static_cast<uint32_t>(-1) << diff)) != 0u) { + return false; + } + entry_.method_index = method_index; + // Insert the bit indicating the method index we've just overwritten + // and shift bits indicating method indexes before that. + entry_.index_mask = dchecked_integral_cast<uint16_t>( + (static_cast<uint32_t>(entry_.index_mask) | 0x10000u) >> diff); + entry_.bss_offset = bss_offset; + return true; + } + + void Reset(uint32_t method_index, uint32_t bss_offset) { + entry_.method_index = method_index; + entry_.index_mask = 0u; + entry_.bss_offset = bss_offset; + } + + MethodBssMappingEntry GetEntry() { + return entry_; + } + + private: + size_t pointer_size_; + MethodBssMappingEntry entry_; +}; + +} // namespace linker +} // namespace art + +#endif // ART_COMPILER_LINKER_METHOD_BSS_MAPPING_ENCODER_H_ diff --git a/compiler/linker/method_bss_mapping_encoder_test.cc b/compiler/linker/method_bss_mapping_encoder_test.cc new file mode 100644 index 0000000000..1240389bef --- /dev/null +++ b/compiler/linker/method_bss_mapping_encoder_test.cc @@ -0,0 +1,50 @@ +/* + * 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 "method_bss_mapping_encoder.h" + +#include "gtest/gtest.h" + +namespace art { +namespace linker { + +TEST(MethodBssMappingEncoder, TryMerge) { + for (PointerSize pointer_size : {PointerSize::k32, PointerSize::k64}) { + size_t raw_pointer_size = static_cast<size_t>(pointer_size); + MethodBssMappingEncoder encoder(pointer_size); + encoder.Reset(1u, 0u); + ASSERT_FALSE(encoder.TryMerge(5u, raw_pointer_size + 1)); // Wrong bss_offset difference. + ASSERT_FALSE(encoder.TryMerge(18u, raw_pointer_size)); // Method index out of range. + ASSERT_TRUE(encoder.TryMerge(5u, raw_pointer_size)); + ASSERT_TRUE(encoder.GetEntry().CoversIndex(1u)); + ASSERT_TRUE(encoder.GetEntry().CoversIndex(5u)); + ASSERT_FALSE(encoder.GetEntry().CoversIndex(17u)); + ASSERT_FALSE(encoder.TryMerge(17u, 2 * raw_pointer_size + 1)); // Wrong bss_offset difference. + ASSERT_FALSE(encoder.TryMerge(18u, 2 * raw_pointer_size)); // Method index out of range. + ASSERT_TRUE(encoder.TryMerge(17u, 2 * raw_pointer_size)); + ASSERT_TRUE(encoder.GetEntry().CoversIndex(1u)); + ASSERT_TRUE(encoder.GetEntry().CoversIndex(5u)); + ASSERT_TRUE(encoder.GetEntry().CoversIndex(17u)); + ASSERT_EQ(0u, encoder.GetEntry().GetBssOffset(1u, raw_pointer_size)); + ASSERT_EQ(raw_pointer_size, encoder.GetEntry().GetBssOffset(5u, raw_pointer_size)); + ASSERT_EQ(2 * raw_pointer_size, encoder.GetEntry().GetBssOffset(17u, raw_pointer_size)); + ASSERT_EQ(0x0011u, encoder.GetEntry().index_mask); + ASSERT_FALSE(encoder.TryMerge(18u, 2 * raw_pointer_size)); // Method index out of range. + } +} + +} // namespace linker +} // namespace art diff --git a/compiler/linker/mips/relative_patcher_mips.cc b/compiler/linker/mips/relative_patcher_mips.cc index 8da530f7cc..d99d237a23 100644 --- a/compiler/linker/mips/relative_patcher_mips.cc +++ b/compiler/linker/mips/relative_patcher_mips.cc @@ -50,7 +50,6 @@ void MipsRelativePatcher::PatchPcRelativeReference(std::vector<uint8_t>* code, uint32_t anchor_literal_offset = patch.PcInsnOffset(); uint32_t literal_offset = patch.LiteralOffset(); uint32_t literal_low_offset; - bool dex_cache_array = (patch.GetType() == LinkerPatch::Type::kDexCacheArray); // Perform basic sanity checks and initialize `literal_low_offset` to point // to the instruction containing the 16 least significant bits of the @@ -72,16 +71,8 @@ void MipsRelativePatcher::PatchPcRelativeReference(std::vector<uint8_t>* code, DCHECK_GE(code->size(), 16u); DCHECK_LE(literal_offset, code->size() - 12u); DCHECK_GE(literal_offset, 4u); - // The NAL instruction may not precede immediately as the PC+0 value may - // come from HMipsComputeBaseMethodAddress. - if (dex_cache_array) { - DCHECK_EQ(literal_offset + 4u, anchor_literal_offset); - // NAL - DCHECK_EQ((*code)[literal_offset - 4], 0x00); - DCHECK_EQ((*code)[literal_offset - 3], 0x00); - DCHECK_EQ((*code)[literal_offset - 2], 0x10); - DCHECK_EQ((*code)[literal_offset - 1], 0x04); - } + // 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); @@ -90,10 +81,6 @@ void MipsRelativePatcher::PatchPcRelativeReference(std::vector<uint8_t>* code, // ADDU reg, reg, reg2 DCHECK_EQ((*code)[literal_offset + 4], 0x21); DCHECK_EQ(((*code)[literal_offset + 5] & 0x07), 0x00); - if (dex_cache_array) { - // reg2 is either RA or from HMipsComputeBaseMethodAddress. - DCHECK_EQ(((*code)[literal_offset + 6] & 0x1F), 0x1F); - } DCHECK_EQ(((*code)[literal_offset + 7] & 0xFC), 0x00); // instr reg(s), offset_low DCHECK_EQ((*code)[literal_offset + 8], 0x78); @@ -104,9 +91,6 @@ void MipsRelativePatcher::PatchPcRelativeReference(std::vector<uint8_t>* code, // Apply patch. uint32_t anchor_offset = patch_offset - literal_offset + anchor_literal_offset; uint32_t diff = target_offset - anchor_offset; - if (dex_cache_array && !is_r6) { - diff += kDexCacheArrayLwOffset; - } diff += (diff & 0x8000) << 1; // Account for sign extension in "instr reg(s), offset_low". // LUI reg, offset_high / AUIPC reg, offset_high diff --git a/compiler/linker/mips/relative_patcher_mips.h b/compiler/linker/mips/relative_patcher_mips.h index 852a345aa6..0b74bd33a4 100644 --- a/compiler/linker/mips/relative_patcher_mips.h +++ b/compiler/linker/mips/relative_patcher_mips.h @@ -46,9 +46,6 @@ class MipsRelativePatcher FINAL : public RelativePatcher { uint32_t patch_offset) OVERRIDE; private: - // We'll maximize the range of a single load instruction for dex cache array accesses - // by aligning offset -32768 with the offset of the first used element. - static constexpr uint32_t kDexCacheArrayLwOffset = 0x8000; bool is_r6; DISALLOW_COPY_AND_ASSIGN(MipsRelativePatcher); diff --git a/compiler/linker/mips/relative_patcher_mips_test.cc b/compiler/linker/mips/relative_patcher_mips_test.cc index 961b31266f..49af7c614b 100644 --- a/compiler/linker/mips/relative_patcher_mips_test.cc +++ b/compiler/linker/mips/relative_patcher_mips_test.cc @@ -61,7 +61,6 @@ void MipsRelativePatcherTest::CheckPcRelativePatch(const ArrayRef<const LinkerPa ASSERT_TRUE(result.first); uint32_t diff = target_offset - (result.second + kAnchorOffset); - CHECK_NE(patches[0].GetType(), LinkerPatch::Type::kDexCacheArray); diff += (diff & 0x8000) << 1; // Account for sign extension in addiu. const uint8_t expected_code[] = { diff --git a/compiler/oat_test.cc b/compiler/oat_test.cc index 1578c0cd3e..fdb21e4dba 100644 --- a/compiler/oat_test.cc +++ b/compiler/oat_test.cc @@ -220,6 +220,7 @@ class OatTest : public CommonCompilerTest { elf_writer->PrepareDynamicSection(rodata_size, text_size, oat_writer.GetBssSize(), + oat_writer.GetBssMethodsOffset(), oat_writer.GetBssRootsOffset()); if (kIsVdexEnabled) { @@ -483,7 +484,7 @@ TEST_F(OatTest, WriteRead) { TEST_F(OatTest, OatHeaderSizeCheck) { // If this test is failing and you have to update these constants, // it is time to update OatHeader::kOatVersion - EXPECT_EQ(72U, sizeof(OatHeader)); + EXPECT_EQ(76U, sizeof(OatHeader)); EXPECT_EQ(4U, sizeof(OatMethodOffsets)); EXPECT_EQ(24U, sizeof(OatQuickMethodHeader)); EXPECT_EQ(161 * static_cast<size_t>(GetInstructionSetPointerSize(kRuntimeISA)), diff --git a/compiler/oat_writer.cc b/compiler/oat_writer.cc index fed2d34cdb..581b1ee593 100644 --- a/compiler/oat_writer.cc +++ b/compiler/oat_writer.cc @@ -22,7 +22,7 @@ #include "arch/arm64/instruction_set_features_arm64.h" #include "art_method-inl.h" #include "base/allocator.h" -#include "base/bit_vector.h" +#include "base/bit_vector-inl.h" #include "base/enums.h" #include "base/file_magic.h" #include "base/stl_util.h" @@ -41,6 +41,7 @@ #include "image_writer.h" #include "linker/buffered_output_stream.h" #include "linker/file_output_stream.h" +#include "linker/method_bss_mapping_encoder.h" #include "linker/multi_oat_relative_patcher.h" #include "linker/output_stream.h" #include "mirror/array.h" @@ -230,12 +231,14 @@ class OatWriter::OatDexFile { return dex_file_location_data_; } - void ReserveClassOffsets(OatWriter* oat_writer); - size_t SizeOf() const; bool Write(OatWriter* oat_writer, OutputStream* out) const; bool WriteClassOffsets(OatWriter* oat_writer, OutputStream* out); + size_t GetClassOffsetsRawSize() const { + return class_offsets_.size() * sizeof(class_offsets_[0]); + } + // The source of the dex file. DexFileSource source_; @@ -256,15 +259,12 @@ class OatWriter::OatDexFile { uint32_t dex_file_offset_; uint32_t class_offsets_offset_; uint32_t lookup_table_offset_; + uint32_t method_bss_mapping_offset_; // Data to write to a separate section. dchecked_vector<uint32_t> class_offsets_; private: - size_t GetClassOffsetsRawSize() const { - return class_offsets_.size() * sizeof(class_offsets_[0]); - } - DISALLOW_COPY_AND_ASSIGN(OatDexFile); }; @@ -294,7 +294,10 @@ OatWriter::OatWriter(bool compiling_boot_image, TimingLogger* timings, ProfileCo oat_size_(0u), bss_start_(0u), bss_size_(0u), + bss_methods_offset_(0u), bss_roots_offset_(0u), + bss_method_entry_references_(), + bss_method_entries_(), bss_type_entries_(), bss_string_entries_(), oat_data_offset_(0u), @@ -331,6 +334,7 @@ OatWriter::OatWriter(bool compiling_boot_image, TimingLogger* timings, ProfileCo size_oat_dex_file_offset_(0), size_oat_dex_file_class_offsets_offset_(0), size_oat_dex_file_lookup_table_offset_(0), + size_oat_dex_file_method_bss_mapping_offset_(0), size_oat_lookup_table_alignment_(0), size_oat_lookup_table_(0), size_oat_class_offsets_alignment_(0), @@ -339,6 +343,7 @@ OatWriter::OatWriter(bool compiling_boot_image, TimingLogger* timings, ProfileCo size_oat_class_status_(0), size_oat_class_method_bitmaps_(0), size_oat_class_method_offsets_(0), + size_method_bss_mappings_(0u), relative_patcher_(nullptr), absolute_patch_locations_(), profile_compilation_info_(info) { @@ -502,11 +507,10 @@ bool OatWriter::WriteAndOpenDexFiles( // Reserve space for Vdex header and checksums. vdex_size_ = sizeof(VdexFile::Header) + oat_dex_files_.size() * sizeof(VdexFile::VdexChecksum); } - size_t oat_data_offset = InitOatHeader(instruction_set, - instruction_set_features, - dchecked_integral_cast<uint32_t>(oat_dex_files_.size()), - key_value_store); - oat_size_ = InitOatDexFiles(oat_data_offset); + oat_size_ = InitOatHeader(instruction_set, + instruction_set_features, + dchecked_integral_cast<uint32_t>(oat_dex_files_.size()), + key_value_store); ChecksumUpdatingOutputStream checksum_updating_rodata(oat_rodata, oat_header_.get()); @@ -539,16 +543,6 @@ bool OatWriter::WriteAndOpenDexFiles( return false; } - // Reserve space for class offsets in OAT and update class_offsets_offset_. - for (OatDexFile& oat_dex_file : oat_dex_files_) { - oat_dex_file.ReserveClassOffsets(this); - } - - // Write OatDexFiles into OAT. Needs to be done last, once offsets are collected. - if (!WriteOatDexFiles(&checksum_updating_rodata)) { - return false; - } - *opened_dex_files_map = std::move(dex_files_map); *opened_dex_files = std::move(dex_files); write_state_ = WriteState::kPrepareLayout; @@ -567,16 +561,34 @@ void OatWriter::PrepareLayout(linker::MultiOatRelativePatcher* relative_patcher) InstructionSet instruction_set = compiler_driver_->GetInstructionSet(); CHECK_EQ(instruction_set, oat_header_->GetInstructionSet()); + { + TimingLogger::ScopedTiming split("InitBssLayout", timings_); + InitBssLayout(instruction_set); + } + uint32_t offset = oat_size_; { + TimingLogger::ScopedTiming split("InitClassOffsets", timings_); + offset = InitClassOffsets(offset); + } + { TimingLogger::ScopedTiming split("InitOatClasses", timings_); offset = InitOatClasses(offset); } { + TimingLogger::ScopedTiming split("InitMethodBssMappings", timings_); + offset = InitMethodBssMappings(offset); + } + { TimingLogger::ScopedTiming split("InitOatMaps", timings_); offset = InitOatMaps(offset); } { + TimingLogger::ScopedTiming split("InitOatDexFiles", timings_); + oat_header_->SetOatDexFilesOffset(offset); + offset = InitOatDexFiles(offset); + } + { TimingLogger::ScopedTiming split("InitOatCode", timings_); offset = InitOatCode(offset); } @@ -585,11 +597,7 @@ void OatWriter::PrepareLayout(linker::MultiOatRelativePatcher* relative_patcher) offset = InitOatCodeDexFiles(offset); } oat_size_ = offset; - - { - TimingLogger::ScopedTiming split("InitBssLayout", timings_); - InitBssLayout(instruction_set); - } + bss_start_ = (bss_size_ != 0u) ? RoundUp(oat_size_, kPageSize) : 0u; CHECK_EQ(dex_files_->size(), oat_dex_files_.size()); if (compiling_boot_image_) { @@ -606,11 +614,10 @@ OatWriter::~OatWriter() { class OatWriter::DexMethodVisitor { public: DexMethodVisitor(OatWriter* writer, size_t offset) - : writer_(writer), - offset_(offset), - dex_file_(nullptr), - class_def_index_(DexFile::kDexNoIndex) { - } + : writer_(writer), + offset_(offset), + dex_file_(nullptr), + class_def_index_(DexFile::kDexNoIndex) {} virtual bool StartClass(const DexFile* dex_file, size_t class_def_index) { DCHECK(dex_file_ == nullptr); @@ -650,19 +657,18 @@ class OatWriter::DexMethodVisitor { class OatWriter::OatDexMethodVisitor : public DexMethodVisitor { public: OatDexMethodVisitor(OatWriter* writer, size_t offset) - : DexMethodVisitor(writer, offset), - oat_class_index_(0u), - method_offsets_index_(0u) { - } + : DexMethodVisitor(writer, offset), + oat_class_index_(0u), + method_offsets_index_(0u) {} - bool StartClass(const DexFile* dex_file, size_t class_def_index) { + bool StartClass(const DexFile* dex_file, size_t class_def_index) OVERRIDE { DexMethodVisitor::StartClass(dex_file, class_def_index); DCHECK_LT(oat_class_index_, writer_->oat_classes_.size()); method_offsets_index_ = 0u; return true; } - bool EndClass() { + bool EndClass() OVERRIDE { ++oat_class_index_; return DexMethodVisitor::EndClass(); } @@ -672,21 +678,61 @@ class OatWriter::OatDexMethodVisitor : public DexMethodVisitor { size_t method_offsets_index_; }; +class OatWriter::InitBssLayoutMethodVisitor : public DexMethodVisitor { + public: + explicit InitBssLayoutMethodVisitor(OatWriter* writer) + : DexMethodVisitor(writer, /* offset */ 0u) {} + + bool VisitMethod(size_t class_def_method_index ATTRIBUTE_UNUSED, + const ClassDataItemIterator& it) OVERRIDE { + // Look for patches with .bss references and prepare maps with placeholders for their offsets. + CompiledMethod* compiled_method = writer_->compiler_driver_->GetCompiledMethod( + MethodReference(dex_file_, it.GetMemberIndex())); + if (compiled_method != nullptr) { + for (const LinkerPatch& patch : compiled_method->GetPatches()) { + if (patch.GetType() == LinkerPatch::Type::kMethodBssEntry) { + MethodReference target_method = patch.TargetMethod(); + auto refs_it = writer_->bss_method_entry_references_.find(target_method.dex_file); + if (refs_it == writer_->bss_method_entry_references_.end()) { + refs_it = writer_->bss_method_entry_references_.Put( + target_method.dex_file, + BitVector(target_method.dex_file->NumMethodIds(), + /* expandable */ false, + Allocator::GetMallocAllocator())); + refs_it->second.ClearAllBits(); + } + refs_it->second.SetBit(target_method.dex_method_index); + writer_->bss_method_entries_.Overwrite(target_method, /* placeholder */ 0u); + } else if (patch.GetType() == LinkerPatch::Type::kTypeBssEntry) { + TypeReference ref(patch.TargetTypeDexFile(), patch.TargetTypeIndex()); + writer_->bss_type_entries_.Overwrite(ref, /* placeholder */ 0u); + } else if (patch.GetType() == LinkerPatch::Type::kStringBssEntry) { + StringReference ref(patch.TargetStringDexFile(), patch.TargetStringIndex()); + writer_->bss_string_entries_.Overwrite(ref, /* placeholder */ 0u); + } + } + } + return true; + } +}; + class OatWriter::InitOatClassesMethodVisitor : public DexMethodVisitor { public: InitOatClassesMethodVisitor(OatWriter* writer, size_t offset) - : DexMethodVisitor(writer, offset), - compiled_methods_(), - num_non_null_compiled_methods_(0u) { + : DexMethodVisitor(writer, offset), + compiled_methods_(), + num_non_null_compiled_methods_(0u) { size_t num_classes = 0u; for (const OatDexFile& oat_dex_file : writer_->oat_dex_files_) { num_classes += oat_dex_file.class_offsets_.size(); } writer_->oat_classes_.reserve(num_classes); compiled_methods_.reserve(256u); + // If there are any classes, the class offsets allocation aligns the offset. + DCHECK(num_classes == 0u || IsAligned<4u>(offset)); } - bool StartClass(const DexFile* dex_file, size_t class_def_index) { + bool StartClass(const DexFile* dex_file, size_t class_def_index) OVERRIDE { DexMethodVisitor::StartClass(dex_file, class_def_index); compiled_methods_.clear(); num_non_null_compiled_methods_ = 0u; @@ -694,7 +740,7 @@ class OatWriter::InitOatClassesMethodVisitor : public DexMethodVisitor { } bool VisitMethod(size_t class_def_method_index ATTRIBUTE_UNUSED, - const ClassDataItemIterator& it) { + const ClassDataItemIterator& it) OVERRIDE { // Fill in the compiled_methods_ array for methods that have a // CompiledMethod. We track the number of non-null entries in // num_non_null_compiled_methods_ since we only want to allocate @@ -704,12 +750,12 @@ class OatWriter::InitOatClassesMethodVisitor : public DexMethodVisitor { writer_->compiler_driver_->GetCompiledMethod(MethodReference(dex_file_, method_idx)); compiled_methods_.push_back(compiled_method); if (compiled_method != nullptr) { - ++num_non_null_compiled_methods_; + ++num_non_null_compiled_methods_; } return true; } - bool EndClass() { + bool EndClass() OVERRIDE { ClassReference class_ref(dex_file_, class_def_index_); mirror::Class::Status status; bool found = writer_->compiler_driver_->GetCompiledClass(class_ref, &status); @@ -740,14 +786,14 @@ class OatWriter::InitOatClassesMethodVisitor : public DexMethodVisitor { class OatWriter::InitCodeMethodVisitor : public OatDexMethodVisitor { public: InitCodeMethodVisitor(OatWriter* writer, size_t offset, size_t quickening_info_offset) - : OatDexMethodVisitor(writer, offset), - debuggable_(writer->GetCompilerDriver()->GetCompilerOptions().GetDebuggable()), - current_quickening_info_offset_(quickening_info_offset) { + : OatDexMethodVisitor(writer, offset), + debuggable_(writer->GetCompilerDriver()->GetCompilerOptions().GetDebuggable()), + current_quickening_info_offset_(quickening_info_offset) { writer_->absolute_patch_locations_.reserve( writer_->compiler_driver_->GetNonRelativeLinkerPatchCount()); } - bool EndClass() { + bool EndClass() OVERRIDE { OatDexMethodVisitor::EndClass(); if (oat_class_index_ == writer_->oat_classes_.size()) { offset_ = writer_->relative_patcher_->ReserveSpaceEnd(offset_); @@ -755,7 +801,7 @@ class OatWriter::InitCodeMethodVisitor : public OatDexMethodVisitor { return true; } - bool VisitMethod(size_t class_def_method_index, const ClassDataItemIterator& it) + bool VisitMethod(size_t class_def_method_index, const ClassDataItemIterator& it) OVERRIDE REQUIRES_SHARED(Locks::mutator_lock_) { OatClass* oat_class = &writer_->oat_classes_[oat_class_index_]; CompiledMethod* compiled_method = oat_class->GetCompiledMethod(class_def_method_index); @@ -858,14 +904,6 @@ class OatWriter::InitCodeMethodVisitor : public OatDexMethodVisitor { if (!patch.IsPcRelative()) { writer_->absolute_patch_locations_.push_back(base_loc + patch.LiteralOffset()); } - if (patch.GetType() == LinkerPatch::Type::kTypeBssEntry) { - TypeReference ref(patch.TargetTypeDexFile(), patch.TargetTypeIndex()); - writer_->bss_type_entries_.Overwrite(ref, /* placeholder */ 0u); - } - if (patch.GetType() == LinkerPatch::Type::kStringBssEntry) { - StringReference ref(patch.TargetStringDexFile(), patch.TargetStringIndex()); - writer_->bss_string_entries_.Overwrite(ref, /* placeholder */ 0u); - } } } } @@ -950,11 +988,10 @@ class OatWriter::InitCodeMethodVisitor : public OatDexMethodVisitor { class OatWriter::InitMapMethodVisitor : public OatDexMethodVisitor { public: InitMapMethodVisitor(OatWriter* writer, size_t offset) - : OatDexMethodVisitor(writer, offset) { - } + : OatDexMethodVisitor(writer, offset) {} bool VisitMethod(size_t class_def_method_index, const ClassDataItemIterator& it ATTRIBUTE_UNUSED) - REQUIRES_SHARED(Locks::mutator_lock_) { + OVERRIDE REQUIRES_SHARED(Locks::mutator_lock_) { OatClass* oat_class = &writer_->oat_classes_[oat_class_index_]; CompiledMethod* compiled_method = oat_class->GetCompiledMethod(class_def_method_index); @@ -997,7 +1034,7 @@ class OatWriter::InitMethodInfoVisitor : public OatDexMethodVisitor { InitMethodInfoVisitor(OatWriter* writer, size_t offset) : OatDexMethodVisitor(writer, offset) {} bool VisitMethod(size_t class_def_method_index, const ClassDataItemIterator& it ATTRIBUTE_UNUSED) - REQUIRES_SHARED(Locks::mutator_lock_) { + OVERRIDE REQUIRES_SHARED(Locks::mutator_lock_) { OatClass* oat_class = &writer_->oat_classes_[oat_class_index_]; CompiledMethod* compiled_method = oat_class->GetCompiledMethod(class_def_method_index); @@ -1035,18 +1072,17 @@ class OatWriter::InitImageMethodVisitor : public OatDexMethodVisitor { InitImageMethodVisitor(OatWriter* writer, size_t offset, const std::vector<const DexFile*>* dex_files) - : OatDexMethodVisitor(writer, offset), - pointer_size_(GetInstructionSetPointerSize(writer_->compiler_driver_->GetInstructionSet())), - dex_files_(dex_files), - class_linker_(Runtime::Current()->GetClassLinker()) { - } + : OatDexMethodVisitor(writer, offset), + pointer_size_(GetInstructionSetPointerSize(writer_->compiler_driver_->GetInstructionSet())), + dex_files_(dex_files), + class_linker_(Runtime::Current()->GetClassLinker()) {} // Handle copied methods here. Copy pointer to quick code from // an origin method to a copied method only if they are // in the same oat file. If the origin and the copied methods are // in different oat files don't touch the copied method. // References to other oat files are not supported yet. - bool StartClass(const DexFile* dex_file, size_t class_def_index) + bool StartClass(const DexFile* dex_file, size_t class_def_index) OVERRIDE REQUIRES_SHARED(Locks::mutator_lock_) { OatDexMethodVisitor::StartClass(dex_file, class_def_index); // Skip classes that are not in the image. @@ -1085,7 +1121,7 @@ class OatWriter::InitImageMethodVisitor : public OatDexMethodVisitor { return true; } - bool VisitMethod(size_t class_def_method_index, const ClassDataItemIterator& it) + bool VisitMethod(size_t class_def_method_index, const ClassDataItemIterator& it) OVERRIDE REQUIRES_SHARED(Locks::mutator_lock_) { // Skip methods that are not in the image. if (!IsImageClass()) { @@ -1131,8 +1167,7 @@ class OatWriter::InitImageMethodVisitor : public OatDexMethodVisitor { // Should already have been resolved by the compiler, just peek into the dex cache. // It may not be resolved if the class failed to verify, in this case, don't set the // entrypoint. This is not fatal since the dex cache will contain a resolution method. - method = dex_cache->GetResolvedMethod(it.GetMemberIndex(), - class_linker_->GetImagePointerSize()); + method = dex_cache->GetResolvedMethod(it.GetMemberIndex(), pointer_size_); } if (method != nullptr && compiled_method != nullptr && @@ -1171,7 +1206,7 @@ class OatWriter::InitImageMethodVisitor : public OatDexMethodVisitor { } } - protected: + private: const PointerSize pointer_size_; const std::vector<const DexFile*>* dex_files_; ClassLinker* const class_linker_; @@ -1182,14 +1217,15 @@ class OatWriter::WriteCodeMethodVisitor : public OatDexMethodVisitor { public: WriteCodeMethodVisitor(OatWriter* writer, OutputStream* out, const size_t file_offset, size_t relative_offset) SHARED_LOCK_FUNCTION(Locks::mutator_lock_) - : OatDexMethodVisitor(writer, relative_offset), - class_loader_(writer->HasImage() ? writer->image_writer_->GetClassLoader() : nullptr), - out_(out), - file_offset_(file_offset), - soa_(Thread::Current()), - no_thread_suspension_("OatWriter patching"), - class_linker_(Runtime::Current()->GetClassLinker()), - dex_cache_(nullptr) { + : OatDexMethodVisitor(writer, relative_offset), + pointer_size_(GetInstructionSetPointerSize(writer_->compiler_driver_->GetInstructionSet())), + class_loader_(writer->HasImage() ? writer->image_writer_->GetClassLoader() : nullptr), + out_(out), + file_offset_(file_offset), + soa_(Thread::Current()), + no_thread_suspension_("OatWriter patching"), + class_linker_(Runtime::Current()->GetClassLinker()), + dex_cache_(nullptr) { patched_code_.reserve(16 * KB); if (writer_->HasBootImage()) { // If we're creating the image, the address space must be ready so that we can apply patches. @@ -1200,7 +1236,7 @@ class OatWriter::WriteCodeMethodVisitor : public OatDexMethodVisitor { ~WriteCodeMethodVisitor() UNLOCK_FUNCTION(Locks::mutator_lock_) { } - bool StartClass(const DexFile* dex_file, size_t class_def_index) + bool StartClass(const DexFile* dex_file, size_t class_def_index) OVERRIDE REQUIRES_SHARED(Locks::mutator_lock_) { OatDexMethodVisitor::StartClass(dex_file, class_def_index); if (dex_cache_ == nullptr || dex_cache_->GetDexFile() != dex_file) { @@ -1210,7 +1246,7 @@ class OatWriter::WriteCodeMethodVisitor : public OatDexMethodVisitor { return true; } - bool EndClass() REQUIRES_SHARED(Locks::mutator_lock_) { + bool EndClass() OVERRIDE REQUIRES_SHARED(Locks::mutator_lock_) { bool result = OatDexMethodVisitor::EndClass(); if (oat_class_index_ == writer_->oat_classes_.size()) { DCHECK(result); // OatDexMethodVisitor::EndClass() never fails. @@ -1223,7 +1259,7 @@ class OatWriter::WriteCodeMethodVisitor : public OatDexMethodVisitor { return result; } - bool VisitMethod(size_t class_def_method_index, const ClassDataItemIterator& it) + bool VisitMethod(size_t class_def_method_index, const ClassDataItemIterator& it) OVERRIDE REQUIRES_SHARED(Locks::mutator_lock_) { OatClass* oat_class = &writer_->oat_classes_[oat_class_index_]; const CompiledMethod* compiled_method = oat_class->GetCompiledMethod(class_def_method_index); @@ -1275,6 +1311,15 @@ class OatWriter::WriteCodeMethodVisitor : public OatDexMethodVisitor { for (const LinkerPatch& patch : compiled_method->GetPatches()) { uint32_t literal_offset = patch.LiteralOffset(); switch (patch.GetType()) { + case LinkerPatch::Type::kMethodBssEntry: { + uint32_t target_offset = + writer_->bss_start_ + writer_->bss_method_entries_.Get(patch.TargetMethod()); + writer_->relative_patcher_->PatchPcRelativeReference(&patched_code_, + patch, + offset_ + literal_offset, + target_offset); + break; + } case LinkerPatch::Type::kCallRelative: { // NOTE: Relative calls across oat files are not supported. uint32_t target_offset = GetTargetOffset(patch); @@ -1284,14 +1329,6 @@ class OatWriter::WriteCodeMethodVisitor : public OatDexMethodVisitor { target_offset); break; } - case LinkerPatch::Type::kDexCacheArray: { - uint32_t target_offset = GetDexCacheOffset(patch); - writer_->relative_patcher_->PatchPcRelativeReference(&patched_code_, - patch, - offset_ + literal_offset, - target_offset); - break; - } case LinkerPatch::Type::kStringRelative: { uint32_t target_offset = GetTargetObjectOffset(GetTargetString(patch)); writer_->relative_patcher_->PatchPcRelativeReference(&patched_code_, @@ -1302,7 +1339,8 @@ class OatWriter::WriteCodeMethodVisitor : public OatDexMethodVisitor { } case LinkerPatch::Type::kStringBssEntry: { StringReference ref(patch.TargetStringDexFile(), patch.TargetStringIndex()); - uint32_t target_offset = writer_->bss_string_entries_.Get(ref); + uint32_t target_offset = + writer_->bss_start_ + writer_->bss_string_entries_.Get(ref); writer_->relative_patcher_->PatchPcRelativeReference(&patched_code_, patch, offset_ + literal_offset, @@ -1319,7 +1357,7 @@ class OatWriter::WriteCodeMethodVisitor : public OatDexMethodVisitor { } case LinkerPatch::Type::kTypeBssEntry: { TypeReference ref(patch.TargetTypeDexFile(), patch.TargetTypeIndex()); - uint32_t target_offset = writer_->bss_type_entries_.Get(ref); + uint32_t target_offset = writer_->bss_start_ + writer_->bss_type_entries_.Get(ref); writer_->relative_patcher_->PatchPcRelativeReference(&patched_code_, patch, offset_ + literal_offset, @@ -1368,6 +1406,7 @@ class OatWriter::WriteCodeMethodVisitor : public OatDexMethodVisitor { } private: + const PointerSize pointer_size_; ObjPtr<mirror::ClassLoader> class_loader_; OutputStream* const out_; const size_t file_offset_; @@ -1388,8 +1427,7 @@ class OatWriter::WriteCodeMethodVisitor : public OatDexMethodVisitor { ObjPtr<mirror::DexCache> dex_cache = (dex_file_ == ref.dex_file) ? dex_cache_ : class_linker_->FindDexCache( Thread::Current(), *ref.dex_file); - ArtMethod* method = dex_cache->GetResolvedMethod( - ref.dex_method_index, class_linker_->GetImagePointerSize()); + ArtMethod* method = dex_cache->GetResolvedMethod(ref.dex_method_index, pointer_size_); CHECK(method != nullptr); return method; } @@ -1401,9 +1439,8 @@ class OatWriter::WriteCodeMethodVisitor : public OatDexMethodVisitor { if (UNLIKELY(target_offset == 0)) { ArtMethod* target = GetTargetMethod(patch); DCHECK(target != nullptr); - PointerSize size = - GetInstructionSetPointerSize(writer_->compiler_driver_->GetInstructionSet()); - const void* oat_code_offset = target->GetEntryPointFromQuickCompiledCodePtrSize(size); + const void* oat_code_offset = + target->GetEntryPointFromQuickCompiledCodePtrSize(pointer_size_); if (oat_code_offset != 0) { DCHECK(!writer_->HasBootImage()); DCHECK(!Runtime::Current()->GetClassLinker()->IsQuickResolutionStub(oat_code_offset)); @@ -1447,19 +1484,6 @@ class OatWriter::WriteCodeMethodVisitor : public OatDexMethodVisitor { return string; } - uint32_t GetDexCacheOffset(const LinkerPatch& patch) REQUIRES_SHARED(Locks::mutator_lock_) { - if (writer_->HasBootImage()) { - uintptr_t element = writer_->image_writer_->GetDexCacheArrayElementImageAddress<uintptr_t>( - patch.TargetDexCacheDexFile(), patch.TargetDexCacheElementOffset()); - size_t oat_index = writer_->image_writer_->GetOatIndexForDexCache(dex_cache_); - uintptr_t oat_data = writer_->image_writer_->GetOatDataBegin(oat_index); - return element - oat_data; - } else { - size_t start = writer_->dex_cache_arrays_offsets_.Get(patch.TargetDexCacheDexFile()); - return start + patch.TargetDexCacheElementOffset(); - } - } - uint32_t GetTargetMethodOffset(ArtMethod* method) REQUIRES_SHARED(Locks::mutator_lock_) { DCHECK(writer_->HasBootImage()); method = writer_->image_writer_->GetImageMethodAddress(method); @@ -1525,12 +1549,11 @@ class OatWriter::WriteMapMethodVisitor : public OatDexMethodVisitor { OutputStream* out, const size_t file_offset, size_t relative_offset) - : OatDexMethodVisitor(writer, relative_offset), - out_(out), - file_offset_(file_offset) { - } + : OatDexMethodVisitor(writer, relative_offset), + out_(out), + file_offset_(file_offset) {} - bool VisitMethod(size_t class_def_method_index, const ClassDataItemIterator& it) { + bool VisitMethod(size_t class_def_method_index, const ClassDataItemIterator& it) OVERRIDE { OatClass* oat_class = &writer_->oat_classes_[oat_class_index_]; const CompiledMethod* compiled_method = oat_class->GetCompiledMethod(class_def_method_index); @@ -1589,11 +1612,11 @@ class OatWriter::WriteMethodInfoVisitor : public OatDexMethodVisitor { OutputStream* out, const size_t file_offset, size_t relative_offset) - : OatDexMethodVisitor(writer, relative_offset), - out_(out), - file_offset_(file_offset) {} + : OatDexMethodVisitor(writer, relative_offset), + out_(out), + file_offset_(file_offset) {} - bool VisitMethod(size_t class_def_method_index, const ClassDataItemIterator& it) { + bool VisitMethod(size_t class_def_method_index, const ClassDataItemIterator& it) OVERRIDE { OatClass* oat_class = &writer_->oat_classes_[oat_class_index_]; const CompiledMethod* compiled_method = oat_class->GetCompiledMethod(class_def_method_index); @@ -1698,12 +1721,17 @@ size_t OatWriter::InitOatHeader(InstructionSet instruction_set, return oat_header_->GetHeaderSize(); } -size_t OatWriter::InitOatDexFiles(size_t offset) { - TimingLogger::ScopedTiming split("InitOatDexFiles", timings_); - // Initialize offsets of dex files. +size_t OatWriter::InitClassOffsets(size_t offset) { + // Reserve space for class offsets in OAT and update class_offsets_offset_. for (OatDexFile& oat_dex_file : oat_dex_files_) { - oat_dex_file.offset_ = offset; - offset += oat_dex_file.SizeOf(); + DCHECK_EQ(oat_dex_file.class_offsets_offset_, 0u); + if (!oat_dex_file.class_offsets_.empty()) { + // Class offsets are required to be 4 byte aligned. + offset = RoundUp(offset, 4u); + oat_dex_file.class_offsets_offset_ = offset; + offset += oat_dex_file.GetClassOffsetsRawSize(); + DCHECK_ALIGNED(offset, 4u); + } } return offset; } @@ -1748,6 +1776,50 @@ size_t OatWriter::InitOatMaps(size_t offset) { return offset; } +size_t OatWriter::InitMethodBssMappings(size_t offset) { + size_t number_of_dex_files = 0u; + for (size_t i = 0, size = dex_files_->size(); i != size; ++i) { + const DexFile* dex_file = (*dex_files_)[i]; + auto it = bss_method_entry_references_.find(dex_file); + if (it != bss_method_entry_references_.end()) { + const BitVector& method_indexes = it->second; + ++number_of_dex_files; + // If there are any classes, the class offsets allocation aligns the offset + // and we cannot have method bss mappings without class offsets. + static_assert(alignof(MethodBssMapping) == 4u, "MethodBssMapping alignment check."); + DCHECK_ALIGNED(offset, 4u); + oat_dex_files_[i].method_bss_mapping_offset_ = offset; + + linker::MethodBssMappingEncoder encoder( + GetInstructionSetPointerSize(oat_header_->GetInstructionSet())); + size_t number_of_entries = 0u; + bool first_index = true; + for (uint32_t method_index : method_indexes.Indexes()) { + uint32_t bss_offset = bss_method_entries_.Get(MethodReference(dex_file, method_index)); + if (first_index || !encoder.TryMerge(method_index, bss_offset)) { + encoder.Reset(method_index, bss_offset); + ++number_of_entries; + first_index = false; + } + } + DCHECK_NE(number_of_entries, 0u); + offset += MethodBssMapping::ComputeSize(number_of_entries); + } + } + // Check that all dex files targeted by method bss entries are in `*dex_files_`. + CHECK_EQ(number_of_dex_files, bss_method_entry_references_.size()); + return offset; +} + +size_t OatWriter::InitOatDexFiles(size_t offset) { + // Initialize offsets of oat dex files. + for (OatDexFile& oat_dex_file : oat_dex_files_) { + oat_dex_file.offset_ = offset; + offset += oat_dex_file.SizeOf(); + } + return offset; +} + size_t OatWriter::InitOatCode(size_t offset) { // calculate the offsets within OatHeader to executable code size_t old_offset = offset; @@ -1806,38 +1878,51 @@ size_t OatWriter::InitOatCodeDexFiles(size_t offset) { } void OatWriter::InitBssLayout(InstructionSet instruction_set) { + { + InitBssLayoutMethodVisitor visitor(this); + bool success = VisitDexMethods(&visitor); + DCHECK(success); + } + + DCHECK_EQ(bss_size_, 0u); if (HasBootImage()) { DCHECK(bss_string_entries_.empty()); - if (bss_type_entries_.empty()) { + if (bss_method_entries_.empty() && bss_type_entries_.empty()) { // Nothing to put to the .bss section. return; } } // Allocate space for app dex cache arrays in the .bss section. - bss_start_ = RoundUp(oat_size_, kPageSize); - bss_size_ = 0u; + PointerSize pointer_size = GetInstructionSetPointerSize(instruction_set); if (!HasBootImage()) { - PointerSize pointer_size = GetInstructionSetPointerSize(instruction_set); for (const DexFile* dex_file : *dex_files_) { - dex_cache_arrays_offsets_.Put(dex_file, bss_start_ + bss_size_); DexCacheArraysLayout layout(pointer_size, dex_file); bss_size_ += layout.Size(); } } + bss_methods_offset_ = bss_size_; + + // Prepare offsets for .bss ArtMethod entries. + for (auto& entry : bss_method_entries_) { + DCHECK_EQ(entry.second, 0u); + entry.second = bss_size_; + bss_size_ += static_cast<size_t>(pointer_size); + } + bss_roots_offset_ = bss_size_; // Prepare offsets for .bss Class entries. for (auto& entry : bss_type_entries_) { DCHECK_EQ(entry.second, 0u); - entry.second = bss_start_ + bss_size_; + entry.second = bss_size_; bss_size_ += sizeof(GcRoot<mirror::Class>); } // Prepare offsets for .bss String entries. for (auto& entry : bss_string_entries_) { DCHECK_EQ(entry.second, 0u); - entry.second = bss_start_ + bss_size_; + entry.second = bss_size_; bss_size_ += sizeof(GcRoot<mirror::String>); } } @@ -1845,30 +1930,45 @@ void OatWriter::InitBssLayout(InstructionSet instruction_set) { bool OatWriter::WriteRodata(OutputStream* out) { CHECK(write_state_ == WriteState::kWriteRoData); + size_t file_offset = oat_data_offset_; + off_t current_offset = out->Seek(0, kSeekCurrent); + if (current_offset == static_cast<off_t>(-1)) { + PLOG(ERROR) << "Failed to retrieve current position in " << out->GetLocation(); + } + DCHECK_GE(static_cast<size_t>(current_offset), file_offset + oat_header_->GetHeaderSize()); + size_t relative_offset = current_offset - file_offset; + // Wrap out to update checksum with each write. ChecksumUpdatingOutputStream checksum_updating_out(out, oat_header_.get()); out = &checksum_updating_out; - if (!WriteClassOffsets(out)) { - LOG(ERROR) << "Failed to write class offsets to " << out->GetLocation(); + relative_offset = WriteClassOffsets(out, file_offset, relative_offset); + if (relative_offset == 0) { + PLOG(ERROR) << "Failed to write class offsets to " << out->GetLocation(); return false; } - if (!WriteClasses(out)) { - LOG(ERROR) << "Failed to write classes to " << out->GetLocation(); + relative_offset = WriteClasses(out, file_offset, relative_offset); + if (relative_offset == 0) { + PLOG(ERROR) << "Failed to write classes to " << out->GetLocation(); return false; } - off_t tables_end_offset = out->Seek(0, kSeekCurrent); - if (tables_end_offset == static_cast<off_t>(-1)) { - LOG(ERROR) << "Failed to get oat code position in " << out->GetLocation(); + relative_offset = WriteMethodBssMappings(out, file_offset, relative_offset); + if (relative_offset == 0) { + PLOG(ERROR) << "Failed to write method bss mappings to " << out->GetLocation(); return false; } - size_t file_offset = oat_data_offset_; - size_t relative_offset = static_cast<size_t>(tables_end_offset) - file_offset; + relative_offset = WriteMaps(out, file_offset, relative_offset); if (relative_offset == 0) { - LOG(ERROR) << "Failed to write oat code to " << out->GetLocation(); + PLOG(ERROR) << "Failed to write oat code to " << out->GetLocation(); + return false; + } + + relative_offset = WriteOatDexFiles(out, file_offset, relative_offset); + if (relative_offset == 0) { + PLOG(ERROR) << "Failed to write oat dex information to " << out->GetLocation(); return false; } @@ -1891,12 +1991,12 @@ bool OatWriter::WriteRodata(OutputStream* out) { class OatWriter::WriteQuickeningInfoMethodVisitor : public DexMethodVisitor { public: WriteQuickeningInfoMethodVisitor(OatWriter* writer, OutputStream* out, uint32_t offset) - : DexMethodVisitor(writer, offset), - out_(out), - written_bytes_(0u) {} + : DexMethodVisitor(writer, offset), + out_(out), + written_bytes_(0u) {} bool VisitMethod(size_t class_def_method_index ATTRIBUTE_UNUSED, - const ClassDataItemIterator& it) { + const ClassDataItemIterator& it) OVERRIDE { if (it.GetMethodCodeItem() == nullptr) { // No CodeItem. Native or abstract method. return true; @@ -2092,6 +2192,7 @@ bool OatWriter::WriteCode(OutputStream* out) { DO_STAT(size_oat_dex_file_offset_); DO_STAT(size_oat_dex_file_class_offsets_offset_); DO_STAT(size_oat_dex_file_lookup_table_offset_); + DO_STAT(size_oat_dex_file_method_bss_mapping_offset_); DO_STAT(size_oat_lookup_table_alignment_); DO_STAT(size_oat_lookup_table_); DO_STAT(size_oat_class_offsets_alignment_); @@ -2100,6 +2201,7 @@ bool OatWriter::WriteCode(OutputStream* out) { DO_STAT(size_oat_class_status_); DO_STAT(size_oat_class_method_bitmaps_); DO_STAT(size_oat_class_method_offsets_); + DO_STAT(size_method_bss_mappings_); #undef DO_STAT VLOG(compiler) << "size_total=" << PrettySize(size_total) << " (" << size_total << "B)"; @@ -2172,35 +2274,41 @@ bool OatWriter::WriteHeader(OutputStream* out, return true; } -bool OatWriter::WriteClassOffsets(OutputStream* out) { +size_t OatWriter::WriteClassOffsets(OutputStream* out, size_t file_offset, size_t relative_offset) { for (OatDexFile& oat_dex_file : oat_dex_files_) { if (oat_dex_file.class_offsets_offset_ != 0u) { - uint32_t expected_offset = oat_data_offset_ + oat_dex_file.class_offsets_offset_; - off_t actual_offset = out->Seek(expected_offset, kSeekSet); - if (static_cast<uint32_t>(actual_offset) != expected_offset) { - PLOG(ERROR) << "Failed to seek to oat class offsets section. Actual: " << actual_offset - << " Expected: " << expected_offset << " File: " << oat_dex_file.GetLocation(); - return false; + // Class offsets are required to be 4 byte aligned. + if (UNLIKELY(!IsAligned<4u>(relative_offset))) { + size_t padding_size = RoundUp(relative_offset, 4u) - relative_offset; + if (!WriteUpTo16BytesAlignment(out, padding_size, &size_oat_class_offsets_alignment_)) { + return 0u; + } + relative_offset += padding_size; } + DCHECK_OFFSET(); if (!oat_dex_file.WriteClassOffsets(this, out)) { - return false; + return 0u; } + relative_offset += oat_dex_file.GetClassOffsetsRawSize(); } } - return true; + return relative_offset; } -bool OatWriter::WriteClasses(OutputStream* out) { +size_t OatWriter::WriteClasses(OutputStream* out, size_t file_offset, size_t relative_offset) { for (OatClass& oat_class : oat_classes_) { + // If there are any classes, the class offsets allocation aligns the offset. + DCHECK_ALIGNED(relative_offset, 4u); + DCHECK_OFFSET(); if (!oat_class.Write(this, out, oat_data_offset_)) { - PLOG(ERROR) << "Failed to write oat methods information to " << out->GetLocation(); - return false; + return 0u; } + relative_offset += oat_class.SizeOf(); } - return true; + return relative_offset; } -size_t OatWriter::WriteMaps(OutputStream* out, const size_t file_offset, size_t relative_offset) { +size_t OatWriter::WriteMaps(OutputStream* out, size_t file_offset, size_t relative_offset) { { size_t vmap_tables_offset = relative_offset; WriteMapMethodVisitor visitor(this, out, file_offset, relative_offset); @@ -2223,7 +2331,87 @@ size_t OatWriter::WriteMaps(OutputStream* out, const size_t file_offset, size_t return relative_offset; } -size_t OatWriter::WriteCode(OutputStream* out, const size_t file_offset, size_t relative_offset) { +size_t OatWriter::WriteMethodBssMappings(OutputStream* out, + size_t file_offset, + size_t relative_offset) { + TimingLogger::ScopedTiming split("WriteMethodBssMappings", timings_); + + for (size_t i = 0, size = dex_files_->size(); i != size; ++i) { + const DexFile* dex_file = (*dex_files_)[i]; + OatDexFile* oat_dex_file = &oat_dex_files_[i]; + auto it = bss_method_entry_references_.find(dex_file); + if (it != bss_method_entry_references_.end()) { + const BitVector& method_indexes = it->second; + // If there are any classes, the class offsets allocation aligns the offset + // and we cannot have method bss mappings without class offsets. + static_assert(alignof(MethodBssMapping) == sizeof(uint32_t), + "MethodBssMapping alignment check."); + DCHECK_ALIGNED(relative_offset, sizeof(uint32_t)); + + linker::MethodBssMappingEncoder encoder( + GetInstructionSetPointerSize(oat_header_->GetInstructionSet())); + // Allocate a sufficiently large MethodBssMapping. + size_t number_of_method_indexes = method_indexes.NumSetBits(); + DCHECK_NE(number_of_method_indexes, 0u); + size_t max_mappings_size = MethodBssMapping::ComputeSize(number_of_method_indexes); + DCHECK_ALIGNED(max_mappings_size, sizeof(uint32_t)); + std::unique_ptr<uint32_t[]> storage(new uint32_t[max_mappings_size / sizeof(uint32_t)]); + MethodBssMapping* mappings = new(storage.get()) MethodBssMapping(number_of_method_indexes); + mappings->ClearPadding(); + // Encode the MethodBssMapping. + auto init_it = mappings->begin(); + bool first_index = true; + for (uint32_t method_index : method_indexes.Indexes()) { + size_t bss_offset = bss_method_entries_.Get(MethodReference(dex_file, method_index)); + if (first_index) { + first_index = false; + encoder.Reset(method_index, bss_offset); + } else if (!encoder.TryMerge(method_index, bss_offset)) { + *init_it = encoder.GetEntry(); + ++init_it; + encoder.Reset(method_index, bss_offset); + } + } + // Store the last entry and shrink the mapping to the actual size. + *init_it = encoder.GetEntry(); + ++init_it; + DCHECK(init_it <= mappings->end()); + mappings->SetSize(std::distance(mappings->begin(), init_it)); + size_t mappings_size = MethodBssMapping::ComputeSize(mappings->size()); + + DCHECK_EQ(relative_offset, oat_dex_file->method_bss_mapping_offset_); + DCHECK_OFFSET(); + if (!out->WriteFully(storage.get(), mappings_size)) { + return 0u; + } + size_method_bss_mappings_ += mappings_size; + relative_offset += mappings_size; + } else { + DCHECK_EQ(0u, oat_dex_file->method_bss_mapping_offset_); + } + } + return relative_offset; +} + +size_t OatWriter::WriteOatDexFiles(OutputStream* out, size_t file_offset, size_t relative_offset) { + TimingLogger::ScopedTiming split("WriteOatDexFiles", timings_); + + for (size_t i = 0, size = oat_dex_files_.size(); i != size; ++i) { + OatDexFile* oat_dex_file = &oat_dex_files_[i]; + DCHECK_EQ(relative_offset, oat_dex_file->offset_); + DCHECK_OFFSET(); + + // Write OatDexFile. + if (!oat_dex_file->Write(this, out)) { + return 0u; + } + relative_offset += oat_dex_file->SizeOf(); + } + + return relative_offset; +} + +size_t OatWriter::WriteCode(OutputStream* out, size_t file_offset, size_t relative_offset) { if (compiler_driver_->GetCompilerOptions().IsBootImage()) { InstructionSet instruction_set = compiler_driver_->GetInstructionSet(); @@ -2253,7 +2441,7 @@ size_t OatWriter::WriteCode(OutputStream* out, const size_t file_offset, size_t } size_t OatWriter::WriteCodeDexFiles(OutputStream* out, - const size_t file_offset, + size_t file_offset, size_t relative_offset) { #define VISIT(VisitorType) \ do { \ @@ -2667,50 +2855,6 @@ bool OatWriter::WriteDexFile(OutputStream* out, return true; } -bool OatWriter::WriteOatDexFiles(OutputStream* rodata) { - TimingLogger::ScopedTiming split("WriteOatDexFiles", timings_); - - off_t initial_offset = rodata->Seek(0, kSeekCurrent); - if (initial_offset == static_cast<off_t>(-1)) { - LOG(ERROR) << "Failed to get current position in " << rodata->GetLocation(); - return false; - } - - // Seek to the start of OatDexFiles, i.e. to the end of the OatHeader. If there are - // no OatDexFiles, no data is actually written to .rodata before WriteHeader() and - // this Seek() ensures that we reserve the space for OatHeader in .rodata. - DCHECK(oat_dex_files_.empty() || oat_dex_files_[0u].offset_ == oat_header_->GetHeaderSize()); - uint32_t expected_offset = oat_data_offset_ + oat_header_->GetHeaderSize(); - off_t actual_offset = rodata->Seek(expected_offset, kSeekSet); - if (static_cast<uint32_t>(actual_offset) != expected_offset) { - PLOG(ERROR) << "Failed to seek to OatDexFile table section. Actual: " << actual_offset - << " Expected: " << expected_offset << " File: " << rodata->GetLocation(); - return false; - } - - for (size_t i = 0, size = oat_dex_files_.size(); i != size; ++i) { - OatDexFile* oat_dex_file = &oat_dex_files_[i]; - - DCHECK_EQ(oat_data_offset_ + oat_dex_file->offset_, - static_cast<size_t>(rodata->Seek(0, kSeekCurrent))); - - // Write OatDexFile. - if (!oat_dex_file->Write(this, rodata)) { - PLOG(ERROR) << "Failed to write oat dex information to " << rodata->GetLocation(); - return false; - } - } - - // Seek back to the initial position. - if (rodata->Seek(initial_offset, kSeekSet) != initial_offset) { - PLOG(ERROR) << "Failed to seek to initial position. Actual: " << actual_offset - << " Expected: " << initial_offset << " File: " << rodata->GetLocation(); - return false; - } - - return true; -} - bool OatWriter::OpenDexFiles( File* file, bool verify, @@ -2929,14 +3073,18 @@ bool OatWriter::WriteChecksumsAndVdexHeader(OutputStream* vdex_out) { } bool OatWriter::WriteCodeAlignment(OutputStream* out, uint32_t aligned_code_delta) { + return WriteUpTo16BytesAlignment(out, aligned_code_delta, &size_code_alignment_); +} + +bool OatWriter::WriteUpTo16BytesAlignment(OutputStream* out, uint32_t size, uint32_t* stat) { static const uint8_t kPadding[] = { 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u, 0u }; - DCHECK_LE(aligned_code_delta, sizeof(kPadding)); - if (UNLIKELY(!out->WriteFully(kPadding, aligned_code_delta))) { + DCHECK_LE(size, sizeof(kPadding)); + if (UNLIKELY(!out->WriteFully(kPadding, size))) { return false; } - size_code_alignment_ += aligned_code_delta; + *stat += size; return true; } @@ -2965,6 +3113,7 @@ OatWriter::OatDexFile::OatDexFile(const char* dex_file_location, dex_file_offset_(0u), class_offsets_offset_(0u), lookup_table_offset_(0u), + method_bss_mapping_offset_(0u), class_offsets_() { } @@ -2974,19 +3123,8 @@ size_t OatWriter::OatDexFile::SizeOf() const { + sizeof(dex_file_location_checksum_) + sizeof(dex_file_offset_) + sizeof(class_offsets_offset_) - + sizeof(lookup_table_offset_); -} - -void OatWriter::OatDexFile::ReserveClassOffsets(OatWriter* oat_writer) { - DCHECK_EQ(class_offsets_offset_, 0u); - if (!class_offsets_.empty()) { - // Class offsets are required to be 4 byte aligned. - size_t initial_offset = oat_writer->oat_size_; - size_t offset = RoundUp(initial_offset, 4); - oat_writer->size_oat_class_offsets_alignment_ += offset - initial_offset; - class_offsets_offset_ = offset; - oat_writer->oat_size_ = offset + GetClassOffsetsRawSize(); - } + + sizeof(lookup_table_offset_) + + sizeof(method_bss_mapping_offset_); } bool OatWriter::OatDexFile::Write(OatWriter* oat_writer, OutputStream* out) const { @@ -3029,6 +3167,12 @@ bool OatWriter::OatDexFile::Write(OatWriter* oat_writer, OutputStream* out) cons } oat_writer->size_oat_dex_file_lookup_table_offset_ += sizeof(lookup_table_offset_); + if (!out->WriteFully(&method_bss_mapping_offset_, sizeof(method_bss_mapping_offset_))) { + PLOG(ERROR) << "Failed to write method bss mapping offset to " << out->GetLocation(); + return false; + } + oat_writer->size_oat_dex_file_method_bss_mapping_offset_ += sizeof(method_bss_mapping_offset_); + return true; } diff --git a/compiler/oat_writer.h b/compiler/oat_writer.h index 66b70ade2e..9217701bc5 100644 --- a/compiler/oat_writer.h +++ b/compiler/oat_writer.h @@ -60,11 +60,6 @@ namespace verifier { // OatHeader variable length with count of D OatDexFiles // -// OatDexFile[0] one variable sized OatDexFile with offsets to Dex and OatClasses -// OatDexFile[1] -// ... -// OatDexFile[D] -// // TypeLookupTable[0] one descriptor to class def index hash table for each OatDexFile. // TypeLookupTable[1] // ... @@ -80,20 +75,25 @@ namespace verifier { // ... // OatClass[C] // -// GcMap one variable sized blob with GC map. -// GcMap GC maps are deduplicated. +// MethodBssMapping one variable sized MethodBssMapping for each dex file, optional. +// MethodBssMapping // ... -// GcMap +// MethodBssMapping // -// VmapTable one variable sized VmapTable blob (quick compiler only). +// VmapTable one variable sized VmapTable blob (CodeInfo or QuickeningInfo). // VmapTable VmapTables are deduplicated. // ... // VmapTable // -// MappingTable one variable sized blob with MappingTable (quick compiler only). -// MappingTable MappingTables are deduplicated. +// MethodInfo one variable sized blob with MethodInfo. +// MethodInfo MethodInfos are deduplicated. +// ... +// MethodInfo +// +// OatDexFile[0] one variable sized OatDexFile with offsets to Dex and OatClasses +// OatDexFile[1] // ... -// MappingTable +// OatDexFile[D] // // padding if necessary so that the following code will be page aligned // @@ -217,6 +217,10 @@ class OatWriter { return bss_size_; } + size_t GetBssMethodsOffset() const { + return bss_methods_offset_; + } + size_t GetBssRootsOffset() const { return bss_roots_offset_; } @@ -251,6 +255,7 @@ class OatWriter { // to actually write it. class DexMethodVisitor; class OatDexMethodVisitor; + class InitBssLayoutMethodVisitor; class InitOatClassesMethodVisitor; class InitCodeMethodVisitor; class InitMapMethodVisitor; @@ -295,26 +300,30 @@ class OatWriter { const InstructionSetFeatures* instruction_set_features, uint32_t num_dex_files, SafeMap<std::string, std::string>* key_value_store); - size_t InitOatDexFiles(size_t offset); + size_t InitClassOffsets(size_t offset); size_t InitOatClasses(size_t offset); size_t InitOatMaps(size_t offset); + size_t InitMethodBssMappings(size_t offset); + size_t InitOatDexFiles(size_t offset); size_t InitOatCode(size_t offset); size_t InitOatCodeDexFiles(size_t offset); void InitBssLayout(InstructionSet instruction_set); - bool WriteClassOffsets(OutputStream* out); - bool WriteClasses(OutputStream* out); - size_t WriteMaps(OutputStream* out, const size_t file_offset, size_t relative_offset); - size_t WriteCode(OutputStream* out, const size_t file_offset, size_t relative_offset); - size_t WriteCodeDexFiles(OutputStream* out, const size_t file_offset, size_t relative_offset); + size_t WriteClassOffsets(OutputStream* out, size_t file_offset, size_t relative_offset); + size_t WriteClasses(OutputStream* out, size_t file_offset, size_t relative_offset); + size_t WriteMaps(OutputStream* out, size_t file_offset, size_t relative_offset); + size_t WriteMethodBssMappings(OutputStream* out, size_t file_offset, size_t relative_offset); + size_t WriteOatDexFiles(OutputStream* out, size_t file_offset, size_t relative_offset); + size_t WriteCode(OutputStream* out, size_t file_offset, size_t relative_offset); + size_t WriteCodeDexFiles(OutputStream* out, size_t file_offset, size_t relative_offset); bool RecordOatDataOffset(OutputStream* out); bool ReadDexFileHeader(File* oat_file, OatDexFile* oat_dex_file); bool ValidateDexFileHeader(const uint8_t* raw_header, const char* location); - bool WriteOatDexFiles(OutputStream* oat_rodata); bool WriteTypeLookupTables(OutputStream* oat_rodata, const std::vector<std::unique_ptr<const DexFile>>& opened_dex_files); bool WriteCodeAlignment(OutputStream* out, uint32_t aligned_code_delta); + bool WriteUpTo16BytesAlignment(OutputStream* out, uint32_t size, uint32_t* stat); void SetMultiOatRelativePatcherAdjustment(); void CloseSources(); @@ -368,9 +377,20 @@ class OatWriter { // The size of the required .bss section holding the DexCache data and GC roots. size_t bss_size_; + // The offset of the methods in .bss section. + size_t bss_methods_offset_; + // The offset of the GC roots in .bss section. size_t bss_roots_offset_; + // Map for recording references to ArtMethod entries in .bss. + SafeMap<const DexFile*, BitVector> bss_method_entry_references_; + + // Map for allocating ArtMethod entries in .bss. Indexed by MethodReference for the target + // method in the dex file with the "method reference value comparator" for deduplication. + // The value is the target offset for patching, starting at `bss_start_ + bss_methods_offset_`. + SafeMap<MethodReference, size_t, MethodReferenceValueComparator> bss_method_entries_; + // Map for allocating Class entries in .bss. Indexed by TypeReference for the source // type in the dex file with the "type value comparator" for deduplication. The value // is the target offset for patching, starting at `bss_start_ + bss_roots_offset_`. @@ -381,10 +401,6 @@ class OatWriter { // is the target offset for patching, starting at `bss_start_ + bss_roots_offset_`. SafeMap<StringReference, size_t, StringReferenceValueComparator> bss_string_entries_; - // Offsets of the dex cache arrays for each app dex file. For the - // boot image, this information is provided by the ImageWriter. - SafeMap<const DexFile*, size_t> dex_cache_arrays_offsets_; // DexFiles not owned. - // Offset of the oat data from the start of the mmapped region of the elf file. size_t oat_data_offset_; @@ -434,6 +450,7 @@ class OatWriter { uint32_t size_oat_dex_file_offset_; uint32_t size_oat_dex_file_class_offsets_offset_; uint32_t size_oat_dex_file_lookup_table_offset_; + uint32_t size_oat_dex_file_method_bss_mapping_offset_; uint32_t size_oat_lookup_table_alignment_; uint32_t size_oat_lookup_table_; uint32_t size_oat_class_offsets_alignment_; @@ -442,6 +459,7 @@ class OatWriter { uint32_t size_oat_class_status_; uint32_t size_oat_class_method_bitmaps_; uint32_t size_oat_class_method_offsets_; + uint32_t size_method_bss_mappings_; // The helper for processing relative patches is external so that we can patch across oat files. linker::MultiOatRelativePatcher* relative_patcher_; diff --git a/compiler/optimizing/code_generator_arm.cc b/compiler/optimizing/code_generator_arm.cc index 8300f8186e..804bc0f1ff 100644 --- a/compiler/optimizing/code_generator_arm.cc +++ b/compiler/optimizing/code_generator_arm.cc @@ -2395,8 +2395,8 @@ CodeGeneratorARM::CodeGeneratorARM(HGraph* graph, isa_features_(isa_features), uint32_literals_(std::less<uint32_t>(), graph->GetArena()->Adapter(kArenaAllocCodeGenerator)), - pc_relative_dex_cache_patches_(graph->GetArena()->Adapter(kArenaAllocCodeGenerator)), pc_relative_method_patches_(graph->GetArena()->Adapter(kArenaAllocCodeGenerator)), + method_bss_entry_patches_(graph->GetArena()->Adapter(kArenaAllocCodeGenerator)), pc_relative_type_patches_(graph->GetArena()->Adapter(kArenaAllocCodeGenerator)), type_bss_entry_patches_(graph->GetArena()->Adapter(kArenaAllocCodeGenerator)), pc_relative_string_patches_(graph->GetArena()->Adapter(kArenaAllocCodeGenerator)), @@ -3553,18 +3553,10 @@ void LocationsBuilderARM::VisitInvokeStaticOrDirect(HInvokeStaticOrDirect* invok IntrinsicLocationsBuilderARM intrinsic(codegen_); if (intrinsic.TryDispatch(invoke)) { - if (invoke->GetLocations()->CanCall() && invoke->HasPcRelativeDexCache()) { - invoke->GetLocations()->SetInAt(invoke->GetSpecialInputIndex(), Location::Any()); - } return; } HandleInvoke(invoke); - - // For PC-relative dex cache the invoke has an extra input, the PC-relative address base. - if (invoke->HasPcRelativeDexCache()) { - invoke->GetLocations()->SetInAt(invoke->GetSpecialInputIndex(), Location::RequiresRegister()); - } } static bool TryGenerateIntrinsicCode(HInvoke* invoke, CodeGeneratorARM* codegen) { @@ -8981,13 +8973,17 @@ void CodeGeneratorARM::GenerateStaticOrDirectCall( case HInvokeStaticOrDirect::MethodLoadKind::kDirectAddress: __ LoadImmediate(temp.AsRegister<Register>(), invoke->GetMethodAddress()); break; - case HInvokeStaticOrDirect::MethodLoadKind::kDexCachePcRelative: { - HArmDexCacheArraysBase* base = - invoke->InputAt(invoke->GetSpecialInputIndex())->AsArmDexCacheArraysBase(); - Register base_reg = GetInvokeStaticOrDirectExtraParameter(invoke, - temp.AsRegister<Register>()); - int32_t offset = invoke->GetDexCacheArrayOffset() - base->GetElementOffset(); - __ LoadFromOffset(kLoadWord, temp.AsRegister<Register>(), base_reg, offset); + case HInvokeStaticOrDirect::MethodLoadKind::kBssEntry: { + Register temp_reg = temp.AsRegister<Register>(); + PcRelativePatchInfo* labels = NewMethodBssEntryPatch( + MethodReference(&GetGraph()->GetDexFile(), invoke->GetDexMethodIndex())); + __ BindTrackedLabel(&labels->movw_label); + __ movw(temp_reg, /* placeholder */ 0u); + __ BindTrackedLabel(&labels->movt_label); + __ movt(temp_reg, /* placeholder */ 0u); + __ BindTrackedLabel(&labels->add_pc_label); + __ add(temp_reg, temp_reg, ShifterOperand(PC)); + __ LoadFromOffset(kLoadWord, temp_reg, temp_reg, /* offset */ 0); break; } case HInvokeStaticOrDirect::MethodLoadKind::kRuntimeCall: { @@ -9056,6 +9052,13 @@ CodeGeneratorARM::PcRelativePatchInfo* CodeGeneratorARM::NewPcRelativeMethodPatc &pc_relative_method_patches_); } +CodeGeneratorARM::PcRelativePatchInfo* CodeGeneratorARM::NewMethodBssEntryPatch( + MethodReference target_method) { + return NewPcRelativePatch(*target_method.dex_file, + target_method.dex_method_index, + &method_bss_entry_patches_); +} + CodeGeneratorARM::PcRelativePatchInfo* CodeGeneratorARM::NewPcRelativeTypePatch( const DexFile& dex_file, dex::TypeIndex type_index) { return NewPcRelativePatch(dex_file, type_index.index_, &pc_relative_type_patches_); @@ -9071,11 +9074,6 @@ CodeGeneratorARM::PcRelativePatchInfo* CodeGeneratorARM::NewPcRelativeStringPatc return NewPcRelativePatch(dex_file, string_index.index_, &pc_relative_string_patches_); } -CodeGeneratorARM::PcRelativePatchInfo* CodeGeneratorARM::NewPcRelativeDexCacheArrayPatch( - const DexFile& dex_file, uint32_t element_offset) { - return NewPcRelativePatch(dex_file, element_offset, &pc_relative_dex_cache_patches_); -} - CodeGeneratorARM::PcRelativePatchInfo* CodeGeneratorARM::NewPcRelativePatch( const DexFile& dex_file, uint32_t offset_or_index, ArenaDeque<PcRelativePatchInfo>* patches) { patches->emplace_back(dex_file, offset_or_index); @@ -9134,15 +9132,13 @@ inline void CodeGeneratorARM::EmitPcRelativeLinkerPatches( void CodeGeneratorARM::EmitLinkerPatches(ArenaVector<LinkerPatch>* linker_patches) { DCHECK(linker_patches->empty()); size_t size = - /* MOVW+MOVT for each entry */ 2u * pc_relative_dex_cache_patches_.size() + /* MOVW+MOVT for each entry */ 2u * pc_relative_method_patches_.size() + + /* MOVW+MOVT for each entry */ 2u * method_bss_entry_patches_.size() + /* MOVW+MOVT for each entry */ 2u * pc_relative_type_patches_.size() + /* MOVW+MOVT for each entry */ 2u * type_bss_entry_patches_.size() + /* MOVW+MOVT for each entry */ 2u * pc_relative_string_patches_.size() + baker_read_barrier_patches_.size(); linker_patches->reserve(size); - EmitPcRelativeLinkerPatches<LinkerPatch::DexCacheArrayPatch>(pc_relative_dex_cache_patches_, - linker_patches); if (GetCompilerOptions().IsBootImage()) { EmitPcRelativeLinkerPatches<LinkerPatch::RelativeMethodPatch>(pc_relative_method_patches_, linker_patches); @@ -9156,6 +9152,8 @@ void CodeGeneratorARM::EmitLinkerPatches(ArenaVector<LinkerPatch>* linker_patche EmitPcRelativeLinkerPatches<LinkerPatch::StringBssEntryPatch>(pc_relative_string_patches_, linker_patches); } + EmitPcRelativeLinkerPatches<LinkerPatch::MethodBssEntryPatch>(method_bss_entry_patches_, + linker_patches); EmitPcRelativeLinkerPatches<LinkerPatch::TypeBssEntryPatch>(type_bss_entry_patches_, linker_patches); for (const BakerReadBarrierPatchInfo& info : baker_read_barrier_patches_) { @@ -9292,23 +9290,6 @@ void InstructionCodeGeneratorARM::VisitPackedSwitch(HPackedSwitch* switch_instr) } } -void LocationsBuilderARM::VisitArmDexCacheArraysBase(HArmDexCacheArraysBase* base) { - LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(base); - locations->SetOut(Location::RequiresRegister()); -} - -void InstructionCodeGeneratorARM::VisitArmDexCacheArraysBase(HArmDexCacheArraysBase* base) { - Register base_reg = base->GetLocations()->Out().AsRegister<Register>(); - CodeGeneratorARM::PcRelativePatchInfo* labels = - codegen_->NewPcRelativeDexCacheArrayPatch(base->GetDexFile(), base->GetElementOffset()); - __ BindTrackedLabel(&labels->movw_label); - __ movw(base_reg, /* placeholder */ 0u); - __ BindTrackedLabel(&labels->movt_label); - __ movt(base_reg, /* placeholder */ 0u); - __ BindTrackedLabel(&labels->add_pc_label); - __ add(base_reg, base_reg, ShifterOperand(PC)); -} - void CodeGeneratorARM::MoveFromReturnRegister(Location trg, Primitive::Type type) { if (!trg.IsValid()) { DCHECK_EQ(type, Primitive::kPrimVoid); diff --git a/compiler/optimizing/code_generator_arm.h b/compiler/optimizing/code_generator_arm.h index 398b6ed7d8..9280e6377c 100644 --- a/compiler/optimizing/code_generator_arm.h +++ b/compiler/optimizing/code_generator_arm.h @@ -483,12 +483,11 @@ class CodeGeneratorARM : public CodeGenerator { }; 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* NewPcRelativeStringPatch(const DexFile& dex_file, dex::StringIndex string_index); - PcRelativePatchInfo* NewPcRelativeDexCacheArrayPatch(const DexFile& dex_file, - uint32_t element_offset); // Add a new baker read barrier patch and return the label to be bound // before the BNE instruction. @@ -669,10 +668,10 @@ class CodeGeneratorARM : public CodeGenerator { // Deduplication map for 32-bit literals, used for non-patchable boot image addresses. Uint32ToLiteralMap uint32_literals_; - // PC-relative patch info for each HArmDexCacheArraysBase. - ArenaDeque<PcRelativePatchInfo> pc_relative_dex_cache_patches_; // PC-relative method patch info for kBootImageLinkTimePcRelative. ArenaDeque<PcRelativePatchInfo> pc_relative_method_patches_; + // PC-relative method patch info for kBssEntry. + ArenaDeque<PcRelativePatchInfo> method_bss_entry_patches_; // PC-relative type patch info for kBootImageLinkTimePcRelative. ArenaDeque<PcRelativePatchInfo> pc_relative_type_patches_; // PC-relative type patch info for kBssEntry. diff --git a/compiler/optimizing/code_generator_arm64.cc b/compiler/optimizing/code_generator_arm64.cc index a84f8f3308..9ba38e577f 100644 --- a/compiler/optimizing/code_generator_arm64.cc +++ b/compiler/optimizing/code_generator_arm64.cc @@ -1448,8 +1448,8 @@ CodeGeneratorARM64::CodeGeneratorARM64(HGraph* graph, graph->GetArena()->Adapter(kArenaAllocCodeGenerator)), uint64_literals_(std::less<uint64_t>(), graph->GetArena()->Adapter(kArenaAllocCodeGenerator)), - pc_relative_dex_cache_patches_(graph->GetArena()->Adapter(kArenaAllocCodeGenerator)), pc_relative_method_patches_(graph->GetArena()->Adapter(kArenaAllocCodeGenerator)), + method_bss_entry_patches_(graph->GetArena()->Adapter(kArenaAllocCodeGenerator)), pc_relative_type_patches_(graph->GetArena()->Adapter(kArenaAllocCodeGenerator)), type_bss_entry_patches_(graph->GetArena()->Adapter(kArenaAllocCodeGenerator)), pc_relative_string_patches_(graph->GetArena()->Adapter(kArenaAllocCodeGenerator)), @@ -4526,15 +4526,14 @@ void CodeGeneratorARM64::GenerateStaticOrDirectCall( // Load method address from literal pool. __ Ldr(XRegisterFrom(temp), DeduplicateUint64Literal(invoke->GetMethodAddress())); break; - case HInvokeStaticOrDirect::MethodLoadKind::kDexCachePcRelative: { + case HInvokeStaticOrDirect::MethodLoadKind::kBssEntry: { // Add ADRP with its PC-relative DexCache access patch. - const DexFile& dex_file = invoke->GetDexFileForPcRelativeDexCache(); - uint32_t element_offset = invoke->GetDexCacheArrayOffset(); - vixl::aarch64::Label* adrp_label = NewPcRelativeDexCacheArrayPatch(dex_file, element_offset); + MethodReference target_method(&GetGraph()->GetDexFile(), invoke->GetDexMethodIndex()); + vixl::aarch64::Label* adrp_label = NewMethodBssEntryPatch(target_method); EmitAdrpPlaceholder(adrp_label, XRegisterFrom(temp)); // Add LDR with its PC-relative DexCache access patch. vixl::aarch64::Label* ldr_label = - NewPcRelativeDexCacheArrayPatch(dex_file, element_offset, adrp_label); + NewMethodBssEntryPatch(target_method, adrp_label); EmitLdrOffsetPlaceholder(ldr_label, XRegisterFrom(temp), XRegisterFrom(temp)); break; } @@ -4635,6 +4634,15 @@ vixl::aarch64::Label* CodeGeneratorARM64::NewPcRelativeMethodPatch( &pc_relative_method_patches_); } +vixl::aarch64::Label* CodeGeneratorARM64::NewMethodBssEntryPatch( + MethodReference target_method, + vixl::aarch64::Label* adrp_label) { + return NewPcRelativePatch(*target_method.dex_file, + target_method.dex_method_index, + adrp_label, + &method_bss_entry_patches_); +} + vixl::aarch64::Label* CodeGeneratorARM64::NewPcRelativeTypePatch( const DexFile& dex_file, dex::TypeIndex type_index, @@ -4657,13 +4665,6 @@ vixl::aarch64::Label* CodeGeneratorARM64::NewPcRelativeStringPatch( NewPcRelativePatch(dex_file, string_index.index_, adrp_label, &pc_relative_string_patches_); } -vixl::aarch64::Label* CodeGeneratorARM64::NewPcRelativeDexCacheArrayPatch( - const DexFile& dex_file, - uint32_t element_offset, - vixl::aarch64::Label* adrp_label) { - return NewPcRelativePatch(dex_file, element_offset, adrp_label, &pc_relative_dex_cache_patches_); -} - vixl::aarch64::Label* CodeGeneratorARM64::NewBakerReadBarrierPatch(uint32_t custom_data) { baker_read_barrier_patches_.emplace_back(custom_data); return &baker_read_barrier_patches_.back().label; @@ -4685,7 +4686,7 @@ vixl::aarch64::Label* CodeGeneratorARM64::NewPcRelativePatch( vixl::aarch64::Literal<uint32_t>* CodeGeneratorARM64::DeduplicateBootImageAddressLiteral( uint64_t address) { - return DeduplicateUint32Literal(dchecked_integral_cast<uint32_t>(address), &uint32_literals_); + return DeduplicateUint32Literal(dchecked_integral_cast<uint32_t>(address)); } vixl::aarch64::Literal<uint32_t>* CodeGeneratorARM64::DeduplicateJitStringLiteral( @@ -4748,19 +4749,13 @@ inline void CodeGeneratorARM64::EmitPcRelativeLinkerPatches( void CodeGeneratorARM64::EmitLinkerPatches(ArenaVector<LinkerPatch>* linker_patches) { DCHECK(linker_patches->empty()); size_t size = - pc_relative_dex_cache_patches_.size() + pc_relative_method_patches_.size() + + method_bss_entry_patches_.size() + pc_relative_type_patches_.size() + type_bss_entry_patches_.size() + pc_relative_string_patches_.size() + baker_read_barrier_patches_.size(); linker_patches->reserve(size); - for (const PcRelativePatchInfo& info : pc_relative_dex_cache_patches_) { - linker_patches->push_back(LinkerPatch::DexCacheArrayPatch(info.label.GetLocation(), - &info.target_dex_file, - info.pc_insn_label->GetLocation(), - info.offset_or_index)); - } if (GetCompilerOptions().IsBootImage()) { EmitPcRelativeLinkerPatches<LinkerPatch::RelativeMethodPatch>(pc_relative_method_patches_, linker_patches); @@ -4774,6 +4769,8 @@ void CodeGeneratorARM64::EmitLinkerPatches(ArenaVector<LinkerPatch>* linker_patc EmitPcRelativeLinkerPatches<LinkerPatch::StringBssEntryPatch>(pc_relative_string_patches_, linker_patches); } + EmitPcRelativeLinkerPatches<LinkerPatch::MethodBssEntryPatch>(method_bss_entry_patches_, + linker_patches); EmitPcRelativeLinkerPatches<LinkerPatch::TypeBssEntryPatch>(type_bss_entry_patches_, linker_patches); for (const BakerReadBarrierPatchInfo& info : baker_read_barrier_patches_) { @@ -4783,9 +4780,8 @@ void CodeGeneratorARM64::EmitLinkerPatches(ArenaVector<LinkerPatch>* linker_patc DCHECK_EQ(size, linker_patches->size()); } -vixl::aarch64::Literal<uint32_t>* CodeGeneratorARM64::DeduplicateUint32Literal(uint32_t value, - Uint32ToLiteralMap* map) { - return map->GetOrCreate( +vixl::aarch64::Literal<uint32_t>* CodeGeneratorARM64::DeduplicateUint32Literal(uint32_t value) { + return uint32_literals_.GetOrCreate( value, [this, value]() { return __ CreateLiteralDestroyedWithPool<uint32_t>(value); }); } diff --git a/compiler/optimizing/code_generator_arm64.h b/compiler/optimizing/code_generator_arm64.h index 5bb2ab57df..d9c49d19bb 100644 --- a/compiler/optimizing/code_generator_arm64.h +++ b/compiler/optimizing/code_generator_arm64.h @@ -557,6 +557,13 @@ class CodeGeneratorARM64 : public CodeGenerator { vixl::aarch64::Label* NewPcRelativeMethodPatch(MethodReference target_method, vixl::aarch64::Label* adrp_label = nullptr); + // Add a new .bss entry method patch for an instruction and return + // the label to be bound before the instruction. The instruction will be + // either the ADRP (pass `adrp_label = null`) or the LDR (pass `adrp_label` + // pointing to the associated ADRP patch label). + vixl::aarch64::Label* NewMethodBssEntryPatch(MethodReference target_method, + vixl::aarch64::Label* adrp_label = nullptr); + // Add a new PC-relative type patch for an instruction and return the label // to be bound before the instruction. The instruction will be either the // ADRP (pass `adrp_label = null`) or the ADD (pass `adrp_label` pointing @@ -581,15 +588,6 @@ class CodeGeneratorARM64 : public CodeGenerator { dex::StringIndex string_index, vixl::aarch64::Label* adrp_label = nullptr); - // Add a new PC-relative dex cache array patch for an instruction and return - // the label to be bound before the instruction. The instruction will be - // either the ADRP (pass `adrp_label = null`) or the LDR (pass `adrp_label` - // pointing to the associated ADRP patch label). - vixl::aarch64::Label* NewPcRelativeDexCacheArrayPatch( - const DexFile& dex_file, - uint32_t element_offset, - vixl::aarch64::Label* adrp_label = nullptr); - // Add a new baker read barrier patch and return the label to be bound // before the CBNZ instruction. vixl::aarch64::Label* NewBakerReadBarrierPatch(uint32_t custom_data); @@ -741,8 +739,7 @@ class CodeGeneratorARM64 : public CodeGenerator { vixl::aarch64::Literal<uint32_t>*, TypeReferenceValueComparator>; - vixl::aarch64::Literal<uint32_t>* DeduplicateUint32Literal(uint32_t value, - Uint32ToLiteralMap* map); + vixl::aarch64::Literal<uint32_t>* DeduplicateUint32Literal(uint32_t value); vixl::aarch64::Literal<uint64_t>* DeduplicateUint64Literal(uint64_t value); // The PcRelativePatchInfo is used for PC-relative addressing of dex cache arrays @@ -793,10 +790,10 @@ class CodeGeneratorARM64 : public CodeGenerator { Uint32ToLiteralMap uint32_literals_; // Deduplication map for 64-bit literals, used for non-patchable method address or method code. Uint64ToLiteralMap uint64_literals_; - // PC-relative DexCache access info. - ArenaDeque<PcRelativePatchInfo> pc_relative_dex_cache_patches_; // PC-relative method patch info for kBootImageLinkTimePcRelative. ArenaDeque<PcRelativePatchInfo> pc_relative_method_patches_; + // PC-relative method patch info for kBssEntry. + ArenaDeque<PcRelativePatchInfo> method_bss_entry_patches_; // PC-relative type patch info for kBootImageLinkTimePcRelative. ArenaDeque<PcRelativePatchInfo> pc_relative_type_patches_; // PC-relative type patch info for kBssEntry. diff --git a/compiler/optimizing/code_generator_arm_vixl.cc b/compiler/optimizing/code_generator_arm_vixl.cc index d5e3723e68..9cd776139b 100644 --- a/compiler/optimizing/code_generator_arm_vixl.cc +++ b/compiler/optimizing/code_generator_arm_vixl.cc @@ -2499,8 +2499,8 @@ CodeGeneratorARMVIXL::CodeGeneratorARMVIXL(HGraph* graph, isa_features_(isa_features), uint32_literals_(std::less<uint32_t>(), graph->GetArena()->Adapter(kArenaAllocCodeGenerator)), - pc_relative_dex_cache_patches_(graph->GetArena()->Adapter(kArenaAllocCodeGenerator)), pc_relative_method_patches_(graph->GetArena()->Adapter(kArenaAllocCodeGenerator)), + method_bss_entry_patches_(graph->GetArena()->Adapter(kArenaAllocCodeGenerator)), pc_relative_type_patches_(graph->GetArena()->Adapter(kArenaAllocCodeGenerator)), type_bss_entry_patches_(graph->GetArena()->Adapter(kArenaAllocCodeGenerator)), pc_relative_string_patches_(graph->GetArena()->Adapter(kArenaAllocCodeGenerator)), @@ -3642,18 +3642,10 @@ void LocationsBuilderARMVIXL::VisitInvokeStaticOrDirect(HInvokeStaticOrDirect* i IntrinsicLocationsBuilderARMVIXL intrinsic(codegen_); if (intrinsic.TryDispatch(invoke)) { - if (invoke->GetLocations()->CanCall() && invoke->HasPcRelativeDexCache()) { - invoke->GetLocations()->SetInAt(invoke->GetSpecialInputIndex(), Location::Any()); - } return; } HandleInvoke(invoke); - - // For PC-relative dex cache the invoke has an extra input, the PC-relative address base. - if (invoke->HasPcRelativeDexCache()) { - invoke->GetLocations()->SetInAt(invoke->GetSpecialInputIndex(), Location::RequiresRegister()); - } } static bool TryGenerateIntrinsicCode(HInvoke* invoke, CodeGeneratorARMVIXL* codegen) { @@ -9140,12 +9132,12 @@ void CodeGeneratorARMVIXL::GenerateStaticOrDirectCall( case HInvokeStaticOrDirect::MethodLoadKind::kDirectAddress: __ Mov(RegisterFrom(temp), Operand::From(invoke->GetMethodAddress())); break; - case HInvokeStaticOrDirect::MethodLoadKind::kDexCachePcRelative: { - HArmDexCacheArraysBase* base = - invoke->InputAt(invoke->GetSpecialInputIndex())->AsArmDexCacheArraysBase(); - vixl32::Register base_reg = GetInvokeStaticOrDirectExtraParameter(invoke, RegisterFrom(temp)); - int32_t offset = invoke->GetDexCacheArrayOffset() - base->GetElementOffset(); - GetAssembler()->LoadFromOffset(kLoadWord, RegisterFrom(temp), base_reg, offset); + case HInvokeStaticOrDirect::MethodLoadKind::kBssEntry: { + PcRelativePatchInfo* labels = NewMethodBssEntryPatch( + MethodReference(&GetGraph()->GetDexFile(), invoke->GetDexMethodIndex())); + vixl32::Register temp_reg = RegisterFrom(temp); + EmitMovwMovtPlaceholder(labels, temp_reg); + GetAssembler()->LoadFromOffset(kLoadWord, temp_reg, temp_reg, /* offset*/ 0); break; } case HInvokeStaticOrDirect::MethodLoadKind::kRuntimeCall: { @@ -9244,6 +9236,13 @@ CodeGeneratorARMVIXL::PcRelativePatchInfo* CodeGeneratorARMVIXL::NewPcRelativeMe &pc_relative_method_patches_); } +CodeGeneratorARMVIXL::PcRelativePatchInfo* CodeGeneratorARMVIXL::NewMethodBssEntryPatch( + MethodReference target_method) { + return NewPcRelativePatch(*target_method.dex_file, + target_method.dex_method_index, + &method_bss_entry_patches_); +} + CodeGeneratorARMVIXL::PcRelativePatchInfo* CodeGeneratorARMVIXL::NewPcRelativeTypePatch( const DexFile& dex_file, dex::TypeIndex type_index) { return NewPcRelativePatch(dex_file, type_index.index_, &pc_relative_type_patches_); @@ -9259,11 +9258,6 @@ CodeGeneratorARMVIXL::PcRelativePatchInfo* CodeGeneratorARMVIXL::NewPcRelativeSt return NewPcRelativePatch(dex_file, string_index.index_, &pc_relative_string_patches_); } -CodeGeneratorARMVIXL::PcRelativePatchInfo* CodeGeneratorARMVIXL::NewPcRelativeDexCacheArrayPatch( - const DexFile& dex_file, uint32_t element_offset) { - return NewPcRelativePatch(dex_file, element_offset, &pc_relative_dex_cache_patches_); -} - CodeGeneratorARMVIXL::PcRelativePatchInfo* CodeGeneratorARMVIXL::NewPcRelativePatch( const DexFile& dex_file, uint32_t offset_or_index, ArenaDeque<PcRelativePatchInfo>* patches) { patches->emplace_back(dex_file, offset_or_index); @@ -9327,15 +9321,13 @@ inline void CodeGeneratorARMVIXL::EmitPcRelativeLinkerPatches( void CodeGeneratorARMVIXL::EmitLinkerPatches(ArenaVector<LinkerPatch>* linker_patches) { DCHECK(linker_patches->empty()); size_t size = - /* MOVW+MOVT for each entry */ 2u * pc_relative_dex_cache_patches_.size() + /* MOVW+MOVT for each entry */ 2u * pc_relative_method_patches_.size() + + /* MOVW+MOVT for each entry */ 2u * method_bss_entry_patches_.size() + /* MOVW+MOVT for each entry */ 2u * pc_relative_type_patches_.size() + /* MOVW+MOVT for each entry */ 2u * type_bss_entry_patches_.size() + /* MOVW+MOVT for each entry */ 2u * pc_relative_string_patches_.size() + baker_read_barrier_patches_.size(); linker_patches->reserve(size); - EmitPcRelativeLinkerPatches<LinkerPatch::DexCacheArrayPatch>(pc_relative_dex_cache_patches_, - linker_patches); if (GetCompilerOptions().IsBootImage()) { EmitPcRelativeLinkerPatches<LinkerPatch::RelativeMethodPatch>(pc_relative_method_patches_, linker_patches); @@ -9349,6 +9341,8 @@ void CodeGeneratorARMVIXL::EmitLinkerPatches(ArenaVector<LinkerPatch>* linker_pa EmitPcRelativeLinkerPatches<LinkerPatch::StringBssEntryPatch>(pc_relative_string_patches_, linker_patches); } + EmitPcRelativeLinkerPatches<LinkerPatch::MethodBssEntryPatch>(method_bss_entry_patches_, + linker_patches); EmitPcRelativeLinkerPatches<LinkerPatch::TypeBssEntryPatch>(type_bss_entry_patches_, linker_patches); for (const BakerReadBarrierPatchInfo& info : baker_read_barrier_patches_) { @@ -9498,17 +9492,6 @@ void InstructionCodeGeneratorARMVIXL::VisitPackedSwitch(HPackedSwitch* switch_in } } } -void LocationsBuilderARMVIXL::VisitArmDexCacheArraysBase(HArmDexCacheArraysBase* base) { - LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(base); - locations->SetOut(Location::RequiresRegister()); -} - -void InstructionCodeGeneratorARMVIXL::VisitArmDexCacheArraysBase(HArmDexCacheArraysBase* base) { - vixl32::Register base_reg = OutputRegister(base); - CodeGeneratorARMVIXL::PcRelativePatchInfo* labels = - codegen_->NewPcRelativeDexCacheArrayPatch(base->GetDexFile(), base->GetElementOffset()); - codegen_->EmitMovwMovtPlaceholder(labels, base_reg); -} // Copy the result of a call into the given target. void CodeGeneratorARMVIXL::MoveFromReturnRegister(Location trg, Primitive::Type type) { diff --git a/compiler/optimizing/code_generator_arm_vixl.h b/compiler/optimizing/code_generator_arm_vixl.h index 5320f71290..805a3f4366 100644 --- a/compiler/optimizing/code_generator_arm_vixl.h +++ b/compiler/optimizing/code_generator_arm_vixl.h @@ -566,12 +566,11 @@ class CodeGeneratorARMVIXL : public CodeGenerator { }; 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* NewPcRelativeStringPatch(const DexFile& dex_file, dex::StringIndex string_index); - PcRelativePatchInfo* NewPcRelativeDexCacheArrayPatch(const DexFile& dex_file, - uint32_t element_offset); // Add a new baker read barrier patch and return the label to be bound // before the BNE instruction. @@ -766,10 +765,10 @@ class CodeGeneratorARMVIXL : public CodeGenerator { // Deduplication map for 32-bit literals, used for non-patchable boot image addresses. Uint32ToLiteralMap uint32_literals_; - // PC-relative patch info for each HArmDexCacheArraysBase. - ArenaDeque<PcRelativePatchInfo> pc_relative_dex_cache_patches_; // PC-relative method patch info for kBootImageLinkTimePcRelative. ArenaDeque<PcRelativePatchInfo> pc_relative_method_patches_; + // PC-relative method patch info for kBssEntry. + ArenaDeque<PcRelativePatchInfo> method_bss_entry_patches_; // PC-relative type patch info for kBootImageLinkTimePcRelative. ArenaDeque<PcRelativePatchInfo> pc_relative_type_patches_; // PC-relative type patch info for kBssEntry. diff --git a/compiler/optimizing/code_generator_mips.cc b/compiler/optimizing/code_generator_mips.cc index 8560e3e5f6..b39d412ac2 100644 --- a/compiler/optimizing/code_generator_mips.cc +++ b/compiler/optimizing/code_generator_mips.cc @@ -40,10 +40,6 @@ namespace mips { static constexpr int kCurrentMethodStackOffset = 0; static constexpr Register kMethodRegisterArgument = A0; -// We'll maximize the range of a single load instruction for dex cache array accesses -// by aligning offset -32768 with the offset of the first used element. -static constexpr uint32_t kDexCacheArrayLwOffset = 0x8000; - Location MipsReturnLocation(Primitive::Type return_type) { switch (return_type) { case Primitive::kPrimBoolean: @@ -1060,8 +1056,8 @@ CodeGeneratorMIPS::CodeGeneratorMIPS(HGraph* graph, isa_features_(isa_features), uint32_literals_(std::less<uint32_t>(), graph->GetArena()->Adapter(kArenaAllocCodeGenerator)), - pc_relative_dex_cache_patches_(graph->GetArena()->Adapter(kArenaAllocCodeGenerator)), pc_relative_method_patches_(graph->GetArena()->Adapter(kArenaAllocCodeGenerator)), + method_bss_entry_patches_(graph->GetArena()->Adapter(kArenaAllocCodeGenerator)), pc_relative_type_patches_(graph->GetArena()->Adapter(kArenaAllocCodeGenerator)), type_bss_entry_patches_(graph->GetArena()->Adapter(kArenaAllocCodeGenerator)), pc_relative_string_patches_(graph->GetArena()->Adapter(kArenaAllocCodeGenerator)), @@ -1602,14 +1598,12 @@ inline void CodeGeneratorMIPS::EmitPcRelativeLinkerPatches( void CodeGeneratorMIPS::EmitLinkerPatches(ArenaVector<LinkerPatch>* linker_patches) { DCHECK(linker_patches->empty()); size_t size = - pc_relative_dex_cache_patches_.size() + pc_relative_method_patches_.size() + + method_bss_entry_patches_.size() + pc_relative_type_patches_.size() + type_bss_entry_patches_.size() + pc_relative_string_patches_.size(); linker_patches->reserve(size); - EmitPcRelativeLinkerPatches<LinkerPatch::DexCacheArrayPatch>(pc_relative_dex_cache_patches_, - linker_patches); if (GetCompilerOptions().IsBootImage()) { EmitPcRelativeLinkerPatches<LinkerPatch::RelativeMethodPatch>(pc_relative_method_patches_, linker_patches); @@ -1623,6 +1617,8 @@ void CodeGeneratorMIPS::EmitLinkerPatches(ArenaVector<LinkerPatch>* linker_patch EmitPcRelativeLinkerPatches<LinkerPatch::StringBssEntryPatch>(pc_relative_string_patches_, linker_patches); } + EmitPcRelativeLinkerPatches<LinkerPatch::MethodBssEntryPatch>(method_bss_entry_patches_, + linker_patches); EmitPcRelativeLinkerPatches<LinkerPatch::TypeBssEntryPatch>(type_bss_entry_patches_, linker_patches); DCHECK_EQ(size, linker_patches->size()); @@ -1635,6 +1631,13 @@ CodeGeneratorMIPS::PcRelativePatchInfo* CodeGeneratorMIPS::NewPcRelativeMethodPa &pc_relative_method_patches_); } +CodeGeneratorMIPS::PcRelativePatchInfo* CodeGeneratorMIPS::NewMethodBssEntryPatch( + MethodReference target_method) { + return NewPcRelativePatch(*target_method.dex_file, + target_method.dex_method_index, + &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_); @@ -1650,11 +1653,6 @@ CodeGeneratorMIPS::PcRelativePatchInfo* CodeGeneratorMIPS::NewPcRelativeStringPa return NewPcRelativePatch(dex_file, string_index.index_, &pc_relative_string_patches_); } -CodeGeneratorMIPS::PcRelativePatchInfo* CodeGeneratorMIPS::NewPcRelativeDexCacheArrayPatch( - const DexFile& dex_file, uint32_t element_offset) { - return NewPcRelativePatch(dex_file, element_offset, &pc_relative_dex_cache_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); @@ -7000,7 +6998,7 @@ HLoadString::LoadKind CodeGeneratorMIPS::GetSupportedLoadStringKind( HLoadString::LoadKind desired_string_load_kind) { // We disable PC-relative load on pre-R6 when there is an irreducible loop, as the optimization // is incompatible with it. - // TODO: Create as many MipsDexCacheArraysBase instructions as needed for methods + // TODO: Create as many HMipsComputeBaseMethodAddress instructions as needed for methods // with irreducible loops. bool has_irreducible_loops = GetGraph()->HasIrreducibleLoops(); bool is_r6 = GetInstructionSetFeatures().IsR6(); @@ -7030,6 +7028,8 @@ HLoadClass::LoadKind CodeGeneratorMIPS::GetSupportedLoadClassKind( HLoadClass::LoadKind desired_class_load_kind) { // We disable PC-relative load on pre-R6 when there is an irreducible loop, as the optimization // is incompatible with it. + // TODO: Create as many HMipsComputeBaseMethodAddress instructions as needed for methods + // with irreducible loops. bool has_irreducible_loops = GetGraph()->HasIrreducibleLoops(); bool is_r6 = GetInstructionSetFeatures().IsR6(); bool fallback_load = has_irreducible_loops && !is_r6; @@ -7093,12 +7093,14 @@ HInvokeStaticOrDirect::DispatchInfo CodeGeneratorMIPS::GetSupportedInvokeStaticO HInvokeStaticOrDirect::DispatchInfo dispatch_info = desired_dispatch_info; // We disable PC-relative load on pre-R6 when there is an irreducible loop, as the optimization // is incompatible with it. + // TODO: Create as many HMipsComputeBaseMethodAddress instructions as needed for methods + // with irreducible loops. bool has_irreducible_loops = GetGraph()->HasIrreducibleLoops(); bool is_r6 = GetInstructionSetFeatures().IsR6(); bool fallback_load = has_irreducible_loops && !is_r6; switch (dispatch_info.method_load_kind) { case HInvokeStaticOrDirect::MethodLoadKind::kBootImageLinkTimePcRelative: - case HInvokeStaticOrDirect::MethodLoadKind::kDexCachePcRelative: + case HInvokeStaticOrDirect::MethodLoadKind::kBssEntry: break; default: fallback_load = false; @@ -7149,23 +7151,16 @@ void CodeGeneratorMIPS::GenerateStaticOrDirectCall( case HInvokeStaticOrDirect::MethodLoadKind::kDirectAddress: __ LoadConst32(temp.AsRegister<Register>(), invoke->GetMethodAddress()); break; - case HInvokeStaticOrDirect::MethodLoadKind::kDexCachePcRelative: - if (is_r6) { - uint32_t offset = invoke->GetDexCacheArrayOffset(); - CodeGeneratorMIPS::PcRelativePatchInfo* info = - NewPcRelativeDexCacheArrayPatch(invoke->GetDexFileForPcRelativeDexCache(), offset); - bool reordering = __ SetReorder(false); - EmitPcRelativeAddressPlaceholderHigh(info, TMP, ZERO); - __ Lw(temp.AsRegister<Register>(), TMP, /* placeholder */ 0x5678); - __ SetReorder(reordering); - } else { - HMipsDexCacheArraysBase* base = - invoke->InputAt(invoke->GetSpecialInputIndex())->AsMipsDexCacheArraysBase(); - int32_t offset = - invoke->GetDexCacheArrayOffset() - base->GetElementOffset() - kDexCacheArrayLwOffset; - __ LoadFromOffset(kLoadWord, temp.AsRegister<Register>(), base_reg, offset); - } + case HInvokeStaticOrDirect::MethodLoadKind::kBssEntry: { + PcRelativePatchInfo* info = NewMethodBssEntryPatch( + MethodReference(&GetGraph()->GetDexFile(), invoke->GetDexMethodIndex())); + Register temp_reg = temp.AsRegister<Register>(); + bool reordering = __ SetReorder(false); + EmitPcRelativeAddressPlaceholderHigh(info, TMP, base_reg); + __ Lw(temp_reg, TMP, /* placeholder */ 0x5678); + __ SetReorder(reordering); break; + } case HInvokeStaticOrDirect::MethodLoadKind::kRuntimeCall: { GenerateInvokeStaticOrDirectRuntimeCall(invoke, temp, slow_path); return; // No code pointer retrieval; the runtime performs the call directly. @@ -8711,29 +8706,11 @@ void InstructionCodeGeneratorMIPS::VisitMipsComputeBaseMethodAddress( __ Nal(); // Grab the return address off RA. __ Move(reg, RA); - // TODO: Can we share this code with that of VisitMipsDexCacheArraysBase()? // Remember this offset (the obtained PC value) for later use with constant area. __ BindPcRelBaseLabel(); } -void LocationsBuilderMIPS::VisitMipsDexCacheArraysBase(HMipsDexCacheArraysBase* base) { - LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(base); - locations->SetOut(Location::RequiresRegister()); -} - -void InstructionCodeGeneratorMIPS::VisitMipsDexCacheArraysBase(HMipsDexCacheArraysBase* base) { - Register reg = base->GetLocations()->Out().AsRegister<Register>(); - CodeGeneratorMIPS::PcRelativePatchInfo* info = - codegen_->NewPcRelativeDexCacheArrayPatch(base->GetDexFile(), base->GetElementOffset()); - CHECK(!codegen_->GetInstructionSetFeatures().IsR6()); - bool reordering = __ SetReorder(false); - // TODO: Reuse MipsComputeBaseMethodAddress on R2 instead of passing ZERO to force emitting NAL. - codegen_->EmitPcRelativeAddressPlaceholderHigh(info, reg, ZERO); - __ Addiu(reg, reg, /* placeholder */ 0x5678); - __ SetReorder(reordering); -} - void LocationsBuilderMIPS::VisitInvokeUnresolved(HInvokeUnresolved* invoke) { // The trampoline uses the same calling convention as dex calling conventions, // except instead of loading arg0/r0 with the target Method*, arg0/r0 will contain diff --git a/compiler/optimizing/code_generator_mips.h b/compiler/optimizing/code_generator_mips.h index d774219ba9..e72e838dd9 100644 --- a/compiler/optimizing/code_generator_mips.h +++ b/compiler/optimizing/code_generator_mips.h @@ -585,12 +585,11 @@ class CodeGeneratorMIPS : public CodeGenerator { }; 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* NewPcRelativeStringPatch(const DexFile& dex_file, dex::StringIndex string_index); - PcRelativePatchInfo* NewPcRelativeDexCacheArrayPatch(const DexFile& dex_file, - uint32_t element_offset); Literal* DeduplicateBootImageAddressLiteral(uint32_t address); void EmitPcRelativeAddressPlaceholderHigh(PcRelativePatchInfo* info, Register out, Register base); @@ -645,10 +644,10 @@ class CodeGeneratorMIPS : public CodeGenerator { // Deduplication map for 32-bit literals, used for non-patchable boot image addresses. Uint32ToLiteralMap uint32_literals_; - // PC-relative patch info for each HMipsDexCacheArraysBase. - ArenaDeque<PcRelativePatchInfo> pc_relative_dex_cache_patches_; // PC-relative method patch info for kBootImageLinkTimePcRelative. ArenaDeque<PcRelativePatchInfo> pc_relative_method_patches_; + // PC-relative method patch info for kBssEntry. + ArenaDeque<PcRelativePatchInfo> method_bss_entry_patches_; // PC-relative type patch info for kBootImageLinkTimePcRelative. ArenaDeque<PcRelativePatchInfo> pc_relative_type_patches_; // PC-relative type patch info for kBssEntry. diff --git a/compiler/optimizing/code_generator_mips64.cc b/compiler/optimizing/code_generator_mips64.cc index da43c4e757..e4f1cbd600 100644 --- a/compiler/optimizing/code_generator_mips64.cc +++ b/compiler/optimizing/code_generator_mips64.cc @@ -957,8 +957,8 @@ CodeGeneratorMIPS64::CodeGeneratorMIPS64(HGraph* graph, graph->GetArena()->Adapter(kArenaAllocCodeGenerator)), uint64_literals_(std::less<uint64_t>(), graph->GetArena()->Adapter(kArenaAllocCodeGenerator)), - pc_relative_dex_cache_patches_(graph->GetArena()->Adapter(kArenaAllocCodeGenerator)), pc_relative_method_patches_(graph->GetArena()->Adapter(kArenaAllocCodeGenerator)), + method_bss_entry_patches_(graph->GetArena()->Adapter(kArenaAllocCodeGenerator)), pc_relative_type_patches_(graph->GetArena()->Adapter(kArenaAllocCodeGenerator)), type_bss_entry_patches_(graph->GetArena()->Adapter(kArenaAllocCodeGenerator)), pc_relative_string_patches_(graph->GetArena()->Adapter(kArenaAllocCodeGenerator)), @@ -1440,14 +1440,12 @@ inline void CodeGeneratorMIPS64::EmitPcRelativeLinkerPatches( void CodeGeneratorMIPS64::EmitLinkerPatches(ArenaVector<LinkerPatch>* linker_patches) { DCHECK(linker_patches->empty()); size_t size = - pc_relative_dex_cache_patches_.size() + pc_relative_method_patches_.size() + + method_bss_entry_patches_.size() + pc_relative_type_patches_.size() + type_bss_entry_patches_.size() + pc_relative_string_patches_.size(); linker_patches->reserve(size); - EmitPcRelativeLinkerPatches<LinkerPatch::DexCacheArrayPatch>(pc_relative_dex_cache_patches_, - linker_patches); if (GetCompilerOptions().IsBootImage()) { EmitPcRelativeLinkerPatches<LinkerPatch::RelativeMethodPatch>(pc_relative_method_patches_, linker_patches); @@ -1461,6 +1459,8 @@ void CodeGeneratorMIPS64::EmitLinkerPatches(ArenaVector<LinkerPatch>* linker_pat EmitPcRelativeLinkerPatches<LinkerPatch::StringBssEntryPatch>(pc_relative_string_patches_, linker_patches); } + EmitPcRelativeLinkerPatches<LinkerPatch::MethodBssEntryPatch>(method_bss_entry_patches_, + linker_patches); EmitPcRelativeLinkerPatches<LinkerPatch::TypeBssEntryPatch>(type_bss_entry_patches_, linker_patches); DCHECK_EQ(size, linker_patches->size()); @@ -1473,6 +1473,13 @@ CodeGeneratorMIPS64::PcRelativePatchInfo* CodeGeneratorMIPS64::NewPcRelativeMeth &pc_relative_method_patches_); } +CodeGeneratorMIPS64::PcRelativePatchInfo* CodeGeneratorMIPS64::NewMethodBssEntryPatch( + MethodReference target_method) { + return NewPcRelativePatch(*target_method.dex_file, + target_method.dex_method_index, + &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_); @@ -1488,11 +1495,6 @@ CodeGeneratorMIPS64::PcRelativePatchInfo* CodeGeneratorMIPS64::NewPcRelativeStri return NewPcRelativePatch(dex_file, string_index.index_, &pc_relative_string_patches_); } -CodeGeneratorMIPS64::PcRelativePatchInfo* CodeGeneratorMIPS64::NewPcRelativeDexCacheArrayPatch( - const DexFile& dex_file, uint32_t element_offset) { - return NewPcRelativePatch(dex_file, element_offset, &pc_relative_dex_cache_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); @@ -4949,10 +4951,9 @@ void CodeGeneratorMIPS64::GenerateStaticOrDirectCall( kLoadDoubleword, DeduplicateUint64Literal(invoke->GetMethodAddress())); break; - case HInvokeStaticOrDirect::MethodLoadKind::kDexCachePcRelative: { - uint32_t offset = invoke->GetDexCacheArrayOffset(); - CodeGeneratorMIPS64::PcRelativePatchInfo* info = - NewPcRelativeDexCacheArrayPatch(invoke->GetDexFileForPcRelativeDexCache(), offset); + case HInvokeStaticOrDirect::MethodLoadKind::kBssEntry: { + PcRelativePatchInfo* info = NewMethodBssEntryPatch( + MethodReference(&GetGraph()->GetDexFile(), invoke->GetDexMethodIndex())); EmitPcRelativeAddressPlaceholderHigh(info, AT); __ Ld(temp.AsRegister<GpuRegister>(), AT, /* placeholder */ 0x5678); break; diff --git a/compiler/optimizing/code_generator_mips64.h b/compiler/optimizing/code_generator_mips64.h index 2e8af2185a..6260c73614 100644 --- a/compiler/optimizing/code_generator_mips64.h +++ b/compiler/optimizing/code_generator_mips64.h @@ -551,12 +551,11 @@ class CodeGeneratorMIPS64 : public CodeGenerator { }; 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* NewPcRelativeStringPatch(const DexFile& dex_file, dex::StringIndex string_index); - PcRelativePatchInfo* NewPcRelativeDexCacheArrayPatch(const DexFile& dex_file, - uint32_t element_offset); PcRelativePatchInfo* NewPcRelativeCallPatch(const DexFile& dex_file, uint32_t method_index); Literal* DeduplicateBootImageAddressLiteral(uint64_t address); @@ -609,10 +608,10 @@ class CodeGeneratorMIPS64 : public CodeGenerator { // Deduplication map for 64-bit literals, used for non-patchable method address or method code // address. Uint64ToLiteralMap uint64_literals_; - // PC-relative patch info. - ArenaDeque<PcRelativePatchInfo> pc_relative_dex_cache_patches_; // PC-relative method patch info for kBootImageLinkTimePcRelative. ArenaDeque<PcRelativePatchInfo> pc_relative_method_patches_; + // PC-relative method patch info for kBssEntry. + ArenaDeque<PcRelativePatchInfo> method_bss_entry_patches_; // PC-relative type patch info for kBootImageLinkTimePcRelative. ArenaDeque<PcRelativePatchInfo> pc_relative_type_patches_; // PC-relative type patch info for kBssEntry. diff --git a/compiler/optimizing/code_generator_x86.cc b/compiler/optimizing/code_generator_x86.cc index ca921b843e..83a261d334 100644 --- a/compiler/optimizing/code_generator_x86.cc +++ b/compiler/optimizing/code_generator_x86.cc @@ -1032,8 +1032,8 @@ CodeGeneratorX86::CodeGeneratorX86(HGraph* graph, move_resolver_(graph->GetArena(), this), assembler_(graph->GetArena()), isa_features_(isa_features), - pc_relative_dex_cache_patches_(graph->GetArena()->Adapter(kArenaAllocCodeGenerator)), boot_image_method_patches_(graph->GetArena()->Adapter(kArenaAllocCodeGenerator)), + method_bss_entry_patches_(graph->GetArena()->Adapter(kArenaAllocCodeGenerator)), boot_image_type_patches_(graph->GetArena()->Adapter(kArenaAllocCodeGenerator)), type_bss_entry_patches_(graph->GetArena()->Adapter(kArenaAllocCodeGenerator)), string_patches_(graph->GetArena()->Adapter(kArenaAllocCodeGenerator)), @@ -4553,16 +4553,14 @@ void CodeGeneratorX86::GenerateStaticOrDirectCall( case HInvokeStaticOrDirect::MethodLoadKind::kDirectAddress: __ movl(temp.AsRegister<Register>(), Immediate(invoke->GetMethodAddress())); break; - case HInvokeStaticOrDirect::MethodLoadKind::kDexCachePcRelative: { + case HInvokeStaticOrDirect::MethodLoadKind::kBssEntry: { Register base_reg = GetInvokeStaticOrDirectExtraParameter(invoke, temp.AsRegister<Register>()); __ movl(temp.AsRegister<Register>(), Address(base_reg, kDummy32BitOffset)); // Bind a new fixup label at the end of the "movl" insn. - uint32_t offset = invoke->GetDexCacheArrayOffset(); - __ Bind(NewPcRelativeDexCacheArrayPatch( + __ Bind(NewMethodBssEntryPatch( invoke->InputAt(invoke->GetSpecialInputIndex())->AsX86ComputeBaseMethodAddress(), - invoke->GetDexFileForPcRelativeDexCache(), - offset)); + MethodReference(&GetGraph()->GetDexFile(), invoke->GetDexMethodIndex()))); break; } case HInvokeStaticOrDirect::MethodLoadKind::kRuntimeCall: { @@ -4629,6 +4627,16 @@ void CodeGeneratorX86::RecordBootMethodPatch(HInvokeStaticOrDirect* invoke) { __ Bind(&boot_image_method_patches_.back().label); } +Label* CodeGeneratorX86::NewMethodBssEntryPatch( + HX86ComputeBaseMethodAddress* method_address, + MethodReference target_method) { + // Add the patch entry and bind its label at the end of the instruction. + method_bss_entry_patches_.emplace_back(method_address, + *target_method.dex_file, + target_method.dex_method_index); + return &method_bss_entry_patches_.back().label; +} + void CodeGeneratorX86::RecordBootTypePatch(HLoadClass* load_class) { HX86ComputeBaseMethodAddress* address = load_class->InputAt(0)->AsX86ComputeBaseMethodAddress(); boot_image_type_patches_.emplace_back(address, @@ -4663,15 +4671,6 @@ Label* CodeGeneratorX86::NewStringBssEntryPatch(HLoadString* load_string) { return &string_patches_.back().label; } -Label* CodeGeneratorX86::NewPcRelativeDexCacheArrayPatch( - HX86ComputeBaseMethodAddress* method_address, - const DexFile& dex_file, - uint32_t element_offset) { - // Add the patch entry and bind its label at the end of the instruction. - pc_relative_dex_cache_patches_.emplace_back(method_address, dex_file, element_offset); - return &pc_relative_dex_cache_patches_.back().label; -} - // The label points to the end of the "movl" or another instruction but the literal offset // for method patch needs to point to the embedded constant which occupies the last 4 bytes. constexpr uint32_t kLabelPositionToLiteralOffsetAdjustment = 4u; @@ -4690,14 +4689,12 @@ inline void CodeGeneratorX86::EmitPcRelativeLinkerPatches( void CodeGeneratorX86::EmitLinkerPatches(ArenaVector<LinkerPatch>* linker_patches) { DCHECK(linker_patches->empty()); size_t size = - pc_relative_dex_cache_patches_.size() + boot_image_method_patches_.size() + + method_bss_entry_patches_.size() + boot_image_type_patches_.size() + type_bss_entry_patches_.size() + string_patches_.size(); linker_patches->reserve(size); - EmitPcRelativeLinkerPatches<LinkerPatch::DexCacheArrayPatch>(pc_relative_dex_cache_patches_, - linker_patches); if (GetCompilerOptions().IsBootImage()) { EmitPcRelativeLinkerPatches<LinkerPatch::RelativeMethodPatch>(boot_image_method_patches_, linker_patches); @@ -4709,6 +4706,8 @@ void CodeGeneratorX86::EmitLinkerPatches(ArenaVector<LinkerPatch>* linker_patche DCHECK(boot_image_type_patches_.empty()); EmitPcRelativeLinkerPatches<LinkerPatch::StringBssEntryPatch>(string_patches_, linker_patches); } + EmitPcRelativeLinkerPatches<LinkerPatch::MethodBssEntryPatch>(method_bss_entry_patches_, + linker_patches); EmitPcRelativeLinkerPatches<LinkerPatch::TypeBssEntryPatch>(type_bss_entry_patches_, linker_patches); DCHECK_EQ(size, linker_patches->size()); diff --git a/compiler/optimizing/code_generator_x86.h b/compiler/optimizing/code_generator_x86.h index 689f93e31a..f48753b614 100644 --- a/compiler/optimizing/code_generator_x86.h +++ b/compiler/optimizing/code_generator_x86.h @@ -415,13 +415,12 @@ class CodeGeneratorX86 : public CodeGenerator { HInvokeVirtual* invoke, Location temp, SlowPathCode* slow_path = nullptr) OVERRIDE; void RecordBootMethodPatch(HInvokeStaticOrDirect* invoke); + Label* NewMethodBssEntryPatch(HX86ComputeBaseMethodAddress* method_address, + MethodReference target_method); void RecordBootTypePatch(HLoadClass* load_class); Label* NewTypeBssEntryPatch(HLoadClass* load_class); void RecordBootStringPatch(HLoadString* load_string); Label* NewStringBssEntryPatch(HLoadString* load_string); - Label* NewPcRelativeDexCacheArrayPatch(HX86ComputeBaseMethodAddress* method_address, - const DexFile& dex_file, - uint32_t element_offset); Label* NewJitRootStringPatch(const DexFile& dex_file, dex::StringIndex dex_index, Handle<mirror::String> handle); @@ -633,10 +632,10 @@ class CodeGeneratorX86 : public CodeGenerator { X86Assembler assembler_; const X86InstructionSetFeatures& isa_features_; - // PC-relative DexCache access info. - ArenaDeque<X86PcRelativePatchInfo> pc_relative_dex_cache_patches_; // PC-relative method patch info for kBootImageLinkTimePcRelative. ArenaDeque<X86PcRelativePatchInfo> boot_image_method_patches_; + // PC-relative method patch info for kBssEntry. + ArenaDeque<X86PcRelativePatchInfo> method_bss_entry_patches_; // PC-relative type patch info for kBootImageLinkTimePcRelative. ArenaDeque<X86PcRelativePatchInfo> boot_image_type_patches_; // Type patch locations for kBssEntry. diff --git a/compiler/optimizing/code_generator_x86_64.cc b/compiler/optimizing/code_generator_x86_64.cc index 148f55139e..7331a9e98e 100644 --- a/compiler/optimizing/code_generator_x86_64.cc +++ b/compiler/optimizing/code_generator_x86_64.cc @@ -1002,12 +1002,12 @@ void CodeGeneratorX86_64::GenerateStaticOrDirectCall( case HInvokeStaticOrDirect::MethodLoadKind::kDirectAddress: Load64BitValue(temp.AsRegister<CpuRegister>(), invoke->GetMethodAddress()); break; - case HInvokeStaticOrDirect::MethodLoadKind::kDexCachePcRelative: { + case HInvokeStaticOrDirect::MethodLoadKind::kBssEntry: { __ movq(temp.AsRegister<CpuRegister>(), Address::Absolute(kDummy32BitOffset, /* no_rip */ false)); // Bind a new fixup label at the end of the "movl" insn. - uint32_t offset = invoke->GetDexCacheArrayOffset(); - __ Bind(NewPcRelativeDexCacheArrayPatch(invoke->GetDexFileForPcRelativeDexCache(), offset)); + __ Bind(NewMethodBssEntryPatch( + MethodReference(&GetGraph()->GetDexFile(), invoke->GetDexMethodIndex()))); break; } case HInvokeStaticOrDirect::MethodLoadKind::kRuntimeCall: { @@ -1071,6 +1071,12 @@ void CodeGeneratorX86_64::RecordBootMethodPatch(HInvokeStaticOrDirect* invoke) { __ Bind(&boot_image_method_patches_.back().label); } +Label* CodeGeneratorX86_64::NewMethodBssEntryPatch(MethodReference target_method) { + // Add a patch entry and return the label. + method_bss_entry_patches_.emplace_back(*target_method.dex_file, target_method.dex_method_index); + return &method_bss_entry_patches_.back().label; +} + void CodeGeneratorX86_64::RecordBootTypePatch(HLoadClass* load_class) { boot_image_type_patches_.emplace_back(load_class->GetDexFile(), load_class->GetTypeIndex().index_); @@ -1094,13 +1100,6 @@ Label* CodeGeneratorX86_64::NewStringBssEntryPatch(HLoadString* load_string) { return &string_patches_.back().label; } -Label* CodeGeneratorX86_64::NewPcRelativeDexCacheArrayPatch(const DexFile& dex_file, - uint32_t element_offset) { - // Add a patch entry and return the label. - pc_relative_dex_cache_patches_.emplace_back(dex_file, element_offset); - return &pc_relative_dex_cache_patches_.back().label; -} - // The label points to the end of the "movl" or another instruction but the literal offset // for method patch needs to point to the embedded constant which occupies the last 4 bytes. constexpr uint32_t kLabelPositionToLiteralOffsetAdjustment = 4u; @@ -1119,14 +1118,12 @@ inline void CodeGeneratorX86_64::EmitPcRelativeLinkerPatches( void CodeGeneratorX86_64::EmitLinkerPatches(ArenaVector<LinkerPatch>* linker_patches) { DCHECK(linker_patches->empty()); size_t size = - pc_relative_dex_cache_patches_.size() + boot_image_method_patches_.size() + + method_bss_entry_patches_.size() + boot_image_type_patches_.size() + type_bss_entry_patches_.size() + string_patches_.size(); linker_patches->reserve(size); - EmitPcRelativeLinkerPatches<LinkerPatch::DexCacheArrayPatch>(pc_relative_dex_cache_patches_, - linker_patches); if (GetCompilerOptions().IsBootImage()) { EmitPcRelativeLinkerPatches<LinkerPatch::RelativeMethodPatch>(boot_image_method_patches_, linker_patches); @@ -1138,6 +1135,8 @@ void CodeGeneratorX86_64::EmitLinkerPatches(ArenaVector<LinkerPatch>* linker_pat DCHECK(boot_image_type_patches_.empty()); EmitPcRelativeLinkerPatches<LinkerPatch::StringBssEntryPatch>(string_patches_, linker_patches); } + EmitPcRelativeLinkerPatches<LinkerPatch::MethodBssEntryPatch>(method_bss_entry_patches_, + linker_patches); EmitPcRelativeLinkerPatches<LinkerPatch::TypeBssEntryPatch>(type_bss_entry_patches_, linker_patches); DCHECK_EQ(size, linker_patches->size()); @@ -1226,8 +1225,8 @@ CodeGeneratorX86_64::CodeGeneratorX86_64(HGraph* graph, assembler_(graph->GetArena()), isa_features_(isa_features), constant_area_start_(0), - pc_relative_dex_cache_patches_(graph->GetArena()->Adapter(kArenaAllocCodeGenerator)), boot_image_method_patches_(graph->GetArena()->Adapter(kArenaAllocCodeGenerator)), + method_bss_entry_patches_(graph->GetArena()->Adapter(kArenaAllocCodeGenerator)), boot_image_type_patches_(graph->GetArena()->Adapter(kArenaAllocCodeGenerator)), type_bss_entry_patches_(graph->GetArena()->Adapter(kArenaAllocCodeGenerator)), string_patches_(graph->GetArena()->Adapter(kArenaAllocCodeGenerator)), diff --git a/compiler/optimizing/code_generator_x86_64.h b/compiler/optimizing/code_generator_x86_64.h index 31debde0ce..33c64290d4 100644 --- a/compiler/optimizing/code_generator_x86_64.h +++ b/compiler/optimizing/code_generator_x86_64.h @@ -410,11 +410,11 @@ class CodeGeneratorX86_64 : public CodeGenerator { HInvokeVirtual* invoke, Location temp, SlowPathCode* slow_path = nullptr) OVERRIDE; void RecordBootMethodPatch(HInvokeStaticOrDirect* invoke); + Label* NewMethodBssEntryPatch(MethodReference target_method); void RecordBootTypePatch(HLoadClass* load_class); Label* NewTypeBssEntryPatch(HLoadClass* load_class); void RecordBootStringPatch(HLoadString* load_string); Label* NewStringBssEntryPatch(HLoadString* load_string); - Label* NewPcRelativeDexCacheArrayPatch(const DexFile& dex_file, uint32_t element_offset); Label* NewJitRootStringPatch(const DexFile& dex_file, dex::StringIndex dex_index, Handle<mirror::String> handle); @@ -603,10 +603,10 @@ class CodeGeneratorX86_64 : public CodeGenerator { // Used for fixups to the constant area. int constant_area_start_; - // PC-relative DexCache access info. - ArenaDeque<PatchInfo<Label>> pc_relative_dex_cache_patches_; // PC-relative method patch info for kBootImageLinkTimePcRelative. ArenaDeque<PatchInfo<Label>> boot_image_method_patches_; + // PC-relative method patch info for kBssEntry. + ArenaDeque<PatchInfo<Label>> method_bss_entry_patches_; // PC-relative type patch info for kBootImageLinkTimePcRelative. ArenaDeque<PatchInfo<Label>> boot_image_type_patches_; // Type patch locations for kBssEntry. diff --git a/compiler/optimizing/dex_cache_array_fixups_arm.cc b/compiler/optimizing/dex_cache_array_fixups_arm.cc deleted file mode 100644 index 0c832a5c35..0000000000 --- a/compiler/optimizing/dex_cache_array_fixups_arm.cc +++ /dev/null @@ -1,116 +0,0 @@ -/* - * Copyright (C) 2015 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#include "dex_cache_array_fixups_arm.h" - -#include "base/arena_containers.h" -#ifdef ART_USE_OLD_ARM_BACKEND -#include "code_generator_arm.h" -#include "intrinsics_arm.h" -#else -#include "code_generator_arm_vixl.h" -#include "intrinsics_arm_vixl.h" -#endif -#include "utils/dex_cache_arrays_layout-inl.h" - -namespace art { -namespace arm { -#ifdef ART_USE_OLD_ARM_BACKEND -typedef CodeGeneratorARM CodeGeneratorARMType; -typedef IntrinsicLocationsBuilderARM IntrinsicLocationsBuilderARMType; -#else -typedef CodeGeneratorARMVIXL CodeGeneratorARMType; -typedef IntrinsicLocationsBuilderARMVIXL IntrinsicLocationsBuilderARMType; -#endif - -/** - * Finds instructions that need the dex cache arrays base as an input. - */ -class DexCacheArrayFixupsVisitor : public HGraphVisitor { - public: - DexCacheArrayFixupsVisitor(HGraph* graph, CodeGenerator* codegen) - : HGraphVisitor(graph), - codegen_(down_cast<CodeGeneratorARMType*>(codegen)), - dex_cache_array_bases_(std::less<const DexFile*>(), - // Attribute memory use to code generator. - graph->GetArena()->Adapter(kArenaAllocCodeGenerator)) {} - - void MoveBasesIfNeeded() { - for (const auto& entry : dex_cache_array_bases_) { - // Bring the base closer to the first use (previously, it was in the - // entry block) and relieve some pressure on the register allocator - // while avoiding recalculation of the base in a loop. - HArmDexCacheArraysBase* base = entry.second; - base->MoveBeforeFirstUserAndOutOfLoops(); - } - } - - private: - void VisitInvokeStaticOrDirect(HInvokeStaticOrDirect* invoke) OVERRIDE { - // If this is an invoke with PC-relative access to the dex cache methods array, - // we need to add the dex cache arrays base as the special input. - if (invoke->HasPcRelativeDexCache() && - !IsCallFreeIntrinsic<IntrinsicLocationsBuilderARMType>(invoke, codegen_)) { - HArmDexCacheArraysBase* base = - GetOrCreateDexCacheArrayBase(invoke, invoke->GetDexFileForPcRelativeDexCache()); - // Update the element offset in base. - DexCacheArraysLayout layout(kArmPointerSize, &invoke->GetDexFileForPcRelativeDexCache()); - base->UpdateElementOffset(layout.MethodOffset(invoke->GetDexMethodIndex())); - // Add the special argument base to the method. - DCHECK(!invoke->HasCurrentMethodInput()); - invoke->AddSpecialInput(base); - } - } - - HArmDexCacheArraysBase* GetOrCreateDexCacheArrayBase(HInstruction* cursor, - const DexFile& dex_file) { - if (GetGraph()->HasIrreducibleLoops()) { - HArmDexCacheArraysBase* base = new (GetGraph()->GetArena()) HArmDexCacheArraysBase(dex_file); - cursor->GetBlock()->InsertInstructionBefore(base, cursor); - return base; - } else { - // Ensure we only initialize the pointer once for each dex file. - auto lb = dex_cache_array_bases_.lower_bound(&dex_file); - if (lb != dex_cache_array_bases_.end() && - !dex_cache_array_bases_.key_comp()(&dex_file, lb->first)) { - return lb->second; - } - - // Insert the base at the start of the entry block, move it to a better - // position later in MoveBaseIfNeeded(). - HArmDexCacheArraysBase* base = new (GetGraph()->GetArena()) HArmDexCacheArraysBase(dex_file); - HBasicBlock* entry_block = GetGraph()->GetEntryBlock(); - entry_block->InsertInstructionBefore(base, entry_block->GetFirstInstruction()); - dex_cache_array_bases_.PutBefore(lb, &dex_file, base); - return base; - } - } - - CodeGeneratorARMType* codegen_; - - using DexCacheArraysBaseMap = - ArenaSafeMap<const DexFile*, HArmDexCacheArraysBase*, std::less<const DexFile*>>; - DexCacheArraysBaseMap dex_cache_array_bases_; -}; - -void DexCacheArrayFixups::Run() { - DexCacheArrayFixupsVisitor visitor(graph_, codegen_); - visitor.VisitInsertionOrder(); - visitor.MoveBasesIfNeeded(); -} - -} // namespace arm -} // namespace art diff --git a/compiler/optimizing/dex_cache_array_fixups_arm.h b/compiler/optimizing/dex_cache_array_fixups_arm.h deleted file mode 100644 index 9d67a319b9..0000000000 --- a/compiler/optimizing/dex_cache_array_fixups_arm.h +++ /dev/null @@ -1,46 +0,0 @@ -/* - * Copyright (C) 2015 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#ifndef ART_COMPILER_OPTIMIZING_DEX_CACHE_ARRAY_FIXUPS_ARM_H_ -#define ART_COMPILER_OPTIMIZING_DEX_CACHE_ARRAY_FIXUPS_ARM_H_ - -#include "nodes.h" -#include "optimization.h" - -namespace art { - -class CodeGenerator; - -namespace arm { - -class DexCacheArrayFixups : public HOptimization { - public: - DexCacheArrayFixups(HGraph* graph, CodeGenerator* codegen, OptimizingCompilerStats* stats) - : HOptimization(graph, kDexCacheArrayFixupsArmPassName, stats), - codegen_(codegen) {} - - static constexpr const char* kDexCacheArrayFixupsArmPassName = "dex_cache_array_fixups_arm"; - - void Run() OVERRIDE; - - private: - CodeGenerator* codegen_; -}; - -} // namespace arm -} // namespace art - -#endif // ART_COMPILER_OPTIMIZING_DEX_CACHE_ARRAY_FIXUPS_ARM_H_ diff --git a/compiler/optimizing/dex_cache_array_fixups_mips.cc b/compiler/optimizing/dex_cache_array_fixups_mips.cc deleted file mode 100644 index 7734f9197d..0000000000 --- a/compiler/optimizing/dex_cache_array_fixups_mips.cc +++ /dev/null @@ -1,111 +0,0 @@ -/* - * Copyright (C) 2016 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#include "code_generator_mips.h" -#include "dex_cache_array_fixups_mips.h" - -#include "base/arena_containers.h" -#include "intrinsics_mips.h" -#include "utils/dex_cache_arrays_layout-inl.h" - -namespace art { -namespace mips { - -/** - * Finds instructions that need the dex cache arrays base as an input. - */ -class DexCacheArrayFixupsVisitor : public HGraphVisitor { - public: - explicit DexCacheArrayFixupsVisitor(HGraph* graph, CodeGenerator* codegen) - : HGraphVisitor(graph), - codegen_(down_cast<CodeGeneratorMIPS*>(codegen)), - dex_cache_array_bases_(std::less<const DexFile*>(), - // Attribute memory use to code generator. - graph->GetArena()->Adapter(kArenaAllocCodeGenerator)) {} - - void MoveBasesIfNeeded() { - for (const auto& entry : dex_cache_array_bases_) { - // Bring the base closer to the first use (previously, it was in the - // entry block) and relieve some pressure on the register allocator - // while avoiding recalculation of the base in a loop. - HMipsDexCacheArraysBase* base = entry.second; - base->MoveBeforeFirstUserAndOutOfLoops(); - } - // Computing the dex cache base for PC-relative accesses will clobber RA with - // the NAL instruction on R2. Take a note of this before generating the method - // entry. - if (!dex_cache_array_bases_.empty()) { - codegen_->ClobberRA(); - } - } - - private: - void VisitInvokeStaticOrDirect(HInvokeStaticOrDirect* invoke) OVERRIDE { - // If this is an invoke with PC-relative access to the dex cache methods array, - // we need to add the dex cache arrays base as the special input. - if (invoke->HasPcRelativeDexCache() && - !IsCallFreeIntrinsic<IntrinsicLocationsBuilderMIPS>(invoke, codegen_)) { - // Initialize base for target method dex file if needed. - HMipsDexCacheArraysBase* base = - GetOrCreateDexCacheArrayBase(invoke->GetDexFileForPcRelativeDexCache()); - // Update the element offset in base. - DexCacheArraysLayout layout(kMipsPointerSize, &invoke->GetDexFileForPcRelativeDexCache()); - base->UpdateElementOffset(layout.MethodOffset(invoke->GetDexMethodIndex())); - // Add the special argument base to the method. - DCHECK(!invoke->HasCurrentMethodInput()); - invoke->AddSpecialInput(base); - } - } - - HMipsDexCacheArraysBase* GetOrCreateDexCacheArrayBase(const DexFile& dex_file) { - return dex_cache_array_bases_.GetOrCreate( - &dex_file, - [this, &dex_file]() { - HMipsDexCacheArraysBase* base = - new (GetGraph()->GetArena()) HMipsDexCacheArraysBase(dex_file); - HBasicBlock* entry_block = GetGraph()->GetEntryBlock(); - // Insert the base at the start of the entry block, move it to a better - // position later in MoveBaseIfNeeded(). - entry_block->InsertInstructionBefore(base, entry_block->GetFirstInstruction()); - return base; - }); - } - - CodeGeneratorMIPS* codegen_; - - using DexCacheArraysBaseMap = - ArenaSafeMap<const DexFile*, HMipsDexCacheArraysBase*, std::less<const DexFile*>>; - DexCacheArraysBaseMap dex_cache_array_bases_; -}; - -void DexCacheArrayFixups::Run() { - CodeGeneratorMIPS* mips_codegen = down_cast<CodeGeneratorMIPS*>(codegen_); - if (mips_codegen->GetInstructionSetFeatures().IsR6()) { - // Do nothing for R6 because it has PC-relative addressing. - return; - } - if (graph_->HasIrreducibleLoops()) { - // Do not run this optimization, as irreducible loops do not work with an instruction - // that can be live-in at the irreducible loop header. - return; - } - DexCacheArrayFixupsVisitor visitor(graph_, codegen_); - visitor.VisitInsertionOrder(); - visitor.MoveBasesIfNeeded(); -} - -} // namespace mips -} // namespace art diff --git a/compiler/optimizing/dex_cache_array_fixups_mips.h b/compiler/optimizing/dex_cache_array_fixups_mips.h deleted file mode 100644 index 861a199d6c..0000000000 --- a/compiler/optimizing/dex_cache_array_fixups_mips.h +++ /dev/null @@ -1,46 +0,0 @@ -/* - * Copyright (C) 2016 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#ifndef ART_COMPILER_OPTIMIZING_DEX_CACHE_ARRAY_FIXUPS_MIPS_H_ -#define ART_COMPILER_OPTIMIZING_DEX_CACHE_ARRAY_FIXUPS_MIPS_H_ - -#include "nodes.h" -#include "optimization.h" - -namespace art { - -class CodeGenerator; - -namespace mips { - -class DexCacheArrayFixups : public HOptimization { - public: - DexCacheArrayFixups(HGraph* graph, CodeGenerator* codegen, OptimizingCompilerStats* stats) - : HOptimization(graph, kDexCacheArrayFixupsMipsPassName, stats), - codegen_(codegen) {} - - static constexpr const char* kDexCacheArrayFixupsMipsPassName = "dex_cache_array_fixups_mips"; - - void Run() OVERRIDE; - - private: - CodeGenerator* codegen_; -}; - -} // namespace mips -} // namespace art - -#endif // ART_COMPILER_OPTIMIZING_DEX_CACHE_ARRAY_FIXUPS_MIPS_H_ diff --git a/compiler/optimizing/nodes.cc b/compiler/optimizing/nodes.cc index e53209f941..d0047c54f2 100644 --- a/compiler/optimizing/nodes.cc +++ b/compiler/optimizing/nodes.cc @@ -2643,8 +2643,8 @@ std::ostream& operator<<(std::ostream& os, HInvokeStaticOrDirect::MethodLoadKind return os << "BootImageLinkTimePcRelative"; case HInvokeStaticOrDirect::MethodLoadKind::kDirectAddress: return os << "DirectAddress"; - case HInvokeStaticOrDirect::MethodLoadKind::kDexCachePcRelative: - return os << "DexCachePcRelative"; + case HInvokeStaticOrDirect::MethodLoadKind::kBssEntry: + return os << "BssEntry"; case HInvokeStaticOrDirect::MethodLoadKind::kRuntimeCall: return os << "RuntimeCall"; default: diff --git a/compiler/optimizing/nodes.h b/compiler/optimizing/nodes.h index 74bb2ab3c4..2867797e20 100644 --- a/compiler/optimizing/nodes.h +++ b/compiler/optimizing/nodes.h @@ -1410,12 +1410,7 @@ class HLoopInformationOutwardIterator : public ValueObject { M(IntermediateAddressIndex, Instruction) #endif -#ifndef ART_ENABLE_CODEGEN_arm #define FOR_EACH_CONCRETE_INSTRUCTION_ARM(M) -#else -#define FOR_EACH_CONCRETE_INSTRUCTION_ARM(M) \ - M(ArmDexCacheArraysBase, Instruction) -#endif #define FOR_EACH_CONCRETE_INSTRUCTION_ARM64(M) @@ -1424,7 +1419,6 @@ class HLoopInformationOutwardIterator : public ValueObject { #else #define FOR_EACH_CONCRETE_INSTRUCTION_MIPS(M) \ M(MipsComputeBaseMethodAddress, Instruction) \ - M(MipsDexCacheArraysBase, Instruction) \ M(MipsPackedSwitch, Instruction) #endif @@ -4166,11 +4160,9 @@ class HInvokeStaticOrDirect FINAL : public HInvoke { // Used for app->boot calls with non-relocatable image and for JIT-compiled calls. kDirectAddress, - // Load from resolved methods array in the dex cache using a PC-relative load. - // Used when we need to use the dex cache, for example for invoke-static that - // may cause class initialization (the entry may point to a resolution method), - // and we know that we can access the dex cache arrays using a PC-relative load. - kDexCachePcRelative, + // Load from an entry in the .bss section using a PC-relative load. + // Used for classes outside boot image when .bss is accessible with a PC-relative load. + kBssEntry, // Make a runtime call to resolve and call the method. This is the last-resort-kind // used when other kinds are unimplemented on a particular architecture. @@ -4195,7 +4187,6 @@ class HInvokeStaticOrDirect FINAL : public HInvoke { // - thread entrypoint offset for kStringInit method if this is a string init invoke. // Note that there are multiple string init methods, each having its own offset. // - the method address for kDirectAddress - // - the dex cache arrays offset for kDexCachePcRel. uint64_t method_load_data; }; @@ -4296,12 +4287,9 @@ class HInvokeStaticOrDirect FINAL : public HInvoke { bool NeedsDexCacheOfDeclaringClass() const OVERRIDE; bool IsStringInit() const { return GetMethodLoadKind() == MethodLoadKind::kStringInit; } bool HasMethodAddress() const { return GetMethodLoadKind() == MethodLoadKind::kDirectAddress; } - bool HasPcRelativeDexCache() const { - return GetMethodLoadKind() == MethodLoadKind::kDexCachePcRelative; - } bool HasPcRelativeMethodLoadKind() const { return GetMethodLoadKind() == MethodLoadKind::kBootImageLinkTimePcRelative || - GetMethodLoadKind() == MethodLoadKind::kDexCachePcRelative; + GetMethodLoadKind() == MethodLoadKind::kBssEntry; } bool HasCurrentMethodInput() const { // This function can be called only after the invoke has been fully initialized by the builder. @@ -4325,11 +4313,6 @@ class HInvokeStaticOrDirect FINAL : public HInvoke { return dispatch_info_.method_load_data; } - uint32_t GetDexCacheArrayOffset() const { - DCHECK(HasPcRelativeDexCache()); - return dispatch_info_.method_load_data; - } - const DexFile& GetDexFileForPcRelativeDexCache() const; ClinitCheckRequirement GetClinitCheckRequirement() const { @@ -6879,9 +6862,6 @@ class HParallelMove FINAL : public HTemplateInstruction<0> { #if defined(ART_ENABLE_CODEGEN_arm) || defined(ART_ENABLE_CODEGEN_arm64) #include "nodes_shared.h" #endif -#ifdef ART_ENABLE_CODEGEN_arm -#include "nodes_arm.h" -#endif #ifdef ART_ENABLE_CODEGEN_mips #include "nodes_mips.h" #endif diff --git a/compiler/optimizing/nodes_arm.h b/compiler/optimizing/nodes_arm.h deleted file mode 100644 index d9f9740e73..0000000000 --- a/compiler/optimizing/nodes_arm.h +++ /dev/null @@ -1,61 +0,0 @@ -/* - * Copyright (C) 2015 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#ifndef ART_COMPILER_OPTIMIZING_NODES_ARM_H_ -#define ART_COMPILER_OPTIMIZING_NODES_ARM_H_ - -namespace art { - -class HArmDexCacheArraysBase FINAL : public HExpression<0> { - public: - explicit HArmDexCacheArraysBase(const DexFile& dex_file) - : HExpression(Primitive::kPrimInt, SideEffects::None(), kNoDexPc), - dex_file_(&dex_file), - element_offset_(static_cast<size_t>(-1)) { } - - bool CanBeMoved() const OVERRIDE { return true; } - - void UpdateElementOffset(size_t element_offset) { - // Use the lowest offset from the requested elements so that all offsets from - // this base are non-negative because our assemblers emit negative-offset loads - // as a sequence of two or more instructions. (However, positive offsets beyond - // 4KiB also require two or more instructions, so this simple heuristic could - // be improved for cases where there is a dense cluster of elements far from - // the lowest offset. This is expected to be rare enough though, so we choose - // not to spend compile time on elaborate calculations.) - element_offset_ = std::min(element_offset_, element_offset); - } - - const DexFile& GetDexFile() const { - return *dex_file_; - } - - size_t GetElementOffset() const { - return element_offset_; - } - - DECLARE_INSTRUCTION(ArmDexCacheArraysBase); - - private: - const DexFile* dex_file_; - size_t element_offset_; - - DISALLOW_COPY_AND_ASSIGN(HArmDexCacheArraysBase); -}; - -} // namespace art - -#endif // ART_COMPILER_OPTIMIZING_NODES_ARM_H_ diff --git a/compiler/optimizing/nodes_mips.h b/compiler/optimizing/nodes_mips.h index 36431c1fb9..8e439d9621 100644 --- a/compiler/optimizing/nodes_mips.h +++ b/compiler/optimizing/nodes_mips.h @@ -34,38 +34,6 @@ class HMipsComputeBaseMethodAddress : public HExpression<0> { DISALLOW_COPY_AND_ASSIGN(HMipsComputeBaseMethodAddress); }; -class HMipsDexCacheArraysBase : public HExpression<0> { - public: - explicit HMipsDexCacheArraysBase(const DexFile& dex_file) - : HExpression(Primitive::kPrimInt, SideEffects::None(), kNoDexPc), - dex_file_(&dex_file), - element_offset_(static_cast<size_t>(-1)) { } - - bool CanBeMoved() const OVERRIDE { return true; } - - void UpdateElementOffset(size_t element_offset) { - // We'll maximize the range of a single load instruction for dex cache array accesses - // by aligning offset -32768 with the offset of the first used element. - element_offset_ = std::min(element_offset_, element_offset); - } - - const DexFile& GetDexFile() const { - return *dex_file_; - } - - size_t GetElementOffset() const { - return element_offset_; - } - - DECLARE_INSTRUCTION(MipsDexCacheArraysBase); - - private: - const DexFile* dex_file_; - size_t element_offset_; - - DISALLOW_COPY_AND_ASSIGN(HMipsDexCacheArraysBase); -}; - // Mips version of HPackedSwitch that holds a pointer to the base method address. class HMipsPackedSwitch FINAL : public HTemplateInstruction<2> { public: diff --git a/compiler/optimizing/optimizing_compiler.cc b/compiler/optimizing/optimizing_compiler.cc index e5ab00bce3..890ba674b5 100644 --- a/compiler/optimizing/optimizing_compiler.cc +++ b/compiler/optimizing/optimizing_compiler.cc @@ -24,16 +24,11 @@ #include "android-base/strings.h" -#ifdef ART_ENABLE_CODEGEN_arm -#include "dex_cache_array_fixups_arm.h" -#endif - #ifdef ART_ENABLE_CODEGEN_arm64 #include "instruction_simplifier_arm64.h" #endif #ifdef ART_ENABLE_CODEGEN_mips -#include "dex_cache_array_fixups_mips.h" #include "pc_relative_fixups_mips.h" #endif @@ -522,8 +517,6 @@ static HOptimization* BuildOptimization( } else if (opt_name == CodeSinking::kCodeSinkingPassName) { return new (arena) CodeSinking(graph, stats); #ifdef ART_ENABLE_CODEGEN_arm - } else if (opt_name == arm::DexCacheArrayFixups::kDexCacheArrayFixupsArmPassName) { - return new (arena) arm::DexCacheArrayFixups(graph, codegen, stats); } else if (opt_name == arm::InstructionSimplifierArm::kInstructionSimplifierArmPassName) { return new (arena) arm::InstructionSimplifierArm(graph, stats); #endif @@ -532,8 +525,6 @@ static HOptimization* BuildOptimization( return new (arena) arm64::InstructionSimplifierArm64(graph, stats); #endif #ifdef ART_ENABLE_CODEGEN_mips - } else if (opt_name == mips::DexCacheArrayFixups::kDexCacheArrayFixupsMipsPassName) { - return new (arena) mips::DexCacheArrayFixups(graph, codegen, stats); } else if (opt_name == mips::PcRelativeFixups::kPcRelativeFixupsMipsPassName) { return new (arena) mips::PcRelativeFixups(graph, codegen, stats); #endif @@ -641,8 +632,6 @@ void OptimizingCompiler::RunArchOptimizations(InstructionSet instruction_set, #if defined(ART_ENABLE_CODEGEN_arm) case kThumb2: case kArm: { - arm::DexCacheArrayFixups* fixups = - new (arena) arm::DexCacheArrayFixups(graph, codegen, stats); arm::InstructionSimplifierArm* simplifier = new (arena) arm::InstructionSimplifierArm(graph, stats); SideEffectsAnalysis* side_effects = new (arena) SideEffectsAnalysis(graph); @@ -653,7 +642,6 @@ void OptimizingCompiler::RunArchOptimizations(InstructionSet instruction_set, simplifier, side_effects, gvn, - fixups, scheduling, }; RunOptimizations(arm_optimizations, arraysize(arm_optimizations), pass_observer); @@ -682,11 +670,8 @@ void OptimizingCompiler::RunArchOptimizations(InstructionSet instruction_set, case kMips: { mips::PcRelativeFixups* pc_relative_fixups = new (arena) mips::PcRelativeFixups(graph, codegen, stats); - mips::DexCacheArrayFixups* dex_cache_array_fixups = - new (arena) mips::DexCacheArrayFixups(graph, codegen, stats); HOptimization* mips_optimizations[] = { pc_relative_fixups, - dex_cache_array_fixups }; RunOptimizations(mips_optimizations, arraysize(mips_optimizations), pass_observer); break; diff --git a/compiler/optimizing/pc_relative_fixups_mips.cc b/compiler/optimizing/pc_relative_fixups_mips.cc index bce54bf49a..21b645279e 100644 --- a/compiler/optimizing/pc_relative_fixups_mips.cc +++ b/compiler/optimizing/pc_relative_fixups_mips.cc @@ -59,10 +59,9 @@ class PCRelativeHandlerVisitor : public HGraphVisitor { } void VisitInvokeStaticOrDirect(HInvokeStaticOrDirect* invoke) OVERRIDE { - // If this is an invoke with PC-relative pointer to a method, + // If this is an invoke with PC-relative load kind, // we need to add the base as the special input. - if (invoke->GetMethodLoadKind() == - HInvokeStaticOrDirect::MethodLoadKind::kBootImageLinkTimePcRelative && + if (invoke->HasPcRelativeMethodLoadKind() && !IsCallFreeIntrinsic<IntrinsicLocationsBuilderMIPS>(invoke, codegen_)) { InitializePCRelativeBasePointer(); // Add the special argument base to the method. diff --git a/compiler/optimizing/scheduler_arm.cc b/compiler/optimizing/scheduler_arm.cc index 832a7e1571..e78cd78aa2 100644 --- a/compiler/optimizing/scheduler_arm.cc +++ b/compiler/optimizing/scheduler_arm.cc @@ -818,10 +818,5 @@ void SchedulingLatencyVisitorARM::VisitTypeConversion(HTypeConversion* instr) { } } -void SchedulingLatencyVisitorARM::VisitArmDexCacheArraysBase(art::HArmDexCacheArraysBase*) { - last_visited_internal_latency_ = kArmIntegerOpLatency; - last_visited_latency_ = kArmIntegerOpLatency; -} - } // namespace arm } // namespace art diff --git a/compiler/optimizing/sharpening.cc b/compiler/optimizing/sharpening.cc index 106b709eda..8bd568befd 100644 --- a/compiler/optimizing/sharpening.cc +++ b/compiler/optimizing/sharpening.cc @@ -128,15 +128,8 @@ void HSharpening::SharpenInvokeStaticOrDirect(HInvokeStaticOrDirect* invoke, method_load_kind = HInvokeStaticOrDirect::MethodLoadKind::kBootImageLinkTimePcRelative; code_ptr_location = HInvokeStaticOrDirect::CodePtrLocation::kCallArtMethod; } else { - // Use PC-relative access to the dex cache arrays. - method_load_kind = HInvokeStaticOrDirect::MethodLoadKind::kDexCachePcRelative; - // Note: we use the invoke's graph instead of the codegen graph, which are - // different when inlining (the codegen graph is the most outer graph). The - // invoke's dex method index is relative to the dex file where the invoke's graph - // was built from. - DexCacheArraysLayout layout(GetInstructionSetPointerSize(codegen->GetInstructionSet()), - &invoke->GetBlock()->GetGraph()->GetDexFile()); - method_load_data = layout.MethodOffset(invoke->GetDexMethodIndex()); + // Use PC-relative access to the .bss methods arrays. + method_load_kind = HInvokeStaticOrDirect::MethodLoadKind::kBssEntry; code_ptr_location = HInvokeStaticOrDirect::CodePtrLocation::kCallArtMethod; } diff --git a/dex2oat/dex2oat.cc b/dex2oat/dex2oat.cc index 331a6f2f64..5efcb9d97b 100644 --- a/dex2oat/dex2oat.cc +++ b/dex2oat/dex2oat.cc @@ -1933,6 +1933,7 @@ class Dex2Oat FINAL { elf_writer->PrepareDynamicSection(rodata_size, text_size, oat_writer->GetBssSize(), + oat_writer->GetBssMethodsOffset(), oat_writer->GetBssRootsOffset()); if (IsImage()) { diff --git a/oatdump/oatdump.cc b/oatdump/oatdump.cc index a79b408a40..0c64b9f9db 100644 --- a/oatdump/oatdump.cc +++ b/oatdump/oatdump.cc @@ -171,6 +171,7 @@ class OatSymbolizer FINAL { rodata_size, text_size, oat_file_->BssSize(), + oat_file_->BssMethodsOffset(), oat_file_->BssRootsOffset()); builder_->WriteDynamicSection(); diff --git a/runtime/class_linker.cc b/runtime/class_linker.cc index 0921bd6783..0fa25d15d2 100644 --- a/runtime/class_linker.cc +++ b/runtime/class_linker.cc @@ -3417,8 +3417,11 @@ void ClassLinker::RegisterDexFileLocked(const DexFile& dex_file, // Example dex_cache location is SettingsProvider.apk and // dex file location is /system/priv-app/SettingsProvider/SettingsProvider.apk CHECK_EQ(dex_cache_location, dex_file_suffix); - // Clean up pass to remove null dex caches. + const OatFile* oat_file = + (dex_file.GetOatDexFile() != nullptr) ? dex_file.GetOatDexFile()->GetOatFile() : nullptr; + // Clean up pass to remove null dex caches. Also check if we need to initialize OatFile .bss. // Null dex caches can occur due to class unloading and we are lazily removing null entries. + bool initialize_oat_file_bss = (oat_file != nullptr); JavaVMExt* const vm = self->GetJniEnv()->vm; for (auto it = dex_caches_.begin(); it != dex_caches_.end(); ) { DexCacheData data = *it; @@ -3426,9 +3429,21 @@ void ClassLinker::RegisterDexFileLocked(const DexFile& dex_file, vm->DeleteWeakGlobalRef(self, data.weak_root); it = dex_caches_.erase(it); } else { + if (initialize_oat_file_bss && + it->dex_file->GetOatDexFile() != nullptr && + it->dex_file->GetOatDexFile()->GetOatFile() == oat_file) { + initialize_oat_file_bss = false; // Already initialized. + } ++it; } } + if (initialize_oat_file_bss) { + // TODO: Pre-initialize from boot/app image? + ArtMethod* resolution_method = Runtime::Current()->GetResolutionMethod(); + for (ArtMethod*& entry : oat_file->GetBssMethods()) { + entry = resolution_method; + } + } jweak dex_cache_jweak = vm->AddWeakGlobalRef(self, dex_cache); dex_cache->SetDexFile(&dex_file); DexCacheData data; diff --git a/runtime/entrypoints/quick/quick_trampoline_entrypoints.cc b/runtime/entrypoints/quick/quick_trampoline_entrypoints.cc index 90231e289e..e90383320b 100644 --- a/runtime/entrypoints/quick/quick_trampoline_entrypoints.cc +++ b/runtime/entrypoints/quick/quick_trampoline_entrypoints.cc @@ -28,6 +28,7 @@ #include "imtable-inl.h" #include "interpreter/interpreter.h" #include "linear_alloc.h" +#include "method_bss_mapping.h" #include "method_handles.h" #include "method_reference.h" #include "mirror/class-inl.h" @@ -36,6 +37,7 @@ #include "mirror/method_handle_impl.h" #include "mirror/object-inl.h" #include "mirror/object_array-inl.h" +#include "oat_file.h" #include "oat_quick_method_header.h" #include "quick_exception_handler.h" #include "runtime.h" @@ -1105,6 +1107,32 @@ extern "C" const void* artQuickResolutionTrampoline( DCHECK_EQ(caller->GetDexFile(), called_method.dex_file); called = linker->ResolveMethod<ClassLinker::kForceICCECheck>( self, called_method.dex_method_index, caller, invoke_type); + + // Update .bss entry in oat file if any. + if (called != nullptr && called_method.dex_file->GetOatDexFile() != nullptr) { + const MethodBssMapping* mapping = + called_method.dex_file->GetOatDexFile()->GetMethodBssMapping(); + if (mapping != nullptr) { + auto pp = std::partition_point( + mapping->begin(), + mapping->end(), + [called_method](const MethodBssMappingEntry& entry) { + return entry.method_index < called_method.dex_method_index; + }); + if (pp != mapping->end() && pp->CoversIndex(called_method.dex_method_index)) { + size_t bss_offset = pp->GetBssOffset(called_method.dex_method_index, + static_cast<size_t>(kRuntimePointerSize)); + DCHECK_ALIGNED(bss_offset, static_cast<size_t>(kRuntimePointerSize)); + const OatFile* oat_file = called_method.dex_file->GetOatDexFile()->GetOatFile(); + ArtMethod** method_entry = reinterpret_cast<ArtMethod**>(const_cast<uint8_t*>( + oat_file->BssBegin() + bss_offset)); + DCHECK_GE(method_entry, oat_file->GetBssMethods().data()); + DCHECK_LT(method_entry, + oat_file->GetBssMethods().data() + oat_file->GetBssMethods().size()); + *method_entry = called; + } + } + } } const void* code = nullptr; if (LIKELY(!self->IsExceptionPending())) { diff --git a/runtime/method_bss_mapping.h b/runtime/method_bss_mapping.h new file mode 100644 index 0000000000..1476f93e21 --- /dev/null +++ b/runtime/method_bss_mapping.h @@ -0,0 +1,57 @@ +/* + * 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_METHOD_BSS_MAPPING_H_ +#define ART_RUNTIME_METHOD_BSS_MAPPING_H_ + +#include "base/bit_utils.h" +#include "base/length_prefixed_array.h" + +namespace art { + +// MethodBssMappingEntry describes a mapping of up to 17 method indexes to their offsets +// in the .bss. The highest index and its associated .bss offset are stored in plain form +// as `method_index` and `bss_offset`, respectively, while the additional indexes can be +// stored in compressed form if their associated .bss entries are consecutive and in the +// method index order. Each of the 16 bits of the `index_mask` corresponds to one of the +// previous 16 method indexes and indicates whether there is a .bss entry for that index. +// +struct MethodBssMappingEntry { + bool CoversIndex(uint32_t method_idx) const { + uint32_t diff = method_index - method_idx; + return (diff == 0) || (diff <= 16 && ((index_mask >> (16u - diff)) & 1u) != 0); + } + + uint32_t GetBssOffset(uint32_t method_idx, size_t entry_size) const { + DCHECK(CoversIndex(method_idx)); + uint32_t diff = method_index - method_idx; + if (diff == 0) { + return bss_offset; + } else { + return bss_offset - POPCOUNT(index_mask >> (16u - diff)) * entry_size; + } + } + + uint16_t method_index; + uint16_t index_mask; + uint32_t bss_offset; +}; + +using MethodBssMapping = LengthPrefixedArray<MethodBssMappingEntry>; + +} // namespace art + +#endif // ART_RUNTIME_METHOD_BSS_MAPPING_H_ diff --git a/runtime/method_reference.h b/runtime/method_reference.h index 0b0afe64a6..3948ed5bb9 100644 --- a/runtime/method_reference.h +++ b/runtime/method_reference.h @@ -44,6 +44,56 @@ struct MethodReferenceComparator { } }; +// Compare the actual referenced method signatures. Used for method reference deduplication. +struct MethodReferenceValueComparator { + bool operator()(MethodReference mr1, MethodReference mr2) const { + if (mr1.dex_file == mr2.dex_file) { + DCHECK_EQ(mr1.dex_method_index < mr2.dex_method_index, SlowCompare(mr1, mr2)); + return mr1.dex_method_index < mr2.dex_method_index; + } else { + return SlowCompare(mr1, mr2); + } + } + + bool SlowCompare(MethodReference mr1, MethodReference mr2) const { + // The order is the same as for method ids in a single dex file. + // Compare the class descriptors first. + const DexFile::MethodId& mid1 = mr1.dex_file->GetMethodId(mr1.dex_method_index); + const DexFile::MethodId& mid2 = mr2.dex_file->GetMethodId(mr2.dex_method_index); + int descriptor_diff = strcmp(mr1.dex_file->StringByTypeIdx(mid1.class_idx_), + mr2.dex_file->StringByTypeIdx(mid2.class_idx_)); + if (descriptor_diff != 0) { + return descriptor_diff < 0; + } + // Compare names second. + int name_diff = strcmp(mr1.dex_file->GetMethodName(mid1), mr2.dex_file->GetMethodName(mid2)); + if (name_diff != 0) { + return name_diff < 0; + } + // And then compare proto ids, starting with return type comparison. + const DexFile::ProtoId& prid1 = mr1.dex_file->GetProtoId(mid1.proto_idx_); + const DexFile::ProtoId& prid2 = mr2.dex_file->GetProtoId(mid2.proto_idx_); + int return_type_diff = strcmp(mr1.dex_file->StringByTypeIdx(prid1.return_type_idx_), + mr2.dex_file->StringByTypeIdx(prid2.return_type_idx_)); + if (return_type_diff != 0) { + return return_type_diff < 0; + } + // And finishing with lexicographical parameter comparison. + const DexFile::TypeList* params1 = mr1.dex_file->GetProtoParameters(prid1); + size_t param1_size = (params1 != nullptr) ? params1->Size() : 0u; + const DexFile::TypeList* params2 = mr2.dex_file->GetProtoParameters(prid2); + size_t param2_size = (params2 != nullptr) ? params2->Size() : 0u; + for (size_t i = 0, num = std::min(param1_size, param2_size); i != num; ++i) { + int param_diff = strcmp(mr1.dex_file->StringByTypeIdx(params1->GetTypeItem(i).type_idx_), + mr2.dex_file->StringByTypeIdx(params2->GetTypeItem(i).type_idx_)); + if (param_diff != 0) { + return param_diff < 0; + } + } + return param1_size < param2_size; + } +}; + } // namespace art #endif // ART_RUNTIME_METHOD_REFERENCE_H_ diff --git a/runtime/oat.cc b/runtime/oat.cc index d14b399a9a..267a975425 100644 --- a/runtime/oat.cc +++ b/runtime/oat.cc @@ -71,6 +71,7 @@ OatHeader::OatHeader(InstructionSet instruction_set, instruction_set_(instruction_set), instruction_set_features_bitmap_(instruction_set_features->AsBitmap()), dex_file_count_(dex_file_count), + oat_dex_files_offset_(0), executable_offset_(0), interpreter_to_interpreter_bridge_offset_(0), interpreter_to_compiled_code_bridge_offset_(0), @@ -203,6 +204,20 @@ uint32_t OatHeader::GetInstructionSetFeaturesBitmap() const { return instruction_set_features_bitmap_; } +uint32_t OatHeader::GetOatDexFilesOffset() const { + DCHECK(IsValid()); + DCHECK_GT(oat_dex_files_offset_, sizeof(OatHeader)); + return oat_dex_files_offset_; +} + +void OatHeader::SetOatDexFilesOffset(uint32_t oat_dex_files_offset) { + DCHECK_GT(oat_dex_files_offset, sizeof(OatHeader)); + DCHECK(IsValid()); + DCHECK_EQ(oat_dex_files_offset_, 0u); + + oat_dex_files_offset_ = oat_dex_files_offset; +} + uint32_t OatHeader::GetExecutableOffset() const { DCHECK(IsValid()); DCHECK_ALIGNED(executable_offset_, kPageSize); diff --git a/runtime/oat.h b/runtime/oat.h index 57c2f9f6e6..521cc40764 100644 --- a/runtime/oat.h +++ b/runtime/oat.h @@ -32,7 +32,7 @@ class InstructionSetFeatures; class PACKED(4) OatHeader { public: static constexpr uint8_t kOatMagic[] = { 'o', 'a', 't', '\n' }; - static constexpr uint8_t kOatVersion[] = { '1', '2', '6', '\0' }; // Shuffle access flags. + static constexpr uint8_t kOatVersion[] = { '1', '2', '7', '\0' }; // .bss ArtMethod* section. static constexpr const char* kImageLocationKey = "image-location"; static constexpr const char* kDex2OatCmdLineKey = "dex2oat-cmdline"; @@ -64,6 +64,8 @@ class PACKED(4) OatHeader { DCHECK(IsValid()); return dex_file_count_; } + uint32_t GetOatDexFilesOffset() const; + void SetOatDexFilesOffset(uint32_t oat_dex_files_offset); uint32_t GetExecutableOffset() const; void SetExecutableOffset(uint32_t executable_offset); @@ -135,6 +137,7 @@ class PACKED(4) OatHeader { InstructionSet instruction_set_; uint32_t instruction_set_features_bitmap_; uint32_t dex_file_count_; + uint32_t oat_dex_files_offset_; uint32_t executable_offset_; uint32_t interpreter_to_interpreter_bridge_offset_; uint32_t interpreter_to_compiled_code_bridge_offset_; diff --git a/runtime/oat_file.cc b/runtime/oat_file.cc index a816522b9e..888de457dc 100644 --- a/runtime/oat_file.cc +++ b/runtime/oat_file.cc @@ -246,6 +246,9 @@ bool OatFileBase::ComputeFields(uint8_t* requested_base, } // Readjust to be non-inclusive upper bound. bss_end_ += sizeof(uint32_t); + // Find bss methods if present. + bss_methods_ = + const_cast<uint8_t*>(FindDynamicSymbolAddress("oatbssmethods", &symbol_error_msg)); // Find bss roots if present. bss_roots_ = const_cast<uint8_t*>(FindDynamicSymbolAddress("oatbssroots", &symbol_error_msg)); } @@ -311,51 +314,63 @@ bool OatFileBase::Setup(const char* abs_dex_location, std::string* error_msg) { cause.c_str()); return false; } - const uint8_t* oat = Begin(); - oat += sizeof(OatHeader); - if (oat > End()) { - *error_msg = StringPrintf("In oat file '%s' found truncated OatHeader", GetLocation().c_str()); + PointerSize pointer_size = GetInstructionSetPointerSize(GetOatHeader().GetInstructionSet()); + size_t key_value_store_size = + (Size() >= sizeof(OatHeader)) ? GetOatHeader().GetKeyValueStoreSize() : 0u; + if (Size() < sizeof(OatHeader) + key_value_store_size) { + *error_msg = StringPrintf("In oat file '%s' found truncated OatHeader, " + "size = %zu < %zu + %zu", + GetLocation().c_str(), + Size(), + sizeof(OatHeader), + key_value_store_size); return false; } - oat += GetOatHeader().GetKeyValueStoreSize(); - if (oat > End()) { - *error_msg = StringPrintf("In oat file '%s' found truncated variable-size data: " - "%p + %zu + %u <= %p", + size_t oat_dex_files_offset = GetOatHeader().GetOatDexFilesOffset(); + if (oat_dex_files_offset < GetOatHeader().GetHeaderSize() || oat_dex_files_offset > Size()) { + *error_msg = StringPrintf("In oat file '%s' found invalid oat dex files offset: " + "%zu is not in [%zu, %zu]", GetLocation().c_str(), - Begin(), - sizeof(OatHeader), - GetOatHeader().GetKeyValueStoreSize(), - End()); + oat_dex_files_offset, + GetOatHeader().GetHeaderSize(), + Size()); return false; } + const uint8_t* oat = Begin() + oat_dex_files_offset; // Jump to the OatDexFile records. - if (!IsAligned<alignof(GcRoot<mirror::Object>)>(bss_begin_) || - !IsAligned<alignof(GcRoot<mirror::Object>)>(bss_roots_) || + DCHECK_GE(static_cast<size_t>(pointer_size), alignof(GcRoot<mirror::Object>)); + if (!IsAligned<kPageSize>(bss_begin_) || + !IsAlignedParam(bss_methods_, static_cast<size_t>(pointer_size)) || + !IsAlignedParam(bss_roots_, static_cast<size_t>(pointer_size)) || !IsAligned<alignof(GcRoot<mirror::Object>)>(bss_end_)) { *error_msg = StringPrintf("In oat file '%s' found unaligned bss symbol(s): " - "begin = %p, roots = %p, end = %p", + "begin = %p, methods_ = %p, roots = %p, end = %p", GetLocation().c_str(), bss_begin_, + bss_methods_, bss_roots_, bss_end_); return false; } - if (bss_roots_ != nullptr && (bss_roots_ < bss_begin_ || bss_roots_ > bss_end_)) { - *error_msg = StringPrintf("In oat file '%s' found bss roots outside .bss: " - "%p is outside range [%p, %p]", + if ((bss_methods_ != nullptr && (bss_methods_ < bss_begin_ || bss_methods_ > bss_end_)) || + (bss_roots_ != nullptr && (bss_roots_ < bss_begin_ || bss_roots_ > bss_end_)) || + (bss_methods_ != nullptr && bss_roots_ != nullptr && bss_methods_ > bss_roots_)) { + *error_msg = StringPrintf("In oat file '%s' found bss symbol(s) outside .bss or unordered: " + "begin = %p, methods_ = %p, roots = %p, end = %p", GetLocation().c_str(), - bss_roots_, bss_begin_, + bss_methods_, + bss_roots_, bss_end_); return false; } - PointerSize pointer_size = GetInstructionSetPointerSize(GetOatHeader().GetInstructionSet()); - uint8_t* dex_cache_arrays = (bss_begin_ == bss_roots_) ? nullptr : bss_begin_; + uint8_t* after_arrays = (bss_methods_ != nullptr) ? bss_methods_ : bss_roots_; // May be null. + uint8_t* dex_cache_arrays = (bss_begin_ == after_arrays) ? nullptr : bss_begin_; uint8_t* dex_cache_arrays_end = - (bss_begin_ == bss_roots_) ? nullptr : (bss_roots_ != nullptr) ? bss_roots_ : bss_end_; + (bss_begin_ == after_arrays) ? nullptr : (after_arrays != nullptr) ? after_arrays : bss_end_; DCHECK_EQ(dex_cache_arrays != nullptr, dex_cache_arrays_end != nullptr); uint32_t dex_file_count = GetOatHeader().GetDexFileCount(); oat_dex_files_storage_.reserve(dex_file_count); @@ -529,6 +544,55 @@ bool OatFileBase::Setup(const char* abs_dex_location, std::string* error_msg) { return false; } + uint32_t method_bss_mapping_offset; + if (UNLIKELY(!ReadOatDexFileData(*this, &oat, &method_bss_mapping_offset))) { + *error_msg = StringPrintf("In oat file '%s' found OatDexFile #%zd for '%s' truncated " + "after method bss mapping offset", + GetLocation().c_str(), + i, + dex_file_location.c_str()); + return false; + } + const bool readable_method_bss_mapping_size = + method_bss_mapping_offset != 0u && + method_bss_mapping_offset <= Size() && + IsAligned<alignof(MethodBssMapping)>(method_bss_mapping_offset) && + Size() - method_bss_mapping_offset >= MethodBssMapping::ComputeSize(0); + const MethodBssMapping* method_bss_mapping = readable_method_bss_mapping_size + ? reinterpret_cast<const MethodBssMapping*>(Begin() + method_bss_mapping_offset) + : nullptr; + if (method_bss_mapping_offset != 0u && + (UNLIKELY(method_bss_mapping == nullptr) || + UNLIKELY(method_bss_mapping->size() == 0u) || + UNLIKELY(Size() - method_bss_mapping_offset < + MethodBssMapping::ComputeSize(method_bss_mapping->size())))) { + *error_msg = StringPrintf("In oat file '%s' found OatDexFile #%zu for '%s' with unaligned or " + " truncated method bss mapping, offset %u of %zu, length %zu", + GetLocation().c_str(), + i, + dex_file_location.c_str(), + method_bss_mapping_offset, + Size(), + method_bss_mapping != nullptr ? method_bss_mapping->size() : 0u); + return false; + } + if (kIsDebugBuild && method_bss_mapping != nullptr) { + const MethodBssMappingEntry* prev_entry = nullptr; + for (const MethodBssMappingEntry& entry : *method_bss_mapping) { + CHECK_ALIGNED_PARAM(entry.bss_offset, static_cast<size_t>(pointer_size)); + CHECK_LT(entry.bss_offset, BssSize()); + CHECK_LE(POPCOUNT(entry.index_mask) * static_cast<size_t>(pointer_size), entry.bss_offset); + size_t index_mask_span = (entry.index_mask != 0u) ? 16u - CTZ(entry.index_mask) : 0u; + CHECK_LE(index_mask_span, entry.method_index); + if (prev_entry != nullptr) { + CHECK_LT(prev_entry->method_index, entry.method_index - index_mask_span); + } + prev_entry = &entry; + } + CHECK_LT(prev_entry->method_index, + reinterpret_cast<const DexFile::Header*>(dex_file_pointer)->method_ids_size_); + } + uint8_t* current_dex_cache_arrays = nullptr; if (dex_cache_arrays != nullptr) { // All DexCache types except for CallSite have their instance counts in the @@ -569,6 +633,7 @@ bool OatFileBase::Setup(const char* abs_dex_location, std::string* error_msg) { dex_file_checksum, dex_file_pointer, lookup_table_data, + method_bss_mapping, class_offsets_pointer, current_dex_cache_arrays); oat_dex_files_storage_.push_back(oat_dex_file); @@ -1158,6 +1223,7 @@ OatFile::OatFile(const std::string& location, bool is_executable) end_(nullptr), bss_begin_(nullptr), bss_end_(nullptr), + bss_methods_(nullptr), bss_roots_(nullptr), is_executable_(is_executable), secondary_lookup_lock_("OatFile secondary lookup lock", kOatFileSecondaryLookupLock) { @@ -1198,6 +1264,17 @@ const uint8_t* OatFile::DexEnd() const { return kIsVdexEnabled ? vdex_->End() : End(); } +ArrayRef<ArtMethod*> OatFile::GetBssMethods() const { + if (bss_methods_ != nullptr) { + ArtMethod** methods = reinterpret_cast<ArtMethod**>(bss_methods_); + ArtMethod** methods_end = + reinterpret_cast<ArtMethod**>(bss_roots_ != nullptr ? bss_roots_ : bss_end_); + return ArrayRef<ArtMethod*>(methods, methods_end - methods); + } else { + return ArrayRef<ArtMethod*>(); + } +} + ArrayRef<GcRoot<mirror::Object>> OatFile::GetBssGcRoots() const { if (bss_roots_ != nullptr) { auto* roots = reinterpret_cast<GcRoot<mirror::Object>*>(bss_roots_); @@ -1283,6 +1360,7 @@ OatFile::OatDexFile::OatDexFile(const OatFile* oat_file, uint32_t dex_file_location_checksum, const uint8_t* dex_file_pointer, const uint8_t* lookup_table_data, + const MethodBssMapping* method_bss_mapping_data, const uint32_t* oat_class_offsets_pointer, uint8_t* dex_cache_arrays) : oat_file_(oat_file), @@ -1291,6 +1369,7 @@ OatFile::OatDexFile::OatDexFile(const OatFile* oat_file, dex_file_location_checksum_(dex_file_location_checksum), dex_file_pointer_(dex_file_pointer), lookup_table_data_(lookup_table_data), + method_bss_mapping_(method_bss_mapping_data), oat_class_offsets_pointer_(oat_class_offsets_pointer), dex_cache_arrays_(dex_cache_arrays) { // Initialize TypeLookupTable. diff --git a/runtime/oat_file.h b/runtime/oat_file.h index a6d2eba354..66ed44f1b9 100644 --- a/runtime/oat_file.h +++ b/runtime/oat_file.h @@ -26,6 +26,7 @@ #include "base/stringpiece.h" #include "compiler_filter.h" #include "dex_file.h" +#include "method_bss_mapping.h" #include "mirror/class.h" #include "oat.h" #include "os.h" @@ -257,8 +258,14 @@ class OatFile { return BssEnd() - BssBegin(); } + size_t BssMethodsOffset() const { + // Note: This is used only for symbolizer and needs to return a valid .bss offset. + return (bss_methods_ != nullptr) ? bss_methods_ - BssBegin() : BssRootsOffset(); + } + size_t BssRootsOffset() const { - return bss_roots_ - BssBegin(); + // Note: This is used only for symbolizer and needs to return a valid .bss offset. + return (bss_roots_ != nullptr) ? bss_roots_ - BssBegin() : BssSize(); } size_t DexSize() const { @@ -274,6 +281,7 @@ class OatFile { const uint8_t* DexBegin() const; const uint8_t* DexEnd() const; + ArrayRef<ArtMethod*> GetBssMethods() const; ArrayRef<GcRoot<mirror::Object>> GetBssGcRoots() const; // Returns the absolute dex location for the encoded relative dex location. @@ -325,6 +333,9 @@ class OatFile { // Pointer to the end of the .bss section, if present, otherwise null. uint8_t* bss_end_; + // Pointer to the beginning of the ArtMethod*s in .bss section, if present, otherwise null. + uint8_t* bss_methods_; + // Pointer to the beginning of the GC roots in .bss section, if present, otherwise null. uint8_t* bss_roots_; @@ -422,6 +433,10 @@ class OatDexFile FINAL { return lookup_table_data_; } + const MethodBssMapping* GetMethodBssMapping() const { + return method_bss_mapping_; + } + const uint8_t* GetDexFilePointer() const { return dex_file_pointer_; } @@ -448,6 +463,7 @@ class OatDexFile FINAL { uint32_t dex_file_checksum, const uint8_t* dex_file_pointer, const uint8_t* lookup_table_data, + const MethodBssMapping* method_bss_mapping, const uint32_t* oat_class_offsets_pointer, uint8_t* dex_cache_arrays); @@ -458,7 +474,8 @@ class OatDexFile FINAL { const std::string canonical_dex_file_location_; const uint32_t dex_file_location_checksum_ = 0u; const uint8_t* const dex_file_pointer_ = nullptr; - const uint8_t* lookup_table_data_ = nullptr; + const uint8_t* const lookup_table_data_ = nullptr; + const MethodBssMapping* const method_bss_mapping_ = nullptr; const uint32_t* const oat_class_offsets_pointer_ = 0u; uint8_t* const dex_cache_arrays_ = nullptr; mutable std::unique_ptr<TypeLookupTable> lookup_table_; diff --git a/runtime/stride_iterator.h b/runtime/stride_iterator.h index ac04c3b403..0560c33eee 100644 --- a/runtime/stride_iterator.h +++ b/runtime/stride_iterator.h @@ -24,8 +24,11 @@ namespace art { template<typename T> -class StrideIterator : public std::iterator<std::forward_iterator_tag, T> { +class StrideIterator : public std::iterator<std::random_access_iterator_tag, T> { public: + using difference_type = + typename std::iterator<std::random_access_iterator_tag, T>::difference_type; + StrideIterator(const StrideIterator&) = default; StrideIterator(StrideIterator&&) = default; StrideIterator& operator=(const StrideIterator&) = default; @@ -44,28 +47,56 @@ class StrideIterator : public std::iterator<std::forward_iterator_tag, T> { return !(*this == other); } - StrideIterator operator++() { // Value after modification. + StrideIterator& operator++() { // Value after modification. ptr_ += stride_; return *this; } StrideIterator operator++(int) { StrideIterator<T> temp = *this; - ptr_ += stride_; + ++*this; return temp; } - StrideIterator operator+(ssize_t delta) const { + StrideIterator& operator--() { // Value after modification. + ptr_ -= stride_; + return *this; + } + + StrideIterator operator--(int) { StrideIterator<T> temp = *this; - temp += delta; + --*this; return temp; } - StrideIterator& operator+=(ssize_t delta) { + StrideIterator& operator+=(difference_type delta) { ptr_ += static_cast<ssize_t>(stride_) * delta; return *this; } + StrideIterator operator+(difference_type delta) const { + StrideIterator<T> temp = *this; + temp += delta; + return temp; + } + + StrideIterator& operator-=(difference_type delta) { + ptr_ -= static_cast<ssize_t>(stride_) * delta; + return *this; + } + + StrideIterator operator-(difference_type delta) const { + StrideIterator<T> temp = *this; + temp -= delta; + return temp; + } + + difference_type operator-(const StrideIterator& rhs) { + DCHECK_EQ(stride_, rhs.stride_); + DCHECK_EQ((ptr_ - rhs.ptr_) % stride_, 0u); + return (ptr_ - rhs.ptr_) / stride_; + } + T& operator*() const { return *reinterpret_cast<T*>(ptr_); } @@ -74,12 +105,46 @@ class StrideIterator : public std::iterator<std::forward_iterator_tag, T> { return &**this; } + T& operator[](difference_type n) { + return *(*this + n); + } + private: uintptr_t ptr_; // Not const for operator=. size_t stride_; + + template <typename U> + friend bool operator<(const StrideIterator<U>& lhs, const StrideIterator<U>& rhs); }; +template <typename T> +StrideIterator<T> operator+(typename StrideIterator<T>::difference_type dist, + const StrideIterator<T>& it) { + return it + dist; +} + +template <typename T> +bool operator<(const StrideIterator<T>& lhs, const StrideIterator<T>& rhs) { + DCHECK_EQ(lhs.stride_, rhs.stride_); + return lhs.ptr_ < rhs.ptr_; +} + +template <typename T> +bool operator>(const StrideIterator<T>& lhs, const StrideIterator<T>& rhs) { + return rhs < lhs; +} + +template <typename T> +bool operator<=(const StrideIterator<T>& lhs, const StrideIterator<T>& rhs) { + return !(rhs < lhs); +} + +template <typename T> +bool operator>=(const StrideIterator<T>& lhs, const StrideIterator<T>& rhs) { + return !(lhs < rhs); +} + } // namespace art #endif // ART_RUNTIME_STRIDE_ITERATOR_H_ diff --git a/test/551-checker-shifter-operand/src/Main.java b/test/551-checker-shifter-operand/src/Main.java index bf09a6aa5e..951889ab9f 100644 --- a/test/551-checker-shifter-operand/src/Main.java +++ b/test/551-checker-shifter-operand/src/Main.java @@ -234,8 +234,8 @@ public class Main { /// CHECK-START-ARM: void Main.$opt$noinline$testAnd(long, long) disassembly (after) /// CHECK: and lsl /// CHECK: sbfx - /// CHECK: asr - /// CHECK: and + /// CHECK: asr{{s?}} + /// CHECK: and{{s?}} /// CHECK-START-ARM64: void Main.$opt$noinline$testAnd(long, long) instruction_simplifier_arm64 (after) /// CHECK: DataProcWithShifterOp @@ -259,7 +259,7 @@ public class Main { /// CHECK-START-ARM: void Main.$opt$noinline$testOr(int, int) disassembly (after) /// CHECK: orr asr /// CHECK: ubfx - /// CHECK: orr + /// CHECK: orr{{s?}} /// CHECK-START-ARM64: void Main.$opt$noinline$testOr(int, int) instruction_simplifier_arm64 (after) /// CHECK: DataProcWithShifterOp @@ -282,9 +282,8 @@ public class Main { /// CHECK-START-ARM: void Main.$opt$noinline$testXor(long, long) disassembly (after) /// CHECK: eor lsr - /// CHECK: mov - /// CHECK: asr - /// CHECK: eor + /// CHECK: asr{{s?}} + /// CHECK: eor{{s?}} /// CHECK-START-ARM64: void Main.$opt$noinline$testXor(long, long) instruction_simplifier_arm64 (after) /// CHECK: DataProcWithShifterOp diff --git a/test/552-checker-sharpening/src/Main.java b/test/552-checker-sharpening/src/Main.java index 4bb179ecc4..7408e6d263 100644 --- a/test/552-checker-sharpening/src/Main.java +++ b/test/552-checker-sharpening/src/Main.java @@ -45,28 +45,27 @@ public class Main { /// CHECK: InvokeStaticOrDirect method_load_kind:RuntimeCall /// CHECK-START-ARM: int Main.testSimple(int) sharpening (after) - /// CHECK-NOT: ArmDexCacheArraysBase - /// CHECK: InvokeStaticOrDirect method_load_kind:DexCachePcRelative + /// CHECK: InvokeStaticOrDirect method_load_kind:BssEntry /// CHECK-START-ARM64: int Main.testSimple(int) sharpening (after) - /// CHECK: InvokeStaticOrDirect method_load_kind:DexCachePcRelative + /// CHECK: InvokeStaticOrDirect method_load_kind:BssEntry /// CHECK-START-MIPS: int Main.testSimple(int) sharpening (after) - /// CHECK: InvokeStaticOrDirect method_load_kind:DexCachePcRelative + /// CHECK: InvokeStaticOrDirect method_load_kind:BssEntry /// CHECK-START-MIPS64: int Main.testSimple(int) sharpening (after) - /// CHECK: InvokeStaticOrDirect method_load_kind:DexCachePcRelative + /// CHECK: InvokeStaticOrDirect method_load_kind:BssEntry /// CHECK-START-X86: int Main.testSimple(int) sharpening (after) /// CHECK-NOT: X86ComputeBaseMethodAddress - /// CHECK: InvokeStaticOrDirect method_load_kind:DexCachePcRelative + /// CHECK: InvokeStaticOrDirect method_load_kind:BssEntry /// CHECK-START-X86_64: int Main.testSimple(int) sharpening (after) - /// CHECK: InvokeStaticOrDirect method_load_kind:DexCachePcRelative + /// CHECK: InvokeStaticOrDirect method_load_kind:BssEntry - /// CHECK-START-ARM: int Main.testSimple(int) dex_cache_array_fixups_arm (after) - /// CHECK: ArmDexCacheArraysBase - /// CHECK-NOT: ArmDexCacheArraysBase + /// CHECK-START-MIPS: int Main.testSimple(int) pc_relative_fixups_mips (after) + /// CHECK: MipsComputeBaseMethodAddress + /// CHECK-NOT: MipsComputeBaseMethodAddress /// CHECK-START-X86: int Main.testSimple(int) pc_relative_fixups_x86 (after) /// CHECK: X86ComputeBaseMethodAddress @@ -81,37 +80,36 @@ public class Main { /// CHECK: InvokeStaticOrDirect method_load_kind:RuntimeCall /// CHECK-START-ARM: int Main.testDiamond(boolean, int) sharpening (after) - /// CHECK-NOT: ArmDexCacheArraysBase - /// CHECK: InvokeStaticOrDirect method_load_kind:DexCachePcRelative - /// CHECK: InvokeStaticOrDirect method_load_kind:DexCachePcRelative + /// CHECK: InvokeStaticOrDirect method_load_kind:BssEntry + /// CHECK: InvokeStaticOrDirect method_load_kind:BssEntry /// CHECK-START-ARM64: int Main.testDiamond(boolean, int) sharpening (after) - /// CHECK: InvokeStaticOrDirect method_load_kind:DexCachePcRelative - /// CHECK: InvokeStaticOrDirect method_load_kind:DexCachePcRelative + /// CHECK: InvokeStaticOrDirect method_load_kind:BssEntry + /// CHECK: InvokeStaticOrDirect method_load_kind:BssEntry /// CHECK-START-MIPS: int Main.testDiamond(boolean, int) sharpening (after) - /// CHECK: InvokeStaticOrDirect method_load_kind:DexCachePcRelative - /// CHECK: InvokeStaticOrDirect method_load_kind:DexCachePcRelative + /// CHECK: InvokeStaticOrDirect method_load_kind:BssEntry + /// CHECK: InvokeStaticOrDirect method_load_kind:BssEntry /// CHECK-START-MIPS64: int Main.testDiamond(boolean, int) sharpening (after) - /// CHECK: InvokeStaticOrDirect method_load_kind:DexCachePcRelative - /// CHECK: InvokeStaticOrDirect method_load_kind:DexCachePcRelative + /// CHECK: InvokeStaticOrDirect method_load_kind:BssEntry + /// CHECK: InvokeStaticOrDirect method_load_kind:BssEntry /// CHECK-START-X86: int Main.testDiamond(boolean, int) sharpening (after) /// CHECK-NOT: X86ComputeBaseMethodAddress - /// CHECK: InvokeStaticOrDirect method_load_kind:DexCachePcRelative - /// CHECK: InvokeStaticOrDirect method_load_kind:DexCachePcRelative + /// CHECK: InvokeStaticOrDirect method_load_kind:BssEntry + /// CHECK: InvokeStaticOrDirect method_load_kind:BssEntry /// CHECK-START-X86_64: int Main.testDiamond(boolean, int) sharpening (after) - /// CHECK: InvokeStaticOrDirect method_load_kind:DexCachePcRelative - /// CHECK: InvokeStaticOrDirect method_load_kind:DexCachePcRelative + /// CHECK: InvokeStaticOrDirect method_load_kind:BssEntry + /// CHECK: InvokeStaticOrDirect method_load_kind:BssEntry - /// CHECK-START-ARM: int Main.testDiamond(boolean, int) dex_cache_array_fixups_arm (after) - /// CHECK: ArmDexCacheArraysBase - /// CHECK-NOT: ArmDexCacheArraysBase + /// CHECK-START-MIPS: int Main.testDiamond(boolean, int) pc_relative_fixups_mips (after) + /// CHECK: MipsComputeBaseMethodAddress + /// CHECK-NOT: MipsComputeBaseMethodAddress - /// CHECK-START-ARM: int Main.testDiamond(boolean, int) dex_cache_array_fixups_arm (after) - /// CHECK: ArmDexCacheArraysBase + /// CHECK-START-MIPS: int Main.testDiamond(boolean, int) pc_relative_fixups_mips (after) + /// CHECK: MipsComputeBaseMethodAddress /// CHECK-NEXT: If /// CHECK-START-X86: int Main.testDiamond(boolean, int) pc_relative_fixups_x86 (after) @@ -123,8 +121,8 @@ public class Main { /// CHECK-NEXT: If public static int testDiamond(boolean negate, int x) { - // These calls should use PC-relative dex cache array loads to retrieve the target method. - // PC-relative bases used by ARM, MIPS and X86 should be pulled before the If. + // These calls should use PC-relative loads to retrieve the target method. + // PC-relative bases used by MIPS and X86 should be pulled before the If. if (negate) { return $noinline$foo(-x); } else { @@ -132,72 +130,72 @@ public class Main { } } - /// CHECK-START-X86: int Main.testLoop(int[], int) pc_relative_fixups_x86 (before) - /// CHECK-NOT: X86ComputeBaseMethodAddress + /// CHECK-START-MIPS: int Main.testLoop(int[], int) pc_relative_fixups_mips (before) + /// CHECK-NOT: MipsComputeBaseMethodAddress - /// CHECK-START-X86: int Main.testLoop(int[], int) pc_relative_fixups_x86 (after) - /// CHECK: X86ComputeBaseMethodAddress - /// CHECK-NOT: X86ComputeBaseMethodAddress + /// CHECK-START-MIPS: int Main.testLoop(int[], int) pc_relative_fixups_mips (after) + /// CHECK: MipsComputeBaseMethodAddress + /// CHECK-NOT: MipsComputeBaseMethodAddress - /// CHECK-START-X86: int Main.testLoop(int[], int) pc_relative_fixups_x86 (after) + /// CHECK-START-MIPS: int Main.testLoop(int[], int) pc_relative_fixups_mips (after) /// CHECK: InvokeStaticOrDirect /// CHECK-NOT: InvokeStaticOrDirect - /// CHECK-START-X86: int Main.testLoop(int[], int) pc_relative_fixups_x86 (after) + /// CHECK-START-MIPS: int Main.testLoop(int[], int) pc_relative_fixups_mips (after) /// CHECK: ArrayLength - /// CHECK-NEXT: X86ComputeBaseMethodAddress + /// CHECK-NEXT: MipsComputeBaseMethodAddress /// CHECK-NEXT: Goto /// CHECK: begin_block - /// CHECK: InvokeStaticOrDirect method_load_kind:DexCachePcRelative + /// CHECK: InvokeStaticOrDirect method_load_kind:BssEntry - /// CHECK-START-ARM: int Main.testLoop(int[], int) dex_cache_array_fixups_arm (before) - /// CHECK-NOT: ArmDexCacheArraysBase + /// CHECK-START-X86: int Main.testLoop(int[], int) pc_relative_fixups_x86 (before) + /// CHECK-NOT: X86ComputeBaseMethodAddress - /// CHECK-START-ARM: int Main.testLoop(int[], int) dex_cache_array_fixups_arm (after) - /// CHECK: ArmDexCacheArraysBase - /// CHECK-NOT: ArmDexCacheArraysBase + /// CHECK-START-X86: int Main.testLoop(int[], int) pc_relative_fixups_x86 (after) + /// CHECK: X86ComputeBaseMethodAddress + /// CHECK-NOT: X86ComputeBaseMethodAddress - /// CHECK-START-ARM: int Main.testLoop(int[], int) dex_cache_array_fixups_arm (after) + /// CHECK-START-X86: int Main.testLoop(int[], int) pc_relative_fixups_x86 (after) /// CHECK: InvokeStaticOrDirect /// CHECK-NOT: InvokeStaticOrDirect - /// CHECK-START-ARM: int Main.testLoop(int[], int) dex_cache_array_fixups_arm (after) + /// CHECK-START-X86: int Main.testLoop(int[], int) pc_relative_fixups_x86 (after) /// CHECK: ArrayLength - /// CHECK-NEXT: ArmDexCacheArraysBase + /// CHECK-NEXT: X86ComputeBaseMethodAddress /// CHECK-NEXT: Goto /// CHECK: begin_block - /// CHECK: InvokeStaticOrDirect method_load_kind:DexCachePcRelative + /// CHECK: InvokeStaticOrDirect method_load_kind:BssEntry public static int testLoop(int[] array, int x) { - // PC-relative bases used by ARM, MIPS and X86 should be pulled before the loop. + // PC-relative bases used by MIPS and X86 should be pulled before the loop. for (int i : array) { x += $noinline$foo(i); } return x; } - /// CHECK-START-X86: int Main.testLoopWithDiamond(int[], boolean, int) pc_relative_fixups_x86 (before) - /// CHECK-NOT: X86ComputeBaseMethodAddress + /// CHECK-START-MIPS: int Main.testLoopWithDiamond(int[], boolean, int) pc_relative_fixups_mips (before) + /// CHECK-NOT: MipsComputeBaseMethodAddress - /// CHECK-START-X86: int Main.testLoopWithDiamond(int[], boolean, int) pc_relative_fixups_x86 (after) + /// CHECK-START-MIPS: int Main.testLoopWithDiamond(int[], boolean, int) pc_relative_fixups_mips (after) /// CHECK: If /// CHECK: begin_block /// CHECK: ArrayLength - /// CHECK-NEXT: X86ComputeBaseMethodAddress + /// CHECK-NEXT: MipsComputeBaseMethodAddress /// CHECK-NEXT: Goto - /// CHECK-START-ARM: int Main.testLoopWithDiamond(int[], boolean, int) dex_cache_array_fixups_arm (before) - /// CHECK-NOT: ArmDexCacheArraysBase + /// CHECK-START-X86: int Main.testLoopWithDiamond(int[], boolean, int) pc_relative_fixups_x86 (before) + /// CHECK-NOT: X86ComputeBaseMethodAddress - /// CHECK-START-ARM: int Main.testLoopWithDiamond(int[], boolean, int) dex_cache_array_fixups_arm (after) + /// CHECK-START-X86: int Main.testLoopWithDiamond(int[], boolean, int) pc_relative_fixups_x86 (after) /// CHECK: If /// CHECK: begin_block /// CHECK: ArrayLength - /// CHECK-NEXT: ArmDexCacheArraysBase + /// CHECK-NEXT: X86ComputeBaseMethodAddress /// CHECK-NEXT: Goto public static int testLoopWithDiamond(int[] array, boolean negate, int x) { - // PC-relative bases used by ARM, MIPS and X86 should be pulled before the loop + // PC-relative bases used by MIPS and X86 should be pulled before the loop // but not outside the if. if (array != null) { for (int i : array) { |