diff options
author | 2017-09-06 17:21:03 +0100 | |
---|---|---|
committer | 2017-09-11 15:12:51 +0100 | |
commit | 94ec2db21332ee1dcdbbf254b99a9a999a304fe0 (patch) | |
tree | 6ced7e596731b61f95a3693f336527f55ea3cf3a | |
parent | 6cfbdbc359ec5414d3e49f70d28f8c0e65b98d63 (diff) |
Use mmapped boot image class table for PIC app HLoadClass.
Implement new HLoadClass load kind for boot image classes
referenced by PIC-compiled apps (i.e. prebuilts) that uses
PC-relative load from a boot image ClassTable mmapped into
the apps .bss. This reduces the size of the PIC prebuilts
that reference boot image classes compared to the kBssEntry
as we can completely avoid the slow path and stack map
unless we need to do the class initialization check.
Prebuilt services.odex for aosp_angler-userdebug (arm64):
- before: 20312800
- after: 19775352 (-525KiB)
Test: m test-art-host-gtest
Test: testrunner.py --host
Test: testrunner.py --host --pictest
Test: testrunner.py --target on Nexus 6P.
Test: testrunner.py --target --pictest on Nexus 6P.
Test: Nexus 6P boots.
Bug: 31951624
Change-Id: I13adb19a1fa7d095a72a41f09daa6101876e77a8
-rw-r--r-- | compiler/compiled_method.h | 15 | ||||
-rw-r--r-- | compiler/linker/arm64/relative_patcher_arm64.cc | 2 | ||||
-rw-r--r-- | compiler/oat_writer.cc | 47 | ||||
-rw-r--r-- | compiler/oat_writer.h | 2 | ||||
-rw-r--r-- | compiler/optimizing/code_generator_arm64.cc | 24 | ||||
-rw-r--r-- | compiler/optimizing/code_generator_arm_vixl.cc | 19 | ||||
-rw-r--r-- | compiler/optimizing/code_generator_mips.cc | 24 | ||||
-rw-r--r-- | compiler/optimizing/code_generator_mips64.cc | 21 | ||||
-rw-r--r-- | compiler/optimizing/code_generator_x86.cc | 19 | ||||
-rw-r--r-- | compiler/optimizing/code_generator_x86_64.cc | 17 | ||||
-rw-r--r-- | compiler/optimizing/nodes.cc | 3 | ||||
-rw-r--r-- | compiler/optimizing/nodes.h | 6 | ||||
-rw-r--r-- | compiler/optimizing/pc_relative_fixups_mips.cc | 1 | ||||
-rw-r--r-- | compiler/optimizing/pc_relative_fixups_x86.cc | 1 | ||||
-rw-r--r-- | compiler/optimizing/sharpening.cc | 12 | ||||
-rw-r--r-- | runtime/class_linker.h | 2 | ||||
-rw-r--r-- | runtime/class_table.h | 1 | ||||
-rw-r--r-- | test/552-checker-sharpening/src/Main.java | 12 |
18 files changed, 207 insertions, 21 deletions
diff --git a/compiler/compiled_method.h b/compiler/compiled_method.h index c67c523eb3..5ef6cbff78 100644 --- a/compiler/compiled_method.h +++ b/compiler/compiled_method.h @@ -124,6 +124,7 @@ class LinkerPatch { kCall, kCallRelative, // NOTE: Actual patching is instruction_set-dependent. kTypeRelative, // NOTE: Actual patching is instruction_set-dependent. + kTypeClassTable, // NOTE: Actual patching is instruction_set-dependent. kTypeBssEntry, // NOTE: Actual patching is instruction_set-dependent. kStringRelative, // NOTE: Actual patching is instruction_set-dependent. kStringInternTable, // NOTE: Actual patching is instruction_set-dependent. @@ -177,6 +178,16 @@ class LinkerPatch { return patch; } + static LinkerPatch TypeClassTablePatch(size_t literal_offset, + const DexFile* target_dex_file, + uint32_t pc_insn_offset, + uint32_t target_type_idx) { + LinkerPatch patch(literal_offset, Type::kTypeClassTable, target_dex_file); + patch.type_idx_ = target_type_idx; + patch.pc_insn_offset_ = pc_insn_offset; + return patch; + } + static LinkerPatch TypeBssEntryPatch(size_t literal_offset, const DexFile* target_dex_file, uint32_t pc_insn_offset, @@ -243,6 +254,7 @@ class LinkerPatch { case Type::kMethodBssEntry: case Type::kCallRelative: case Type::kTypeRelative: + case Type::kTypeClassTable: case Type::kTypeBssEntry: case Type::kStringRelative: case Type::kStringInternTable: @@ -264,12 +276,14 @@ class LinkerPatch { const DexFile* TargetTypeDexFile() const { DCHECK(patch_type_ == Type::kTypeRelative || + patch_type_ == Type::kTypeClassTable || patch_type_ == Type::kTypeBssEntry); return target_dex_file_; } dex::TypeIndex TargetTypeIndex() const { DCHECK(patch_type_ == Type::kTypeRelative || + patch_type_ == Type::kTypeClassTable || patch_type_ == Type::kTypeBssEntry); return dex::TypeIndex(type_idx_); } @@ -292,6 +306,7 @@ class LinkerPatch { DCHECK(patch_type_ == Type::kMethodRelative || patch_type_ == Type::kMethodBssEntry || patch_type_ == Type::kTypeRelative || + patch_type_ == Type::kTypeClassTable || patch_type_ == Type::kTypeBssEntry || patch_type_ == Type::kStringRelative || patch_type_ == Type::kStringInternTable || diff --git a/compiler/linker/arm64/relative_patcher_arm64.cc b/compiler/linker/arm64/relative_patcher_arm64.cc index 0ebabc15aa..4960f4d856 100644 --- a/compiler/linker/arm64/relative_patcher_arm64.cc +++ b/compiler/linker/arm64/relative_patcher_arm64.cc @@ -61,6 +61,7 @@ inline bool IsAdrpPatch(const LinkerPatch& patch) { case LinkerPatch::Type::kMethodRelative: case LinkerPatch::Type::kMethodBssEntry: case LinkerPatch::Type::kTypeRelative: + case LinkerPatch::Type::kTypeClassTable: case LinkerPatch::Type::kTypeBssEntry: case LinkerPatch::Type::kStringRelative: case LinkerPatch::Type::kStringInternTable: @@ -266,6 +267,7 @@ void Arm64RelativePatcher::PatchPcRelativeReference(std::vector<uint8_t>* code, } else { // LDR/STR 32-bit or 64-bit with imm12 == 0 (unset). DCHECK(patch.GetType() == LinkerPatch::Type::kMethodBssEntry || + patch.GetType() == LinkerPatch::Type::kTypeClassTable || patch.GetType() == LinkerPatch::Type::kTypeBssEntry || patch.GetType() == LinkerPatch::Type::kStringInternTable || patch.GetType() == LinkerPatch::Type::kStringBssEntry) << patch.GetType(); diff --git a/compiler/oat_writer.cc b/compiler/oat_writer.cc index a33081e033..cc8c6dfac0 100644 --- a/compiler/oat_writer.cc +++ b/compiler/oat_writer.cc @@ -28,6 +28,7 @@ #include "base/stl_util.h" #include "base/unix_file/fd_file.h" #include "class_linker.h" +#include "class_table-inl.h" #include "compiled_method.h" #include "debug/method_debug_info.h" #include "dex/verification_results.h" @@ -772,7 +773,8 @@ class OatWriter::InitBssLayoutMethodVisitor : public DexMethodVisitor { } else if (patch.GetType() == LinkerPatch::Type::kStringBssEntry) { StringReference ref(patch.TargetStringDexFile(), patch.TargetStringIndex()); writer_->bss_string_entries_.Overwrite(ref, /* placeholder */ 0u); - } else if (patch.GetType() == LinkerPatch::Type::kStringInternTable) { + } else if (patch.GetType() == LinkerPatch::Type::kStringInternTable || + patch.GetType() == LinkerPatch::Type::kTypeClassTable) { writer_->map_boot_image_tables_to_bss_ = true; } } @@ -1427,6 +1429,14 @@ class OatWriter::WriteCodeMethodVisitor : public OatDexMethodVisitor { target_offset); break; } + case LinkerPatch::Type::kTypeClassTable: { + uint32_t target_offset = GetClassTableEntryOffset(patch); + writer_->relative_patcher_->PatchPcRelativeReference(&patched_code_, + patch, + offset_ + literal_offset, + target_offset); + break; + } case LinkerPatch::Type::kTypeBssEntry: { TypeReference ref(patch.TargetTypeDexFile(), patch.TargetTypeIndex()); uint32_t target_offset = writer_->bss_start_ + writer_->bss_type_entries_.Get(ref); @@ -1621,11 +1631,25 @@ class OatWriter::WriteCodeMethodVisitor : public OatDexMethodVisitor { const uint8_t* string_root = writer_->LookupBootImageInternTableSlot( *patch.TargetStringDexFile(), patch.TargetStringIndex()); DCHECK(string_root != nullptr); + return GetBootImageTableEntryOffset(string_root); + } + + // Calculate the offset of the ClassTable::TableSlot when mmapped to the .bss. + uint32_t GetClassTableEntryOffset(const LinkerPatch& patch) + REQUIRES_SHARED(Locks::mutator_lock_) { + DCHECK(!writer_->HasBootImage()); + const uint8_t* table_slot = + writer_->LookupBootImageClassTableSlot(*patch.TargetTypeDexFile(), patch.TargetTypeIndex()); + DCHECK(table_slot != nullptr); + return GetBootImageTableEntryOffset(table_slot); + } + + uint32_t GetBootImageTableEntryOffset(const uint8_t* raw_root) { uint32_t base_offset = writer_->bss_start_; for (gc::space::ImageSpace* space : Runtime::Current()->GetHeap()->GetBootImageSpaces()) { const uint8_t* const_tables_begin = space->Begin() + space->GetImageHeader().GetBootImageConstantTablesOffset(); - size_t offset = static_cast<size_t>(string_root - const_tables_begin); + size_t offset = static_cast<size_t>(raw_root - const_tables_begin); if (offset < space->GetImageHeader().GetBootImageConstantTablesSize()) { DCHECK_LE(base_offset + offset, writer_->bss_start_ + writer_->bss_methods_offset_); return base_offset + offset; @@ -3542,8 +3566,7 @@ bool OatWriter::OatClass::Write(OatWriter* oat_writer, OutputStream* out) const const uint8_t* OatWriter::LookupBootImageInternTableSlot(const DexFile& dex_file, dex::StringIndex string_idx) - NO_THREAD_SAFETY_ANALYSIS { - // Single-threaded OatWriter can avoid locking. + NO_THREAD_SAFETY_ANALYSIS { // Single-threaded OatWriter can avoid locking. uint32_t utf16_length; const char* utf8_data = dex_file.StringDataAndUtf16LengthByIdx(string_idx, &utf16_length); DCHECK_EQ(utf16_length, CountModifiedUtf8Chars(utf8_data)); @@ -3561,4 +3584,20 @@ const uint8_t* OatWriter::LookupBootImageInternTableSlot(const DexFile& dex_file UNREACHABLE(); } +const uint8_t* OatWriter::LookupBootImageClassTableSlot(const DexFile& dex_file, + dex::TypeIndex type_idx) + NO_THREAD_SAFETY_ANALYSIS { // Single-threaded OatWriter can avoid locking. + const char* descriptor = dex_file.StringByTypeIdx(type_idx); + ClassTable::DescriptorHashPair pair(descriptor, ComputeModifiedUtf8Hash(descriptor)); + ClassTable* table = Runtime::Current()->GetClassLinker()->boot_class_table_.get(); + for (const ClassTable::ClassSet& class_set : table->classes_) { + auto it = class_set.Find(pair); + if (it != class_set.end()) { + return reinterpret_cast<const uint8_t*>(std::addressof(*it)); + } + } + LOG(FATAL) << "Did not find boot image class " << descriptor; + UNREACHABLE(); +} + } // namespace art diff --git a/compiler/oat_writer.h b/compiler/oat_writer.h index 780dee0bac..7f2045f8da 100644 --- a/compiler/oat_writer.h +++ b/compiler/oat_writer.h @@ -336,6 +336,8 @@ class OatWriter { // Find the address of the GcRoot<String> in the InternTable for a boot image string. const uint8_t* LookupBootImageInternTableSlot(const DexFile& dex_file, dex::StringIndex string_idx); + // Find the address of the ClassTable::TableSlot for a boot image class. + const uint8_t* LookupBootImageClassTableSlot(const DexFile& dex_file, dex::TypeIndex type_idx); enum class WriteState { kAddingDexFileSources, diff --git a/compiler/optimizing/code_generator_arm64.cc b/compiler/optimizing/code_generator_arm64.cc index 1b628688ec..19e5d067a1 100644 --- a/compiler/optimizing/code_generator_arm64.cc +++ b/compiler/optimizing/code_generator_arm64.cc @@ -21,6 +21,7 @@ #include "art_method.h" #include "base/bit_utils.h" #include "base/bit_utils_iterator.h" +#include "class_table.h" #include "code_generator_utils.h" #include "compiled_method.h" #include "entrypoints/quick/quick_entrypoints.h" @@ -4784,7 +4785,8 @@ void CodeGeneratorARM64::EmitLinkerPatches(ArenaVector<LinkerPatch>* linker_patc linker_patches); } else { DCHECK(pc_relative_method_patches_.empty()); - DCHECK(pc_relative_type_patches_.empty()); + EmitPcRelativeLinkerPatches<LinkerPatch::TypeClassTablePatch>(pc_relative_type_patches_, + linker_patches); EmitPcRelativeLinkerPatches<LinkerPatch::StringInternTablePatch>(pc_relative_string_patches_, linker_patches); } @@ -4861,6 +4863,7 @@ HLoadClass::LoadKind CodeGeneratorARM64::GetSupportedLoadClassKind( case HLoadClass::LoadKind::kReferrersClass: break; case HLoadClass::LoadKind::kBootImageLinkTimePcRelative: + case HLoadClass::LoadKind::kBootImageClassTable: case HLoadClass::LoadKind::kBssEntry: DCHECK(!Runtime::Current()->UseJitCompilation()); break; @@ -4972,6 +4975,25 @@ void InstructionCodeGeneratorARM64::VisitLoadClass(HLoadClass* cls) NO_THREAD_SA __ Ldr(out.W(), codegen_->DeduplicateBootImageAddressLiteral(address)); break; } + case HLoadClass::LoadKind::kBootImageClassTable: { + DCHECK(!codegen_->GetCompilerOptions().IsBootImage()); + // Add ADRP with its PC-relative type patch. + const DexFile& dex_file = cls->GetDexFile(); + dex::TypeIndex type_index = cls->GetTypeIndex(); + vixl::aarch64::Label* adrp_label = codegen_->NewPcRelativeTypePatch(dex_file, type_index); + codegen_->EmitAdrpPlaceholder(adrp_label, out.X()); + // Add LDR with its PC-relative type patch. + vixl::aarch64::Label* ldr_label = + codegen_->NewPcRelativeTypePatch(dex_file, type_index, adrp_label); + codegen_->EmitLdrOffsetPlaceholder(ldr_label, out.W(), out.X()); + // Extract the reference from the slot data, i.e. clear the hash bits. + int32_t masked_hash = ClassTable::TableSlot::MaskHash( + ComputeModifiedUtf8Hash(dex_file.StringByTypeIdx(type_index))); + if (masked_hash != 0) { + __ Sub(out.W(), out.W(), Operand(masked_hash)); + } + break; + } case HLoadClass::LoadKind::kBssEntry: { // Add ADRP with its PC-relative Class .bss entry patch. const DexFile& dex_file = cls->GetDexFile(); diff --git a/compiler/optimizing/code_generator_arm_vixl.cc b/compiler/optimizing/code_generator_arm_vixl.cc index 8288141954..8b9495d564 100644 --- a/compiler/optimizing/code_generator_arm_vixl.cc +++ b/compiler/optimizing/code_generator_arm_vixl.cc @@ -21,6 +21,7 @@ #include "art_method.h" #include "base/bit_utils.h" #include "base/bit_utils_iterator.h" +#include "class_table.h" #include "code_generator_utils.h" #include "common_arm.h" #include "compiled_method.h" @@ -7122,6 +7123,7 @@ HLoadClass::LoadKind CodeGeneratorARMVIXL::GetSupportedLoadClassKind( case HLoadClass::LoadKind::kReferrersClass: break; case HLoadClass::LoadKind::kBootImageLinkTimePcRelative: + case HLoadClass::LoadKind::kBootImageClassTable: case HLoadClass::LoadKind::kBssEntry: DCHECK(!Runtime::Current()->UseJitCompilation()); break; @@ -7234,6 +7236,20 @@ void InstructionCodeGeneratorARMVIXL::VisitLoadClass(HLoadClass* cls) NO_THREAD_ __ Ldr(out, codegen_->DeduplicateBootImageAddressLiteral(address)); break; } + case HLoadClass::LoadKind::kBootImageClassTable: { + DCHECK(!codegen_->GetCompilerOptions().IsBootImage()); + CodeGeneratorARMVIXL::PcRelativePatchInfo* labels = + codegen_->NewPcRelativeTypePatch(cls->GetDexFile(), cls->GetTypeIndex()); + codegen_->EmitMovwMovtPlaceholder(labels, out); + __ Ldr(out, MemOperand(out, /* offset */ 0)); + // Extract the reference from the slot data, i.e. clear the hash bits. + int32_t masked_hash = ClassTable::TableSlot::MaskHash( + ComputeModifiedUtf8Hash(cls->GetDexFile().StringByTypeIdx(cls->GetTypeIndex()))); + if (masked_hash != 0) { + __ Sub(out, out, Operand(masked_hash)); + } + break; + } case HLoadClass::LoadKind::kBssEntry: { vixl32::Register temp = (!kUseReadBarrier || kUseBakerReadBarrier) ? RegisterFrom(locations->GetTemp(0)) @@ -9214,7 +9230,8 @@ void CodeGeneratorARMVIXL::EmitLinkerPatches(ArenaVector<LinkerPatch>* linker_pa linker_patches); } else { DCHECK(pc_relative_method_patches_.empty()); - DCHECK(pc_relative_type_patches_.empty()); + EmitPcRelativeLinkerPatches<LinkerPatch::TypeClassTablePatch>(pc_relative_type_patches_, + linker_patches); EmitPcRelativeLinkerPatches<LinkerPatch::StringInternTablePatch>(pc_relative_string_patches_, linker_patches); } diff --git a/compiler/optimizing/code_generator_mips.cc b/compiler/optimizing/code_generator_mips.cc index ac8f675e2d..f0ef0071b6 100644 --- a/compiler/optimizing/code_generator_mips.cc +++ b/compiler/optimizing/code_generator_mips.cc @@ -20,6 +20,7 @@ #include "arch/mips/entrypoints_direct_mips.h" #include "arch/mips/instruction_set_features_mips.h" #include "art_method.h" +#include "class_table.h" #include "code_generator_utils.h" #include "compiled_method.h" #include "entrypoints/quick/quick_entrypoints.h" @@ -1664,7 +1665,8 @@ void CodeGeneratorMIPS::EmitLinkerPatches(ArenaVector<LinkerPatch>* linker_patch linker_patches); } else { DCHECK(pc_relative_method_patches_.empty()); - DCHECK(pc_relative_type_patches_.empty()); + EmitPcRelativeLinkerPatches<LinkerPatch::TypeClassTablePatch>(pc_relative_type_patches_, + linker_patches); EmitPcRelativeLinkerPatches<LinkerPatch::StringInternTablePatch>(pc_relative_string_patches_, linker_patches); } @@ -7413,6 +7415,7 @@ HLoadClass::LoadKind CodeGeneratorMIPS::GetSupportedLoadClassKind( fallback_load = false; break; case HLoadClass::LoadKind::kBootImageLinkTimePcRelative: + case HLoadClass::LoadKind::kBootImageClassTable: case HLoadClass::LoadKind::kBssEntry: DCHECK(!Runtime::Current()->UseJitCompilation()); break; @@ -7643,6 +7646,7 @@ void LocationsBuilderMIPS::VisitLoadClass(HLoadClass* cls) { // We need an extra register for PC-relative literals on R2. case HLoadClass::LoadKind::kBootImageLinkTimePcRelative: case HLoadClass::LoadKind::kBootImageAddress: + case HLoadClass::LoadKind::kBootImageClassTable: case HLoadClass::LoadKind::kBssEntry: if (isR6) { break; @@ -7741,6 +7745,24 @@ void InstructionCodeGeneratorMIPS::VisitLoadClass(HLoadClass* cls) NO_THREAD_SAF codegen_->DeduplicateBootImageAddressLiteral(address)); break; } + case HLoadClass::LoadKind::kBootImageClassTable: { + DCHECK(!codegen_->GetCompilerOptions().IsBootImage()); + CodeGeneratorMIPS::PcRelativePatchInfo* info_high = + codegen_->NewPcRelativeTypePatch(cls->GetDexFile(), cls->GetTypeIndex()); + CodeGeneratorMIPS::PcRelativePatchInfo* info_low = + codegen_->NewPcRelativeTypePatch(cls->GetDexFile(), cls->GetTypeIndex(), info_high); + codegen_->EmitPcRelativeAddressPlaceholderHigh(info_high, + out, + base_or_current_method_reg); + __ Lw(out, out, /* placeholder */ 0x5678, &info_low->label); + // Extract the reference from the slot data, i.e. clear the hash bits. + int32_t masked_hash = ClassTable::TableSlot::MaskHash( + ComputeModifiedUtf8Hash(cls->GetDexFile().StringByTypeIdx(cls->GetTypeIndex()))); + if (masked_hash != 0) { + __ Addiu(out, out, -masked_hash); + } + break; + } case HLoadClass::LoadKind::kBssEntry: { bss_info_high = codegen_->NewTypeBssEntryPatch(cls->GetDexFile(), cls->GetTypeIndex()); CodeGeneratorMIPS::PcRelativePatchInfo* info_low = diff --git a/compiler/optimizing/code_generator_mips64.cc b/compiler/optimizing/code_generator_mips64.cc index 71c2bfff19..201b1b065f 100644 --- a/compiler/optimizing/code_generator_mips64.cc +++ b/compiler/optimizing/code_generator_mips64.cc @@ -18,6 +18,7 @@ #include "arch/mips64/asm_support_mips64.h" #include "art_method.h" +#include "class_table.h" #include "code_generator_utils.h" #include "compiled_method.h" #include "entrypoints/quick/quick_entrypoints.h" @@ -1573,7 +1574,8 @@ void CodeGeneratorMIPS64::EmitLinkerPatches(ArenaVector<LinkerPatch>* linker_pat linker_patches); } else { DCHECK(pc_relative_method_patches_.empty()); - DCHECK(pc_relative_type_patches_.empty()); + EmitPcRelativeLinkerPatches<LinkerPatch::TypeClassTablePatch>(pc_relative_type_patches_, + linker_patches); EmitPcRelativeLinkerPatches<LinkerPatch::StringInternTablePatch>(pc_relative_string_patches_, linker_patches); } @@ -5767,6 +5769,7 @@ HLoadClass::LoadKind CodeGeneratorMIPS64::GetSupportedLoadClassKind( case HLoadClass::LoadKind::kReferrersClass: break; case HLoadClass::LoadKind::kBootImageLinkTimePcRelative: + case HLoadClass::LoadKind::kBootImageClassTable: case HLoadClass::LoadKind::kBssEntry: DCHECK(!Runtime::Current()->UseJitCompilation()); break; @@ -6016,6 +6019,22 @@ void InstructionCodeGeneratorMIPS64::VisitLoadClass(HLoadClass* cls) NO_THREAD_S codegen_->DeduplicateBootImageAddressLiteral(address)); break; } + case HLoadClass::LoadKind::kBootImageClassTable: { + DCHECK(!codegen_->GetCompilerOptions().IsBootImage()); + CodeGeneratorMIPS64::PcRelativePatchInfo* info_high = + codegen_->NewPcRelativeTypePatch(cls->GetDexFile(), cls->GetTypeIndex()); + CodeGeneratorMIPS64::PcRelativePatchInfo* info_low = + codegen_->NewPcRelativeTypePatch(cls->GetDexFile(), cls->GetTypeIndex(), info_high); + codegen_->EmitPcRelativeAddressPlaceholderHigh(info_high, AT, info_low); + __ Lwu(out, AT, /* placeholder */ 0x5678); + // Extract the reference from the slot data, i.e. clear the hash bits. + int32_t masked_hash = ClassTable::TableSlot::MaskHash( + ComputeModifiedUtf8Hash(cls->GetDexFile().StringByTypeIdx(cls->GetTypeIndex()))); + if (masked_hash != 0) { + __ Daddiu(out, out, -masked_hash); + } + break; + } case HLoadClass::LoadKind::kBssEntry: { bss_info_high = codegen_->NewTypeBssEntryPatch(cls->GetDexFile(), cls->GetTypeIndex()); CodeGeneratorMIPS64::PcRelativePatchInfo* info_low = diff --git a/compiler/optimizing/code_generator_x86.cc b/compiler/optimizing/code_generator_x86.cc index 512968f01d..e45ad0a9a3 100644 --- a/compiler/optimizing/code_generator_x86.cc +++ b/compiler/optimizing/code_generator_x86.cc @@ -17,6 +17,7 @@ #include "code_generator_x86.h" #include "art_method.h" +#include "class_table.h" #include "code_generator_utils.h" #include "compiled_method.h" #include "entrypoints/quick/quick_entrypoints.h" @@ -4702,7 +4703,8 @@ void CodeGeneratorX86::EmitLinkerPatches(ArenaVector<LinkerPatch>* linker_patche EmitPcRelativeLinkerPatches<LinkerPatch::RelativeStringPatch>(string_patches_, linker_patches); } else { DCHECK(boot_image_method_patches_.empty()); - DCHECK(boot_image_type_patches_.empty()); + EmitPcRelativeLinkerPatches<LinkerPatch::TypeClassTablePatch>(boot_image_type_patches_, + linker_patches); EmitPcRelativeLinkerPatches<LinkerPatch::StringInternTablePatch>(string_patches_, linker_patches); } @@ -6038,6 +6040,7 @@ HLoadClass::LoadKind CodeGeneratorX86::GetSupportedLoadClassKind( case HLoadClass::LoadKind::kReferrersClass: break; case HLoadClass::LoadKind::kBootImageLinkTimePcRelative: + case HLoadClass::LoadKind::kBootImageClassTable: case HLoadClass::LoadKind::kBssEntry: DCHECK(!Runtime::Current()->UseJitCompilation()); break; @@ -6075,6 +6078,7 @@ void LocationsBuilderX86::VisitLoadClass(HLoadClass* cls) { if (load_kind == HLoadClass::LoadKind::kReferrersClass || load_kind == HLoadClass::LoadKind::kBootImageLinkTimePcRelative || + load_kind == HLoadClass::LoadKind::kBootImageClassTable || load_kind == HLoadClass::LoadKind::kBssEntry) { locations->SetInAt(0, Location::RequiresRegister()); } @@ -6151,6 +6155,19 @@ void InstructionCodeGeneratorX86::VisitLoadClass(HLoadClass* cls) NO_THREAD_SAFE __ movl(out, Immediate(address)); break; } + case HLoadClass::LoadKind::kBootImageClassTable: { + DCHECK(!codegen_->GetCompilerOptions().IsBootImage()); + Register method_address = locations->InAt(0).AsRegister<Register>(); + __ movl(out, Address(method_address, CodeGeneratorX86::kDummy32BitOffset)); + codegen_->RecordBootTypePatch(cls); + // Extract the reference from the slot data, i.e. clear the hash bits. + int32_t masked_hash = ClassTable::TableSlot::MaskHash( + ComputeModifiedUtf8Hash(cls->GetDexFile().StringByTypeIdx(cls->GetTypeIndex()))); + if (masked_hash != 0) { + __ subl(out, Immediate(masked_hash)); + } + break; + } case HLoadClass::LoadKind::kBssEntry: { Register method_address = locations->InAt(0).AsRegister<Register>(); Address address(method_address, CodeGeneratorX86::kDummy32BitOffset); diff --git a/compiler/optimizing/code_generator_x86_64.cc b/compiler/optimizing/code_generator_x86_64.cc index 0c3b2ad742..8c4374d71e 100644 --- a/compiler/optimizing/code_generator_x86_64.cc +++ b/compiler/optimizing/code_generator_x86_64.cc @@ -17,6 +17,7 @@ #include "code_generator_x86_64.h" #include "art_method.h" +#include "class_table.h" #include "code_generator_utils.h" #include "compiled_method.h" #include "entrypoints/quick/quick_entrypoints.h" @@ -1133,7 +1134,8 @@ void CodeGeneratorX86_64::EmitLinkerPatches(ArenaVector<LinkerPatch>* linker_pat EmitPcRelativeLinkerPatches<LinkerPatch::RelativeStringPatch>(string_patches_, linker_patches); } else { DCHECK(boot_image_method_patches_.empty()); - DCHECK(boot_image_type_patches_.empty()); + EmitPcRelativeLinkerPatches<LinkerPatch::TypeClassTablePatch>(boot_image_type_patches_, + linker_patches); EmitPcRelativeLinkerPatches<LinkerPatch::StringInternTablePatch>(string_patches_, linker_patches); } @@ -5456,6 +5458,7 @@ HLoadClass::LoadKind CodeGeneratorX86_64::GetSupportedLoadClassKind( case HLoadClass::LoadKind::kReferrersClass: break; case HLoadClass::LoadKind::kBootImageLinkTimePcRelative: + case HLoadClass::LoadKind::kBootImageClassTable: case HLoadClass::LoadKind::kBssEntry: DCHECK(!Runtime::Current()->UseJitCompilation()); break; @@ -5564,6 +5567,18 @@ void InstructionCodeGeneratorX86_64::VisitLoadClass(HLoadClass* cls) NO_THREAD_S __ movl(out, Immediate(static_cast<int32_t>(address))); // Zero-extended. break; } + case HLoadClass::LoadKind::kBootImageClassTable: { + DCHECK(!codegen_->GetCompilerOptions().IsBootImage()); + __ movl(out, Address::Absolute(CodeGeneratorX86_64::kDummy32BitOffset, /* no_rip */ false)); + codegen_->RecordBootTypePatch(cls); + // Extract the reference from the slot data, i.e. clear the hash bits. + int32_t masked_hash = ClassTable::TableSlot::MaskHash( + ComputeModifiedUtf8Hash(cls->GetDexFile().StringByTypeIdx(cls->GetTypeIndex()))); + if (masked_hash != 0) { + __ subl(out, Immediate(masked_hash)); + } + break; + } case HLoadClass::LoadKind::kBssEntry: { Address address = Address::Absolute(CodeGeneratorX86_64::kDummy32BitOffset, /* no_rip */ false); diff --git a/compiler/optimizing/nodes.cc b/compiler/optimizing/nodes.cc index ebbea27e08..2a7017c2cb 100644 --- a/compiler/optimizing/nodes.cc +++ b/compiler/optimizing/nodes.cc @@ -2736,6 +2736,7 @@ bool HLoadClass::InstructionDataEquals(const HInstruction* other) const { } switch (GetLoadKind()) { case LoadKind::kBootImageAddress: + case LoadKind::kBootImageClassTable: case LoadKind::kJitTableAddress: { ScopedObjectAccess soa(Thread::Current()); return GetClass().Get() == other_load_class->GetClass().Get(); @@ -2769,6 +2770,8 @@ std::ostream& operator<<(std::ostream& os, HLoadClass::LoadKind rhs) { return os << "BootImageLinkTimePcRelative"; case HLoadClass::LoadKind::kBootImageAddress: return os << "BootImageAddress"; + case HLoadClass::LoadKind::kBootImageClassTable: + return os << "BootImageClassTable"; case HLoadClass::LoadKind::kBssEntry: return os << "BssEntry"; case HLoadClass::LoadKind::kJitTableAddress: diff --git a/compiler/optimizing/nodes.h b/compiler/optimizing/nodes.h index 5e8c77102a..b551f37135 100644 --- a/compiler/optimizing/nodes.h +++ b/compiler/optimizing/nodes.h @@ -5675,6 +5675,10 @@ class HLoadClass FINAL : public HInstruction { // Used for boot image classes referenced by apps in AOT- and JIT-compiled code. kBootImageAddress, + // Use a PC-relative load from a boot image ClassTable mmapped into the .bss + // of the oat file. + kBootImageClassTable, + // 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, @@ -5820,6 +5824,7 @@ class HLoadClass FINAL : public HInstruction { static bool HasTypeReference(LoadKind load_kind) { return load_kind == LoadKind::kReferrersClass || load_kind == LoadKind::kBootImageLinkTimePcRelative || + load_kind == LoadKind::kBootImageClassTable || load_kind == LoadKind::kBssEntry || load_kind == LoadKind::kRuntimeCall; } @@ -5853,6 +5858,7 @@ inline void HLoadClass::AddSpecialInput(HInstruction* special_input) { // including literal pool loads, which are PC-relative too. DCHECK(GetLoadKind() == LoadKind::kBootImageLinkTimePcRelative || GetLoadKind() == LoadKind::kBootImageAddress || + GetLoadKind() == LoadKind::kBootImageClassTable || GetLoadKind() == LoadKind::kBssEntry) << GetLoadKind(); DCHECK(special_input_.GetInstruction() == nullptr); special_input_ = HUserRecord<HInstruction*>(special_input); diff --git a/compiler/optimizing/pc_relative_fixups_mips.cc b/compiler/optimizing/pc_relative_fixups_mips.cc index 4cb99f9b5c..e569b78c9d 100644 --- a/compiler/optimizing/pc_relative_fixups_mips.cc +++ b/compiler/optimizing/pc_relative_fixups_mips.cc @@ -75,6 +75,7 @@ class PCRelativeHandlerVisitor : public HGraphVisitor { switch (load_kind) { case HLoadClass::LoadKind::kBootImageLinkTimePcRelative: case HLoadClass::LoadKind::kBootImageAddress: + case HLoadClass::LoadKind::kBootImageClassTable: case HLoadClass::LoadKind::kBssEntry: // Add a base register for PC-relative literals on R2. InitializePCRelativeBasePointer(); diff --git a/compiler/optimizing/pc_relative_fixups_x86.cc b/compiler/optimizing/pc_relative_fixups_x86.cc index c463ecdb0a..9877e10474 100644 --- a/compiler/optimizing/pc_relative_fixups_x86.cc +++ b/compiler/optimizing/pc_relative_fixups_x86.cc @@ -83,6 +83,7 @@ class PCRelativeHandlerVisitor : public HGraphVisitor { void VisitLoadClass(HLoadClass* load_class) OVERRIDE { HLoadClass::LoadKind load_kind = load_class->GetLoadKind(); if (load_kind == HLoadClass::LoadKind::kBootImageLinkTimePcRelative || + load_kind == HLoadClass::LoadKind::kBootImageClassTable || load_kind == HLoadClass::LoadKind::kBssEntry) { HX86ComputeBaseMethodAddress* method_address = GetPCRelativeBasePointer(load_class); load_class->AddSpecialInput(method_address); diff --git a/compiler/optimizing/sharpening.cc b/compiler/optimizing/sharpening.cc index 1ca63f4f86..e46c9a7081 100644 --- a/compiler/optimizing/sharpening.cc +++ b/compiler/optimizing/sharpening.cc @@ -205,11 +205,15 @@ HLoadClass::LoadKind HSharpening::ComputeLoadClassKind(HLoadClass* load_class, // TODO(ngeoffray): Generate HDeoptimize instead. desired_load_kind = HLoadClass::LoadKind::kRuntimeCall; } - } else if (is_in_boot_image && !codegen->GetCompilerOptions().GetCompilePic()) { - // AOT app compilation. Check if the class is in the boot image. - desired_load_kind = HLoadClass::LoadKind::kBootImageAddress; + } else if (is_in_boot_image) { + // AOT app compilation, boot image class. + if (codegen->GetCompilerOptions().GetCompilePic()) { + desired_load_kind = HLoadClass::LoadKind::kBootImageClassTable; + } else { + desired_load_kind = HLoadClass::LoadKind::kBootImageAddress; + } } else { - // Not JIT and either the klass is not in boot image or we are compiling in PIC mode. + // Not JIT and the klass is not in boot image. desired_load_kind = HLoadClass::LoadKind::kBssEntry; } } diff --git a/runtime/class_linker.h b/runtime/class_linker.h index 8c2f0a5064..9727adff44 100644 --- a/runtime/class_linker.h +++ b/runtime/class_linker.h @@ -1278,7 +1278,7 @@ class ClassLinker { friend class ImageWriter; // for GetClassRoots friend class JniCompilerTest; // for GetRuntimeQuickGenericJniStub friend class JniInternalTest; // for GetRuntimeQuickGenericJniStub - friend class OatWriter; // for boot image string table slot address lookup. + friend class OatWriter; // for boot image string/class table slot address lookup. friend class VMClassLoader; // for LookupClass and FindClassInBaseDexClassLoader. ART_FRIEND_TEST(ClassLinkerTest, RegisterDexFileName); // for DexLock, and RegisterDexFileLocked ART_FRIEND_TEST(mirror::DexCacheMethodHandlesTest, Open); // for AllocDexCache diff --git a/runtime/class_table.h b/runtime/class_table.h index a259725399..0ffe93e051 100644 --- a/runtime/class_table.h +++ b/runtime/class_table.h @@ -287,6 +287,7 @@ class ClassTable { std::vector<const OatFile*> oat_files_ GUARDED_BY(lock_); friend class ImageWriter; // for InsertWithoutLocks. + friend class OatWriter; // for boot class TableSlot address lookup. }; } // namespace art diff --git a/test/552-checker-sharpening/src/Main.java b/test/552-checker-sharpening/src/Main.java index 7a60bb5cc0..1f1920ca15 100644 --- a/test/552-checker-sharpening/src/Main.java +++ b/test/552-checker-sharpening/src/Main.java @@ -277,27 +277,27 @@ public class Main { /// CHECK-START-X86: java.lang.Class Main.$noinline$getStringClass() sharpening (after) // Note: load kind depends on PIC/non-PIC - /// CHECK: LoadClass load_kind:{{BootImageAddress|BssEntry}} class_name:java.lang.String + /// CHECK: LoadClass load_kind:{{BootImageAddress|BootImageClassTable}} class_name:java.lang.String /// CHECK-START-X86_64: java.lang.Class Main.$noinline$getStringClass() sharpening (after) // Note: load kind depends on PIC/non-PIC - /// CHECK: LoadClass load_kind:{{BootImageAddress|BssEntry}} class_name:java.lang.String + /// CHECK: LoadClass load_kind:{{BootImageAddress|BootImageClassTable}} class_name:java.lang.String /// CHECK-START-ARM: java.lang.Class Main.$noinline$getStringClass() sharpening (after) // Note: load kind depends on PIC/non-PIC - /// CHECK: LoadClass load_kind:{{BootImageAddress|BssEntry}} class_name:java.lang.String + /// CHECK: LoadClass load_kind:{{BootImageAddress|BootImageClassTable}} class_name:java.lang.String /// CHECK-START-ARM64: java.lang.Class Main.$noinline$getStringClass() sharpening (after) // Note: load kind depends on PIC/non-PIC - /// CHECK: LoadClass load_kind:{{BootImageAddress|BssEntry}} class_name:java.lang.String + /// CHECK: LoadClass load_kind:{{BootImageAddress|BootImageClassTable}} class_name:java.lang.String /// CHECK-START-MIPS: java.lang.Class Main.$noinline$getStringClass() sharpening (after) // Note: load kind depends on PIC/non-PIC - /// CHECK: LoadClass load_kind:{{BootImageAddress|BssEntry}} class_name:java.lang.String + /// CHECK: LoadClass load_kind:{{BootImageAddress|BootImageClassTable}} class_name:java.lang.String /// CHECK-START-MIPS64: java.lang.Class Main.$noinline$getStringClass() sharpening (after) // Note: load kind depends on PIC/non-PIC - /// CHECK: LoadClass load_kind:{{BootImageAddress|BssEntry}} class_name:java.lang.String + /// CHECK: LoadClass load_kind:{{BootImageAddress|BootImageClassTable}} class_name:java.lang.String public static Class<?> $noinline$getStringClass() { // Prevent inlining to avoid the string comparison being optimized away. |