diff options
author | 2022-03-08 16:43:54 +0000 | |
---|---|---|
committer | 2022-03-09 14:13:53 +0000 | |
commit | 69a87e30730d0c6e6e5974fd2bd001f77fffed5e (patch) | |
tree | dd4ee9fddd6eb68b56c3a808ce26e0ddba9fe0fe | |
parent | cf414b24f4097593cb68da8e0dc52d956724b4fa (diff) |
Revert^4 "Add bss support for inlining BCP DexFiles for single image"
This reverts commit 1849c3a875aab44d9bff45623ec076b0331302f8.
Reason for revert: Relading after fix. It can be seen in PS 1..2
Bug: 154012332
Test: art/test/testrunner/testrunner.py --target --32 --optimizing
Test: art/test/testrunner/testrunner.py --host --64 --optimizing
Change-Id: I168572957363dd5ae1598279f2ecc8fb947a1fd5
-rw-r--r-- | compiler/optimizing/code_generator_arm64.cc | 4 | ||||
-rw-r--r-- | compiler/optimizing/code_generator_arm_vixl.cc | 4 | ||||
-rw-r--r-- | compiler/optimizing/code_generator_x86.cc | 8 | ||||
-rw-r--r-- | compiler/optimizing/code_generator_x86_64.cc | 8 | ||||
-rw-r--r-- | compiler/optimizing/inliner.cc | 11 | ||||
-rw-r--r-- | dex2oat/linker/oat_writer.cc | 519 | ||||
-rw-r--r-- | dex2oat/linker/oat_writer.h | 34 | ||||
-rw-r--r-- | dex2oat/linker/oat_writer_test.cc | 2 | ||||
-rw-r--r-- | oatdump/oatdump.cc | 143 | ||||
-rw-r--r-- | runtime/entrypoints/entrypoint_utils.cc | 51 | ||||
-rw-r--r-- | runtime/entrypoints/entrypoint_utils.h | 11 | ||||
-rw-r--r-- | runtime/entrypoints/jni/jni_entrypoints.cc | 4 | ||||
-rw-r--r-- | runtime/entrypoints/quick/quick_dexcache_entrypoints.cc | 141 | ||||
-rw-r--r-- | runtime/entrypoints/quick/quick_trampoline_entrypoints.cc | 7 | ||||
-rw-r--r-- | runtime/oat.cc | 17 | ||||
-rw-r--r-- | runtime/oat.h | 7 | ||||
-rw-r--r-- | runtime/oat_file-inl.h | 15 | ||||
-rw-r--r-- | runtime/oat_file.cc | 79 | ||||
-rw-r--r-- | runtime/oat_file.h | 18 |
19 files changed, 811 insertions, 272 deletions
diff --git a/compiler/optimizing/code_generator_arm64.cc b/compiler/optimizing/code_generator_arm64.cc index fc1c07dcbb..76d2a6d3f2 100644 --- a/compiler/optimizing/code_generator_arm64.cc +++ b/compiler/optimizing/code_generator_arm64.cc @@ -283,7 +283,9 @@ class LoadClassSlowPathARM64 : public SlowPathCodeARM64 { InvokeRuntimeCallingConvention calling_convention; if (must_resolve_type) { DCHECK(IsSameDexFile(cls_->GetDexFile(), arm64_codegen->GetGraph()->GetDexFile()) || - arm64_codegen->GetCompilerOptions().WithinOatFile(&cls_->GetDexFile())); + arm64_codegen->GetCompilerOptions().WithinOatFile(&cls_->GetDexFile()) || + ContainsElement(Runtime::Current()->GetClassLinker()->GetBootClassPath(), + &cls_->GetDexFile())); dex::TypeIndex type_index = cls_->GetTypeIndex(); __ Mov(calling_convention.GetRegisterAt(0).W(), type_index.index_); if (cls_->NeedsAccessCheck()) { diff --git a/compiler/optimizing/code_generator_arm_vixl.cc b/compiler/optimizing/code_generator_arm_vixl.cc index f65890bcb8..1c243b635e 100644 --- a/compiler/optimizing/code_generator_arm_vixl.cc +++ b/compiler/optimizing/code_generator_arm_vixl.cc @@ -531,7 +531,9 @@ class LoadClassSlowPathARMVIXL : public SlowPathCodeARMVIXL { InvokeRuntimeCallingConventionARMVIXL calling_convention; if (must_resolve_type) { DCHECK(IsSameDexFile(cls_->GetDexFile(), arm_codegen->GetGraph()->GetDexFile()) || - arm_codegen->GetCompilerOptions().WithinOatFile(&cls_->GetDexFile())); + arm_codegen->GetCompilerOptions().WithinOatFile(&cls_->GetDexFile()) || + ContainsElement(Runtime::Current()->GetClassLinker()->GetBootClassPath(), + &cls_->GetDexFile())); dex::TypeIndex type_index = cls_->GetTypeIndex(); __ Mov(calling_convention.GetRegisterAt(0), type_index.index_); if (cls_->NeedsAccessCheck()) { diff --git a/compiler/optimizing/code_generator_x86.cc b/compiler/optimizing/code_generator_x86.cc index 0efd51cedf..4025684bda 100644 --- a/compiler/optimizing/code_generator_x86.cc +++ b/compiler/optimizing/code_generator_x86.cc @@ -290,7 +290,9 @@ class LoadClassSlowPathX86 : public SlowPathCode { InvokeRuntimeCallingConvention calling_convention; if (must_resolve_type) { DCHECK(IsSameDexFile(cls_->GetDexFile(), x86_codegen->GetGraph()->GetDexFile()) || - x86_codegen->GetCompilerOptions().WithinOatFile(&cls_->GetDexFile())); + x86_codegen->GetCompilerOptions().WithinOatFile(&cls_->GetDexFile()) || + ContainsElement(Runtime::Current()->GetClassLinker()->GetBootClassPath(), + &cls_->GetDexFile())); dex::TypeIndex type_index = cls_->GetTypeIndex(); __ movl(calling_convention.GetRegisterAt(0), Immediate(type_index.index_)); if (cls_->NeedsAccessCheck()) { @@ -5474,7 +5476,9 @@ void CodeGeneratorX86::RecordMethodBssEntryPatch(HInvoke* invoke) { ? invoke->AsInvokeInterface()->GetSpecialInputIndex() : invoke->AsInvokeStaticOrDirect()->GetSpecialInputIndex(); DCHECK(IsSameDexFile(GetGraph()->GetDexFile(), *invoke->GetMethodReference().dex_file) || - GetCompilerOptions().WithinOatFile(invoke->GetMethodReference().dex_file)); + GetCompilerOptions().WithinOatFile(invoke->GetMethodReference().dex_file) || + ContainsElement(Runtime::Current()->GetClassLinker()->GetBootClassPath(), + invoke->GetMethodReference().dex_file)); HX86ComputeBaseMethodAddress* method_address = invoke->InputAt(index)->AsX86ComputeBaseMethodAddress(); // Add the patch entry and bind its label at the end of the instruction. diff --git a/compiler/optimizing/code_generator_x86_64.cc b/compiler/optimizing/code_generator_x86_64.cc index ff4ab59760..8c1a533fd3 100644 --- a/compiler/optimizing/code_generator_x86_64.cc +++ b/compiler/optimizing/code_generator_x86_64.cc @@ -274,7 +274,9 @@ class LoadClassSlowPathX86_64 : public SlowPathCode { // Custom calling convention: RAX serves as both input and output. if (must_resolve_type) { DCHECK(IsSameDexFile(cls_->GetDexFile(), x86_64_codegen->GetGraph()->GetDexFile()) || - x86_64_codegen->GetCompilerOptions().WithinOatFile(&cls_->GetDexFile())); + x86_64_codegen->GetCompilerOptions().WithinOatFile(&cls_->GetDexFile()) || + ContainsElement(Runtime::Current()->GetClassLinker()->GetBootClassPath(), + &cls_->GetDexFile())); dex::TypeIndex type_index = cls_->GetTypeIndex(); __ movl(CpuRegister(RAX), Immediate(type_index.index_)); if (cls_->NeedsAccessCheck()) { @@ -1241,7 +1243,9 @@ void CodeGeneratorX86_64::RecordBootImageMethodPatch(HInvoke* invoke) { void CodeGeneratorX86_64::RecordMethodBssEntryPatch(HInvoke* invoke) { DCHECK(IsSameDexFile(GetGraph()->GetDexFile(), *invoke->GetMethodReference().dex_file) || - GetCompilerOptions().WithinOatFile(invoke->GetMethodReference().dex_file)); + GetCompilerOptions().WithinOatFile(invoke->GetMethodReference().dex_file) || + ContainsElement(Runtime::Current()->GetClassLinker()->GetBootClassPath(), + invoke->GetMethodReference().dex_file)); method_bss_entry_patches_.emplace_back(invoke->GetMethodReference().dex_file, invoke->GetMethodReference().index); __ Bind(&method_bss_entry_patches_.back().label); diff --git a/compiler/optimizing/inliner.cc b/compiler/optimizing/inliner.cc index 39f684b895..741e6dffc1 100644 --- a/compiler/optimizing/inliner.cc +++ b/compiler/optimizing/inliner.cc @@ -1745,11 +1745,12 @@ static bool CanEncodeInlinedMethodInStackMap(const DexFile& outer_dex_file, // Inline across dexfiles if the callee's DexFile is: // 1) in the bootclasspath, or if (callee->GetDeclaringClass()->GetClassLoader() == nullptr) { - // There are cases in which the BCP DexFiles are within the OatFile as far as the compiler - // options are concerned, but they have their own OatWriter (and therefore not in the same - // OatFile). Then, we request the BSS check for all BCP DexFiles. - // TODO(solanes): Add .bss support for BCP. - *out_needs_bss_check = true; + // In multi-image, each BCP DexFile has their own OatWriter. Since they don't cooperate with + // each other, we request the BSS check for them. + // TODO(solanes): Add .bss support for BCP multi-image. + const bool is_multi_image = codegen->GetCompilerOptions().IsBootImage() || + codegen->GetCompilerOptions().IsBootImageExtension(); + *out_needs_bss_check = is_multi_image; return true; } diff --git a/dex2oat/linker/oat_writer.cc b/dex2oat/linker/oat_writer.cc index 7c7318720d..55cee6db0a 100644 --- a/dex2oat/linker/oat_writer.cc +++ b/dex2oat/linker/oat_writer.cc @@ -470,6 +470,12 @@ OatWriter::OatWriter(const CompilerOptions& compiler_options, size_oat_dex_file_public_type_bss_mapping_offset_(0), size_oat_dex_file_package_type_bss_mapping_offset_(0), size_oat_dex_file_string_bss_mapping_offset_(0), + size_bcp_bss_info_size_(0), + size_bcp_bss_info_method_bss_mapping_offset_(0), + size_bcp_bss_info_type_bss_mapping_offset_(0), + size_bcp_bss_info_public_type_bss_mapping_offset_(0), + size_bcp_bss_info_package_type_bss_mapping_offset_(0), + size_bcp_bss_info_string_bss_mapping_offset_(0), size_oat_class_offsets_alignment_(0), size_oat_class_offsets_(0), size_oat_class_type_(0), @@ -790,6 +796,10 @@ void OatWriter::PrepareLayout(MultiOatRelativePatcher* relative_patcher) { offset = InitOatDexFiles(offset); } { + TimingLogger::ScopedTiming split("InitBcpBssInfo", timings_); + offset = InitBcpBssInfo(offset); + } + { TimingLogger::ScopedTiming split("InitOatCode", timings_); offset = InitOatCode(offset); } @@ -944,10 +954,8 @@ class OatWriter::InitBssLayoutMethodVisitor : public DexMethodVisitor { void AddBssReference(const DexFileReference& ref, size_t number_of_indexes, /*inout*/ SafeMap<const DexFile*, BitVector>* references) { - // We currently support inlining of throwing instructions only when they originate in the - // same oat file as the outer method. All .bss references are used by throwing instructions. - DCHECK(std::find(writer_->dex_files_->begin(), writer_->dex_files_->end(), ref.dex_file) != - writer_->dex_files_->end()); + DCHECK(ContainsElement(*writer_->dex_files_, ref.dex_file) || + ContainsElement(Runtime::Current()->GetClassLinker()->GetBootClassPath(), ref.dex_file)); DCHECK_LT(ref.index, number_of_indexes); auto refs_it = references->find(ref.dex_file); @@ -1045,6 +1053,29 @@ class OatWriter::InitOatClassesMethodVisitor : public DexMethodVisitor { size_t compiled_methods_with_code_; }; +// .bss mapping offsets used for BCP DexFiles. +struct OatWriter::BssMappingInfo { + // Offsets set in PrepareLayout. + uint32_t method_bss_mapping_offset = 0u; + uint32_t type_bss_mapping_offset = 0u; + uint32_t public_type_bss_mapping_offset = 0u; + uint32_t package_type_bss_mapping_offset = 0u; + uint32_t string_bss_mapping_offset = 0u; + + // Offset of the BSSInfo start from beginning of OatHeader. It is used to validate file position + // when writing. + size_t offset_ = 0u; + + static size_t SizeOf() { + return sizeof(method_bss_mapping_offset) + + sizeof(type_bss_mapping_offset) + + sizeof(public_type_bss_mapping_offset) + + sizeof(package_type_bss_mapping_offset) + + sizeof(string_bss_mapping_offset); + } + bool Write(OatWriter* oat_writer, OutputStream* out) const; +}; + // CompiledMethod + metadata required to do ordered method layout. // // See also OrderedMethodVisitor. @@ -2184,67 +2215,123 @@ size_t OatWriter::InitIndexBssMappings(size_t offset) { size_t number_of_public_type_dex_files = 0u; size_t number_of_package_type_dex_files = 0u; size_t number_of_string_dex_files = 0u; - PointerSize pointer_size = GetInstructionSetPointerSize(oat_header_->GetInstructionSet()); for (size_t i = 0, size = dex_files_->size(); i != size; ++i) { const DexFile* dex_file = (*dex_files_)[i]; - auto method_it = bss_method_entry_references_.find(dex_file); - if (method_it != bss_method_entry_references_.end()) { - const BitVector& method_indexes = method_it->second; - ++number_of_method_dex_files; - oat_dex_files_[i].method_bss_mapping_offset_ = offset; - offset += CalculateIndexBssMappingSize( - dex_file->NumMethodIds(), - static_cast<size_t>(pointer_size), - method_indexes, - [=](uint32_t index) { - return bss_method_entries_.Get({dex_file, index}); - }); - } - - auto type_it = bss_type_entry_references_.find(dex_file); - if (type_it != bss_type_entry_references_.end()) { - const BitVector& type_indexes = type_it->second; - ++number_of_type_dex_files; - oat_dex_files_[i].type_bss_mapping_offset_ = offset; - offset += CalculateIndexBssMappingSize(dex_file, type_indexes, bss_type_entries_); - } - - auto public_type_it = bss_public_type_entry_references_.find(dex_file); - if (public_type_it != bss_public_type_entry_references_.end()) { - const BitVector& type_indexes = public_type_it->second; - ++number_of_public_type_dex_files; - oat_dex_files_[i].public_type_bss_mapping_offset_ = offset; - offset += CalculateIndexBssMappingSize(dex_file, type_indexes, bss_public_type_entries_); - } - - auto package_type_it = bss_package_type_entry_references_.find(dex_file); - if (package_type_it != bss_package_type_entry_references_.end()) { - const BitVector& type_indexes = package_type_it->second; - ++number_of_package_type_dex_files; - oat_dex_files_[i].package_type_bss_mapping_offset_ = offset; - offset += CalculateIndexBssMappingSize(dex_file, type_indexes, bss_package_type_entries_); - } - - auto string_it = bss_string_entry_references_.find(dex_file); - if (string_it != bss_string_entry_references_.end()) { - const BitVector& string_indexes = string_it->second; - ++number_of_string_dex_files; - oat_dex_files_[i].string_bss_mapping_offset_ = offset; - offset += CalculateIndexBssMappingSize( - dex_file->NumStringIds(), - sizeof(GcRoot<mirror::String>), - string_indexes, - [=](uint32_t index) { - return bss_string_entries_.Get({dex_file, dex::StringIndex(index)}); - }); + offset = InitIndexBssMappingsHelper(offset, + dex_file, + number_of_method_dex_files, + number_of_type_dex_files, + number_of_public_type_dex_files, + number_of_package_type_dex_files, + number_of_string_dex_files, + oat_dex_files_[i].method_bss_mapping_offset_, + oat_dex_files_[i].type_bss_mapping_offset_, + oat_dex_files_[i].public_type_bss_mapping_offset_, + oat_dex_files_[i].package_type_bss_mapping_offset_, + oat_dex_files_[i].string_bss_mapping_offset_); + } + + if (!(compiler_options_.IsBootImage() || compiler_options_.IsBootImageExtension())) { + ArrayRef<const DexFile* const> boot_class_path( + Runtime::Current()->GetClassLinker()->GetBootClassPath()); + // We initialize bcp_bss_info for single image and purposively leave it empty for the multi + // image case. + // Note that we have an early break at the beginning of the method, so `bcp_bss_info_` will also + // be empty in the case of having no mappings at all. + DCHECK(bcp_bss_info_.empty()); + bcp_bss_info_.resize(boot_class_path.size()); + for (size_t i = 0, size = bcp_bss_info_.size(); i != size; ++i) { + const DexFile* dex_file = boot_class_path[i]; + DCHECK(!ContainsElement(*dex_files_, dex_file)); + offset = InitIndexBssMappingsHelper(offset, + dex_file, + number_of_method_dex_files, + number_of_type_dex_files, + number_of_public_type_dex_files, + number_of_package_type_dex_files, + number_of_string_dex_files, + bcp_bss_info_[i].method_bss_mapping_offset, + bcp_bss_info_[i].type_bss_mapping_offset, + bcp_bss_info_[i].public_type_bss_mapping_offset, + bcp_bss_info_[i].package_type_bss_mapping_offset, + bcp_bss_info_[i].string_bss_mapping_offset); } } - // Check that all dex files targeted by bss entries are in `*dex_files_`. + + // Check that all dex files targeted by bss entries are in `*dex_files_`, or in the bootclaspath's + // DexFiles in the single image case. CHECK_EQ(number_of_method_dex_files, bss_method_entry_references_.size()); CHECK_EQ(number_of_type_dex_files, bss_type_entry_references_.size()); CHECK_EQ(number_of_public_type_dex_files, bss_public_type_entry_references_.size()); CHECK_EQ(number_of_package_type_dex_files, bss_package_type_entry_references_.size()); CHECK_EQ(number_of_string_dex_files, bss_string_entry_references_.size()); + + return offset; +} + +size_t OatWriter::InitIndexBssMappingsHelper(size_t offset, + const DexFile* dex_file, + /*inout*/ size_t& number_of_method_dex_files, + /*inout*/ size_t& number_of_type_dex_files, + /*inout*/ size_t& number_of_public_type_dex_files, + /*inout*/ size_t& number_of_package_type_dex_files, + /*inout*/ size_t& number_of_string_dex_files, + /*inout*/ uint32_t& method_bss_mapping_offset, + /*inout*/ uint32_t& type_bss_mapping_offset, + /*inout*/ uint32_t& public_type_bss_mapping_offset, + /*inout*/ uint32_t& package_type_bss_mapping_offset, + /*inout*/ uint32_t& string_bss_mapping_offset) { + const PointerSize pointer_size = GetInstructionSetPointerSize(oat_header_->GetInstructionSet()); + auto method_it = bss_method_entry_references_.find(dex_file); + if (method_it != bss_method_entry_references_.end()) { + const BitVector& method_indexes = method_it->second; + ++number_of_method_dex_files; + method_bss_mapping_offset = offset; + offset += CalculateIndexBssMappingSize(dex_file->NumMethodIds(), + static_cast<size_t>(pointer_size), + method_indexes, + [=](uint32_t index) { + return bss_method_entries_.Get({dex_file, index}); + }); + } + + auto type_it = bss_type_entry_references_.find(dex_file); + if (type_it != bss_type_entry_references_.end()) { + const BitVector& type_indexes = type_it->second; + ++number_of_type_dex_files; + type_bss_mapping_offset = offset; + offset += CalculateIndexBssMappingSize(dex_file, type_indexes, bss_type_entries_); + } + + auto public_type_it = bss_public_type_entry_references_.find(dex_file); + if (public_type_it != bss_public_type_entry_references_.end()) { + const BitVector& type_indexes = public_type_it->second; + ++number_of_public_type_dex_files; + public_type_bss_mapping_offset = offset; + offset += CalculateIndexBssMappingSize(dex_file, type_indexes, bss_public_type_entries_); + } + + auto package_type_it = bss_package_type_entry_references_.find(dex_file); + if (package_type_it != bss_package_type_entry_references_.end()) { + const BitVector& type_indexes = package_type_it->second; + ++number_of_package_type_dex_files; + package_type_bss_mapping_offset = offset; + offset += CalculateIndexBssMappingSize(dex_file, type_indexes, bss_package_type_entries_); + } + + auto string_it = bss_string_entry_references_.find(dex_file); + if (string_it != bss_string_entry_references_.end()) { + const BitVector& string_indexes = string_it->second; + ++number_of_string_dex_files; + string_bss_mapping_offset = offset; + offset += CalculateIndexBssMappingSize( + dex_file->NumStringIds(), + sizeof(GcRoot<mirror::String>), + string_indexes, + [=](uint32_t index) { + return bss_string_entries_.Get({dex_file, dex::StringIndex(index)}); + }); + } return offset; } @@ -2257,6 +2344,23 @@ size_t OatWriter::InitOatDexFiles(size_t offset) { return offset; } +size_t OatWriter::InitBcpBssInfo(size_t offset) { + if (bcp_bss_info_.size() == 0) { + return offset; + } + + // We first increase the offset to make room to store the number of BCP DexFiles, if we have at + // least one entry. + oat_header_->SetBcpBssInfoOffset(offset); + offset += sizeof(uint32_t); + + for (BssMappingInfo& info : bcp_bss_info_) { + info.offset_ = offset; + offset += BssMappingInfo::SizeOf(); + } + return offset; +} + size_t OatWriter::InitOatCode(size_t offset) { // calculate the offsets within OatHeader to executable code size_t old_offset = offset; @@ -2487,6 +2591,12 @@ bool OatWriter::WriteRodata(OutputStream* out) { return false; } + relative_offset = WriteBcpBssInfo(out, file_offset, relative_offset); + if (relative_offset == 0) { + PLOG(ERROR) << "Failed to write BCP bss information to " << out->GetLocation(); + return false; + } + // Write padding. off_t new_offset = out->Seek(size_executable_offset_alignment_, kSeekCurrent); relative_offset += size_executable_offset_alignment_; @@ -2660,6 +2770,12 @@ bool OatWriter::CheckOatSize(OutputStream* out, size_t file_offset, size_t relat DO_STAT(size_oat_dex_file_public_type_bss_mapping_offset_); DO_STAT(size_oat_dex_file_package_type_bss_mapping_offset_); DO_STAT(size_oat_dex_file_string_bss_mapping_offset_); + DO_STAT(size_bcp_bss_info_size_); + DO_STAT(size_bcp_bss_info_method_bss_mapping_offset_); + DO_STAT(size_bcp_bss_info_type_bss_mapping_offset_); + DO_STAT(size_bcp_bss_info_public_type_bss_mapping_offset_); + DO_STAT(size_bcp_bss_info_package_type_bss_mapping_offset_); + DO_STAT(size_bcp_bss_info_string_bss_mapping_offset_); DO_STAT(size_oat_class_offsets_alignment_); DO_STAT(size_oat_class_offsets_); DO_STAT(size_oat_class_type_); @@ -2849,6 +2965,111 @@ size_t WriteIndexBssMapping( [=](uint32_t index) { return bss_entries.Get({dex_file, dex::TypeIndex(index)}); }); } +size_t OatWriter::WriteIndexBssMappingsHelper(OutputStream* out, + size_t file_offset, + size_t relative_offset, + const DexFile* dex_file, + uint32_t method_bss_mapping_offset, + uint32_t type_bss_mapping_offset, + uint32_t public_type_bss_mapping_offset, + uint32_t package_type_bss_mapping_offset, + uint32_t string_bss_mapping_offset) { + const PointerSize pointer_size = GetInstructionSetPointerSize(oat_header_->GetInstructionSet()); + auto method_it = bss_method_entry_references_.find(dex_file); + if (method_it != bss_method_entry_references_.end()) { + const BitVector& method_indexes = method_it->second; + DCHECK_EQ(relative_offset, method_bss_mapping_offset); + DCHECK_OFFSET(); + size_t method_mappings_size = + WriteIndexBssMapping(out, + dex_file->NumMethodIds(), + static_cast<size_t>(pointer_size), + method_indexes, + [=](uint32_t index) { + return bss_method_entries_.Get({dex_file, index}); + }); + if (method_mappings_size == 0u) { + return 0u; + } + size_method_bss_mappings_ += method_mappings_size; + relative_offset += method_mappings_size; + } else { + DCHECK_EQ(0u, method_bss_mapping_offset); + } + + auto type_it = bss_type_entry_references_.find(dex_file); + if (type_it != bss_type_entry_references_.end()) { + const BitVector& type_indexes = type_it->second; + DCHECK_EQ(relative_offset, type_bss_mapping_offset); + DCHECK_OFFSET(); + size_t type_mappings_size = + WriteIndexBssMapping(out, dex_file, type_indexes, bss_type_entries_); + if (type_mappings_size == 0u) { + return 0u; + } + size_type_bss_mappings_ += type_mappings_size; + relative_offset += type_mappings_size; + } else { + DCHECK_EQ(0u, type_bss_mapping_offset); + } + + auto public_type_it = bss_public_type_entry_references_.find(dex_file); + if (public_type_it != bss_public_type_entry_references_.end()) { + const BitVector& type_indexes = public_type_it->second; + DCHECK_EQ(relative_offset, public_type_bss_mapping_offset); + DCHECK_OFFSET(); + size_t public_type_mappings_size = + WriteIndexBssMapping(out, dex_file, type_indexes, bss_public_type_entries_); + if (public_type_mappings_size == 0u) { + return 0u; + } + size_public_type_bss_mappings_ += public_type_mappings_size; + relative_offset += public_type_mappings_size; + } else { + DCHECK_EQ(0u, public_type_bss_mapping_offset); + } + + auto package_type_it = bss_package_type_entry_references_.find(dex_file); + if (package_type_it != bss_package_type_entry_references_.end()) { + const BitVector& type_indexes = package_type_it->second; + DCHECK_EQ(relative_offset, package_type_bss_mapping_offset); + DCHECK_OFFSET(); + size_t package_type_mappings_size = + WriteIndexBssMapping(out, dex_file, type_indexes, bss_package_type_entries_); + if (package_type_mappings_size == 0u) { + return 0u; + } + size_package_type_bss_mappings_ += package_type_mappings_size; + relative_offset += package_type_mappings_size; + } else { + DCHECK_EQ(0u, package_type_bss_mapping_offset); + } + + auto string_it = bss_string_entry_references_.find(dex_file); + if (string_it != bss_string_entry_references_.end()) { + const BitVector& string_indexes = string_it->second; + DCHECK_EQ(relative_offset, string_bss_mapping_offset); + DCHECK_OFFSET(); + size_t string_mappings_size = + WriteIndexBssMapping(out, + dex_file->NumStringIds(), + sizeof(GcRoot<mirror::String>), + string_indexes, + [=](uint32_t index) { + return bss_string_entries_.Get({dex_file, dex::StringIndex(index)}); + }); + if (string_mappings_size == 0u) { + return 0u; + } + size_string_bss_mappings_ += string_mappings_size; + relative_offset += string_mappings_size; + } else { + DCHECK_EQ(0u, string_bss_mapping_offset); + } + + return relative_offset; +} + size_t OatWriter::WriteIndexBssMappings(OutputStream* out, size_t file_offset, size_t relative_offset) { @@ -2862,104 +3083,45 @@ size_t OatWriter::WriteIndexBssMappings(OutputStream* out, } // 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(IndexBssMapping) == sizeof(uint32_t), - "IndexBssMapping alignment check."); + static_assert(alignof(IndexBssMapping) == sizeof(uint32_t), "IndexBssMapping alignment check."); DCHECK_ALIGNED(relative_offset, sizeof(uint32_t)); - PointerSize pointer_size = GetInstructionSetPointerSize(oat_header_->GetInstructionSet()); 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 method_it = bss_method_entry_references_.find(dex_file); - if (method_it != bss_method_entry_references_.end()) { - const BitVector& method_indexes = method_it->second; - DCHECK_EQ(relative_offset, oat_dex_file->method_bss_mapping_offset_); - DCHECK_OFFSET(); - size_t method_mappings_size = WriteIndexBssMapping( - out, - dex_file->NumMethodIds(), - static_cast<size_t>(pointer_size), - method_indexes, - [=](uint32_t index) { - return bss_method_entries_.Get({dex_file, index}); - }); - if (method_mappings_size == 0u) { - return 0u; - } - size_method_bss_mappings_ += method_mappings_size; - relative_offset += method_mappings_size; - } else { - DCHECK_EQ(0u, oat_dex_file->method_bss_mapping_offset_); - } - - auto type_it = bss_type_entry_references_.find(dex_file); - if (type_it != bss_type_entry_references_.end()) { - const BitVector& type_indexes = type_it->second; - DCHECK_EQ(relative_offset, oat_dex_file->type_bss_mapping_offset_); - DCHECK_OFFSET(); - size_t type_mappings_size = - WriteIndexBssMapping(out, dex_file, type_indexes, bss_type_entries_); - if (type_mappings_size == 0u) { - return 0u; - } - size_type_bss_mappings_ += type_mappings_size; - relative_offset += type_mappings_size; - } else { - DCHECK_EQ(0u, oat_dex_file->type_bss_mapping_offset_); - } - - auto public_type_it = bss_public_type_entry_references_.find(dex_file); - if (public_type_it != bss_public_type_entry_references_.end()) { - const BitVector& type_indexes = public_type_it->second; - DCHECK_EQ(relative_offset, oat_dex_file->public_type_bss_mapping_offset_); - DCHECK_OFFSET(); - size_t public_type_mappings_size = - WriteIndexBssMapping(out, dex_file, type_indexes, bss_public_type_entries_); - if (public_type_mappings_size == 0u) { - return 0u; - } - size_public_type_bss_mappings_ += public_type_mappings_size; - relative_offset += public_type_mappings_size; - } else { - DCHECK_EQ(0u, oat_dex_file->public_type_bss_mapping_offset_); - } - - auto package_type_it = bss_package_type_entry_references_.find(dex_file); - if (package_type_it != bss_package_type_entry_references_.end()) { - const BitVector& type_indexes = package_type_it->second; - DCHECK_EQ(relative_offset, oat_dex_file->package_type_bss_mapping_offset_); - DCHECK_OFFSET(); - size_t package_type_mappings_size = - WriteIndexBssMapping(out, dex_file, type_indexes, bss_package_type_entries_); - if (package_type_mappings_size == 0u) { - return 0u; - } - size_package_type_bss_mappings_ += package_type_mappings_size; - relative_offset += package_type_mappings_size; - } else { - DCHECK_EQ(0u, oat_dex_file->package_type_bss_mapping_offset_); + relative_offset = WriteIndexBssMappingsHelper(out, + file_offset, + relative_offset, + dex_file, + oat_dex_file->method_bss_mapping_offset_, + oat_dex_file->type_bss_mapping_offset_, + oat_dex_file->public_type_bss_mapping_offset_, + oat_dex_file->package_type_bss_mapping_offset_, + oat_dex_file->string_bss_mapping_offset_); + if (relative_offset == 0u) { + return 0u; } + } - auto string_it = bss_string_entry_references_.find(dex_file); - if (string_it != bss_string_entry_references_.end()) { - const BitVector& string_indexes = string_it->second; - DCHECK_EQ(relative_offset, oat_dex_file->string_bss_mapping_offset_); - DCHECK_OFFSET(); - size_t string_mappings_size = WriteIndexBssMapping( - out, - dex_file->NumStringIds(), - sizeof(GcRoot<mirror::String>), - string_indexes, - [=](uint32_t index) { - return bss_string_entries_.Get({dex_file, dex::StringIndex(index)}); - }); - if (string_mappings_size == 0u) { + if (!(compiler_options_.IsBootImage() || compiler_options_.IsBootImageExtension())) { + ArrayRef<const DexFile* const> boot_class_path( + Runtime::Current()->GetClassLinker()->GetBootClassPath()); + for (size_t i = 0, size = bcp_bss_info_.size(); i != size; ++i) { + const DexFile* dex_file = boot_class_path[i]; + DCHECK(!ContainsElement(*dex_files_, dex_file)); + relative_offset = + WriteIndexBssMappingsHelper(out, + file_offset, + relative_offset, + dex_file, + bcp_bss_info_[i].method_bss_mapping_offset, + bcp_bss_info_[i].type_bss_mapping_offset, + bcp_bss_info_[i].public_type_bss_mapping_offset, + bcp_bss_info_[i].package_type_bss_mapping_offset, + bcp_bss_info_[i].string_bss_mapping_offset); + if (relative_offset == 0u) { return 0u; } - size_string_bss_mappings_ += string_mappings_size; - relative_offset += string_mappings_size; - } else { - DCHECK_EQ(0u, oat_dex_file->string_bss_mapping_offset_); } } return relative_offset; @@ -2983,6 +3145,34 @@ size_t OatWriter::WriteOatDexFiles(OutputStream* out, size_t file_offset, size_t return relative_offset; } +size_t OatWriter::WriteBcpBssInfo(OutputStream* out, size_t file_offset, size_t relative_offset) { + TimingLogger::ScopedTiming split("WriteBcpBssInfo", timings_); + + const uint32_t number_of_bcp_dexfiles = bcp_bss_info_.size(); + // We skip adding the number of DexFiles if we have no .bss mappings. + if (number_of_bcp_dexfiles == 0) { + return relative_offset; + } + + if (!out->WriteFully(&number_of_bcp_dexfiles, sizeof(number_of_bcp_dexfiles))) { + PLOG(ERROR) << "Failed to write the number of BCP dexfiles to " << out->GetLocation(); + return false; + } + size_bcp_bss_info_size_ = sizeof(number_of_bcp_dexfiles); + relative_offset += size_bcp_bss_info_size_; + + for (size_t i = 0, size = number_of_bcp_dexfiles; i != size; ++i) { + DCHECK_EQ(relative_offset, bcp_bss_info_[i].offset_); + DCHECK_OFFSET(); + if (!bcp_bss_info_[i].Write(this, out)) { + return 0u; + } + relative_offset += BssMappingInfo::SizeOf(); + } + + return relative_offset; +} + size_t OatWriter::WriteCode(OutputStream* out, size_t file_offset, size_t relative_offset) { if (GetCompilerOptions().IsBootImage() && primary_oat_file_) { InstructionSet instruction_set = compiler_options_.GetInstructionSet(); @@ -3972,6 +4162,45 @@ bool OatWriter::OatDexFile::Write(OatWriter* oat_writer, OutputStream* out) cons return true; } +bool OatWriter::BssMappingInfo::Write(OatWriter* oat_writer, OutputStream* out) const { + const size_t file_offset = oat_writer->oat_data_offset_; + DCHECK_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_bcp_bss_info_method_bss_mapping_offset_ += sizeof(method_bss_mapping_offset); + + if (!out->WriteFully(&type_bss_mapping_offset, sizeof(type_bss_mapping_offset))) { + PLOG(ERROR) << "Failed to write type bss mapping offset to " << out->GetLocation(); + return false; + } + oat_writer->size_bcp_bss_info_type_bss_mapping_offset_ += sizeof(type_bss_mapping_offset); + + if (!out->WriteFully(&public_type_bss_mapping_offset, sizeof(public_type_bss_mapping_offset))) { + PLOG(ERROR) << "Failed to write public type bss mapping offset to " << out->GetLocation(); + return false; + } + oat_writer->size_bcp_bss_info_public_type_bss_mapping_offset_ += + sizeof(public_type_bss_mapping_offset); + + if (!out->WriteFully(&package_type_bss_mapping_offset, sizeof(package_type_bss_mapping_offset))) { + PLOG(ERROR) << "Failed to write package type bss mapping offset to " << out->GetLocation(); + return false; + } + oat_writer->size_bcp_bss_info_package_type_bss_mapping_offset_ += + sizeof(package_type_bss_mapping_offset); + + if (!out->WriteFully(&string_bss_mapping_offset, sizeof(string_bss_mapping_offset))) { + PLOG(ERROR) << "Failed to write string bss mapping offset to " << out->GetLocation(); + return false; + } + oat_writer->size_bcp_bss_info_string_bss_mapping_offset_ += sizeof(string_bss_mapping_offset); + + return true; +} + bool OatWriter::OatDexFile::WriteClassOffsets(OatWriter* oat_writer, OutputStream* out) { if (!out->WriteFully(class_offsets_.data(), GetClassOffsetsRawSize())) { PLOG(ERROR) << "Failed to write oat class offsets for " << GetLocation() diff --git a/dex2oat/linker/oat_writer.h b/dex2oat/linker/oat_writer.h index ad14d60189..21ae77a6c5 100644 --- a/dex2oat/linker/oat_writer.h +++ b/dex2oat/linker/oat_writer.h @@ -244,6 +244,7 @@ class OatWriter { } private: + struct BssMappingInfo; class ChecksumUpdatingOutputStream; class DexFileSource; class OatClassHeader; @@ -307,6 +308,7 @@ class OatWriter { size_t InitOatMaps(size_t offset); size_t InitIndexBssMappings(size_t offset); size_t InitOatDexFiles(size_t offset); + size_t InitBcpBssInfo(size_t offset); size_t InitOatCode(size_t offset); size_t InitOatCodeDexFiles(size_t offset); size_t InitDataBimgRelRoLayout(size_t offset); @@ -317,9 +319,32 @@ class OatWriter { size_t WriteMaps(OutputStream* out, size_t file_offset, size_t relative_offset); size_t WriteIndexBssMappings(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 WriteBcpBssInfo(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); size_t WriteDataBimgRelRo(OutputStream* out, size_t file_offset, size_t relative_offset); + // These helpers extract common code from BCP and non-BCP DexFiles from its corresponding methods. + size_t WriteIndexBssMappingsHelper(OutputStream* out, + size_t file_offset, + size_t relative_offset, + const DexFile* dex_file, + uint32_t method_bss_mapping_offset, + uint32_t type_bss_mapping_offset, + uint32_t public_type_bss_mapping_offset, + uint32_t package_type_bss_mapping_offset, + uint32_t string_bss_mapping_offset); + size_t InitIndexBssMappingsHelper(size_t offset, + const DexFile* dex_file, + /*inout*/ size_t& number_of_method_dex_files, + /*inout*/ size_t& number_of_type_dex_files, + /*inout*/ size_t& number_of_public_type_dex_files, + /*inout*/ size_t& number_of_package_type_dex_files, + /*inout*/ size_t& number_of_string_dex_files, + /*inout*/ uint32_t& method_bss_mapping_offset, + /*inout*/ uint32_t& type_bss_mapping_offset, + /*inout*/ uint32_t& public_type_bss_mapping_offset, + /*inout*/ uint32_t& package_type_bss_mapping_offset, + /*inout*/ uint32_t& string_bss_mapping_offset); bool RecordOatDataOffset(OutputStream* out); void InitializeTypeLookupTables( @@ -423,6 +448,9 @@ class OatWriter { // The offset of the GC roots in .bss section. size_t bss_roots_offset_; + // OatFile's information regarding the bss metadata for BCP DexFiles. Empty for multi-image. + std::vector<BssMappingInfo> bcp_bss_info_; + // Map for allocating .data.bimg.rel.ro entries. Indexed by the boot image offset of the // relocation. The value is the assigned offset within the .data.bimg.rel.ro section. SafeMap<uint32_t, size_t> data_bimg_rel_ro_entries_; @@ -534,6 +562,12 @@ class OatWriter { uint32_t size_oat_dex_file_public_type_bss_mapping_offset_; uint32_t size_oat_dex_file_package_type_bss_mapping_offset_; uint32_t size_oat_dex_file_string_bss_mapping_offset_; + uint32_t size_bcp_bss_info_size_; + uint32_t size_bcp_bss_info_method_bss_mapping_offset_; + uint32_t size_bcp_bss_info_type_bss_mapping_offset_; + uint32_t size_bcp_bss_info_public_type_bss_mapping_offset_; + uint32_t size_bcp_bss_info_package_type_bss_mapping_offset_; + uint32_t size_bcp_bss_info_string_bss_mapping_offset_; uint32_t size_oat_class_offsets_alignment_; uint32_t size_oat_class_offsets_; uint32_t size_oat_class_type_; diff --git a/dex2oat/linker/oat_writer_test.cc b/dex2oat/linker/oat_writer_test.cc index b0ff362381..6b2198d9b2 100644 --- a/dex2oat/linker/oat_writer_test.cc +++ b/dex2oat/linker/oat_writer_test.cc @@ -502,7 +502,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(64U, sizeof(OatHeader)); + EXPECT_EQ(68U, sizeof(OatHeader)); EXPECT_EQ(4U, sizeof(OatMethodOffsets)); EXPECT_EQ(4U, sizeof(OatQuickMethodHeader)); EXPECT_EQ(167 * static_cast<size_t>(GetInstructionSetPointerSize(kRuntimeISA)), diff --git a/oatdump/oatdump.cc b/oatdump/oatdump.cc index f8d81288b5..c7e6c0934e 100644 --- a/oatdump/oatdump.cc +++ b/oatdump/oatdump.cc @@ -528,42 +528,48 @@ class OatDumper { } if (!options_.dump_header_only_) { - // Dump .bss entries. - DumpBssEntries( - os, - "ArtMethod", - oat_dex_file->GetMethodBssMapping(), - dex_file->NumMethodIds(), - static_cast<size_t>(GetInstructionSetPointerSize(instruction_set_)), - [=](uint32_t index) { return dex_file->PrettyMethod(index); }); - DumpBssEntries( - os, - "Class", - oat_dex_file->GetTypeBssMapping(), - dex_file->NumTypeIds(), - sizeof(GcRoot<mirror::Class>), - [=](uint32_t index) { return dex_file->PrettyType(dex::TypeIndex(index)); }); - DumpBssEntries( - os, - "Public Class", - oat_dex_file->GetPublicTypeBssMapping(), - dex_file->NumTypeIds(), - sizeof(GcRoot<mirror::Class>), - [=](uint32_t index) { return dex_file->PrettyType(dex::TypeIndex(index)); }); - DumpBssEntries( - os, - "Package Class", - oat_dex_file->GetPackageTypeBssMapping(), - dex_file->NumTypeIds(), - sizeof(GcRoot<mirror::Class>), - [=](uint32_t index) { return dex_file->PrettyType(dex::TypeIndex(index)); }); - DumpBssEntries( - os, - "String", - oat_dex_file->GetStringBssMapping(), - dex_file->NumStringIds(), - sizeof(GcRoot<mirror::Class>), - [=](uint32_t index) { return dex_file->StringDataByIdx(dex::StringIndex(index)); }); + DumpBssMappings(os, + dex_file, + oat_dex_file->GetMethodBssMapping(), + oat_dex_file->GetTypeBssMapping(), + oat_dex_file->GetPublicTypeBssMapping(), + oat_dex_file->GetPackageTypeBssMapping(), + oat_dex_file->GetStringBssMapping()); + } + } + + if (!options_.dump_header_only_) { + Runtime* const runtime = Runtime::Current(); + ClassLinker* const linker = runtime != nullptr ? runtime->GetClassLinker() : nullptr; + + if (linker != nullptr) { + ArrayRef<const DexFile* const> bcp_dex_files(linker->GetBootClassPath()); + // The guarantee that we have is that we can safely take a look the BCP DexFiles in + // [0..number_of_compiled_bcp_dexfiles) since the runtime may add more DexFiles after that. + // As a note, in the case of not having mappings or in the case of multi image we + // purposively leave `oat_file_.bcp_bss_info` empty. + CHECK_LE(oat_file_.bcp_bss_info_.size(), bcp_dex_files.size()); + for (size_t i = 0; i < oat_file_.bcp_bss_info_.size(); i++) { + const DexFile* const dex_file = bcp_dex_files[i]; + os << "Dumping entries for BCP DexFile: " << dex_file->GetLocation() << "\n"; + DumpBssMappings(os, + dex_file, + oat_file_.bcp_bss_info_[i].method_bss_mapping, + oat_file_.bcp_bss_info_[i].type_bss_mapping, + oat_file_.bcp_bss_info_[i].public_type_bss_mapping, + oat_file_.bcp_bss_info_[i].package_type_bss_mapping, + oat_file_.bcp_bss_info_[i].string_bss_mapping); + } + } else { + // We don't have a runtime, just dump the offsets + for (size_t i = 0; i < oat_file_.bcp_bss_info_.size(); i++) { + os << "We don't have a runtime, just dump the offsets for BCP Dexfile " << i << "\n"; + DumpBssOffsets(os, "ArtMethod", oat_file_.bcp_bss_info_[i].method_bss_mapping); + DumpBssOffsets(os, "Class", oat_file_.bcp_bss_info_[i].type_bss_mapping); + DumpBssOffsets(os, "Public Class", oat_file_.bcp_bss_info_[i].public_type_bss_mapping); + DumpBssOffsets(os, "Package Class", oat_file_.bcp_bss_info_[i].package_type_bss_mapping); + DumpBssOffsets(os, "String", oat_file_.bcp_bss_info_[i].string_bss_mapping); + } } } @@ -1680,6 +1686,71 @@ class OatDumper { os << std::dec; } + void DumpBssMappings(std::ostream& os, + const DexFile* dex_file, + const IndexBssMapping* method_bss_mapping, + const IndexBssMapping* type_bss_mapping, + const IndexBssMapping* public_type_bss_mapping, + const IndexBssMapping* package_type_bss_mapping, + const IndexBssMapping* string_bss_mapping) { + DumpBssEntries(os, + "ArtMethod", + method_bss_mapping, + dex_file->NumMethodIds(), + static_cast<size_t>(GetInstructionSetPointerSize(instruction_set_)), + [=](uint32_t index) { return dex_file->PrettyMethod(index); }); + DumpBssEntries(os, + "Class", + type_bss_mapping, + dex_file->NumTypeIds(), + sizeof(GcRoot<mirror::Class>), + [=](uint32_t index) { return dex_file->PrettyType(dex::TypeIndex(index)); }); + DumpBssEntries(os, + "Public Class", + public_type_bss_mapping, + dex_file->NumTypeIds(), + sizeof(GcRoot<mirror::Class>), + [=](uint32_t index) { return dex_file->PrettyType(dex::TypeIndex(index)); }); + DumpBssEntries(os, + "Package Class", + package_type_bss_mapping, + dex_file->NumTypeIds(), + sizeof(GcRoot<mirror::Class>), + [=](uint32_t index) { return dex_file->PrettyType(dex::TypeIndex(index)); }); + DumpBssEntries( + os, + "String", + string_bss_mapping, + dex_file->NumStringIds(), + sizeof(GcRoot<mirror::Class>), + [=](uint32_t index) { return dex_file->StringDataByIdx(dex::StringIndex(index)); }); + } + + void DumpBssOffsets(std::ostream& os, const char* slot_type, const IndexBssMapping* mapping) { + os << ".bss offset for " << slot_type << ": "; + if (mapping == nullptr) { + os << "empty.\n"; + return; + } + + os << "Mapping size: " << mapping->size() << "\n"; + for (size_t i = 0; i < mapping->size(); ++i) { + os << "Entry[" << i << "]: index_and_mask: " + << mapping->At(i).index_and_mask + << ", bss_offset: " + << mapping->At(i).bss_offset << "\n"; + } + + // TODO(solanes, 154012332): We are dumping the raw values but we could make assumptions about + // ordering of the entries and deconstruct even the `index_and_mask`. This would allow us to use + // DumpBssEntries and dump more information. The size and alignment of the entry (ArtMethod* + // depends on instruction set but Class and String references are 32-bit) and the difference + // from the previous `bss_offset` (or from the "oatbss" symbol for the first item) tell us how + // many .bss entries a single `IndexBssMappingEntry` should describe. So we know how many most + // significant set bits represent the mask and the rest is the actual index. And the position of + // the mask bits would allow reconstructing the other indexes. + } + const OatFile& oat_file_; const std::vector<const OatDexFile*> oat_dex_files_; const OatDumperOptions& options_; diff --git a/runtime/entrypoints/entrypoint_utils.cc b/runtime/entrypoints/entrypoint_utils.cc index 1c0127a519..63d2aa4351 100644 --- a/runtime/entrypoints/entrypoint_utils.cc +++ b/runtime/entrypoints/entrypoint_utils.cc @@ -36,6 +36,7 @@ #include "mirror/object_array-inl.h" #include "nth_caller_visitor.h" #include "oat_file.h" +#include "oat_file-inl.h" #include "oat_quick_method_header.h" #include "reflection.h" #include "scoped_thread_state_change-inl.h" @@ -284,22 +285,46 @@ ObjPtr<mirror::MethodType> ResolveMethodTypeFromCode(ArtMethod* referrer, return method_type; } -void MaybeUpdateBssMethodEntry(ArtMethod* callee, MethodReference callee_reference) { - DCHECK(callee != nullptr); - if (callee_reference.dex_file->GetOatDexFile() != nullptr) { - size_t bss_offset = IndexBssMappingLookup::GetBssOffset( - callee_reference.dex_file->GetOatDexFile()->GetMethodBssMapping(), - callee_reference.index, - callee_reference.dex_file->NumMethodIds(), - static_cast<size_t>(kRuntimePointerSize)); +void MaybeUpdateBssMethodEntry(ArtMethod* callee, + MethodReference callee_reference, + ArtMethod* outer_method) { + DCHECK_NE(callee, nullptr); + if (outer_method->GetDexFile()->GetOatDexFile() == nullptr || + outer_method->GetDexFile()->GetOatDexFile()->GetOatFile() == nullptr) { + // No OatFile to update. + return; + } + const OatFile* outer_oat_file = outer_method->GetDexFile()->GetOatDexFile()->GetOatFile(); + + const DexFile* dex_file = callee_reference.dex_file; + const OatDexFile* oat_dex_file = dex_file->GetOatDexFile(); + const IndexBssMapping* mapping = nullptr; + if (oat_dex_file != nullptr && oat_dex_file->GetOatFile() == outer_oat_file) { + // DexFiles compiled together to an oat file case. + mapping = oat_dex_file->GetMethodBssMapping(); + } else { + // Try to find the DexFile in the BCP of the outer_method. + const OatFile::BssMappingInfo* mapping_info = outer_oat_file->FindBcpMappingInfo(dex_file); + if (mapping_info != nullptr) { + mapping = mapping_info->method_bss_mapping; + } + } + + // Perform the update if we found a mapping. + if (mapping != nullptr) { + size_t bss_offset = + IndexBssMappingLookup::GetBssOffset(mapping, + callee_reference.index, + dex_file->NumMethodIds(), + static_cast<size_t>(kRuntimePointerSize)); if (bss_offset != IndexBssMappingLookup::npos) { DCHECK_ALIGNED(bss_offset, static_cast<size_t>(kRuntimePointerSize)); - const OatFile* oat_file = callee_reference.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_NE(outer_oat_file, nullptr); + ArtMethod** method_entry = reinterpret_cast<ArtMethod**>( + const_cast<uint8_t*>(outer_oat_file->BssBegin() + bss_offset)); + DCHECK_GE(method_entry, outer_oat_file->GetBssMethods().data()); DCHECK_LT(method_entry, - oat_file->GetBssMethods().data() + oat_file->GetBssMethods().size()); + outer_oat_file->GetBssMethods().data() + outer_oat_file->GetBssMethods().size()); std::atomic<ArtMethod*>* atomic_entry = reinterpret_cast<std::atomic<ArtMethod*>*>(method_entry); if (kIsDebugBuild) { diff --git a/runtime/entrypoints/entrypoint_utils.h b/runtime/entrypoints/entrypoint_utils.h index 5faf387093..8b6fc69bea 100644 --- a/runtime/entrypoints/entrypoint_utils.h +++ b/runtime/entrypoints/entrypoint_utils.h @@ -213,9 +213,14 @@ bool NeedsClinitCheckBeforeCall(ArtMethod* method) REQUIRES_SHARED(Locks::mutato ObjPtr<mirror::Object> GetGenericJniSynchronizationObject(Thread* self, ArtMethod* called) REQUIRES_SHARED(Locks::mutator_lock_); -// Update .bss method entrypoint if the `callee_reference` has an associated oat file -// and that oat file has a .bss entry for the `callee_reference`. -void MaybeUpdateBssMethodEntry(ArtMethod* callee, MethodReference callee_reference); +// Update .bss method entrypoint if the `outer_method` has a valid OatFile, and either +// A) the `callee_reference` has the same OatFile as `outer_method`, or +// B) the `callee_reference` comes from a BCP DexFile that was present during `outer_method`'s +// OatFile compilation. +// In both cases, we require that the oat file has a .bss entry for the `callee_reference`. +void MaybeUpdateBssMethodEntry(ArtMethod* callee, + MethodReference callee_reference, + ArtMethod* outer_method) REQUIRES_SHARED(Locks::mutator_lock_); } // namespace art diff --git a/runtime/entrypoints/jni/jni_entrypoints.cc b/runtime/entrypoints/jni/jni_entrypoints.cc index ddc6839014..690f16af51 100644 --- a/runtime/entrypoints/jni/jni_entrypoints.cc +++ b/runtime/entrypoints/jni/jni_entrypoints.cc @@ -69,7 +69,9 @@ extern "C" const void* artFindNativeMethodRunnable(Thread* self) // Note that the BSS also contains entries used for super calls. Given we // only deal with invokestatic in this code path, we don't need to adjust // the method index. - MaybeUpdateBssMethodEntry(target_method, MethodReference(method->GetDexFile(), method_idx)); + MaybeUpdateBssMethodEntry(target_method, + MethodReference(method->GetDexFile(), method_idx), + GetCalleeSaveOuterMethod(self, CalleeSaveType::kSaveRefsAndArgs)); // These calls do not have an explicit class initialization check, so do the check now. // (When going through the stub or GenericJNI, the check was already done.) diff --git a/runtime/entrypoints/quick/quick_dexcache_entrypoints.cc b/runtime/entrypoints/quick/quick_dexcache_entrypoints.cc index 8061315971..60a5875c5e 100644 --- a/runtime/entrypoints/quick/quick_dexcache_entrypoints.cc +++ b/runtime/entrypoints/quick/quick_dexcache_entrypoints.cc @@ -28,11 +28,12 @@ #include "mirror/object-inl.h" #include "mirror/object_array-inl.h" #include "oat_file.h" +#include "oat_file-inl.h" #include "runtime.h" namespace art { -static void StoreObjectInBss(ArtMethod* caller, +static void StoreObjectInBss(ArtMethod* outer_method, const OatFile* oat_file, size_t bss_offset, ObjPtr<mirror::Object> object) REQUIRES_SHARED(Locks::mutator_lock_) { @@ -41,6 +42,7 @@ static void StoreObjectInBss(ArtMethod* caller, static_assert(sizeof(GcRoot<mirror::String>) == sizeof(GcRoot<mirror::Object>), "Size check."); DCHECK_NE(bss_offset, IndexBssMappingLookup::npos); DCHECK_ALIGNED(bss_offset, sizeof(GcRoot<mirror::Object>)); + DCHECK_NE(oat_file, nullptr); if (UNLIKELY(!oat_file->IsExecutable())) { // There are situations where we execute bytecode tied to an oat file opened // as non-executable (i.e. the AOT-compiled code cannot be executed) and we @@ -58,13 +60,13 @@ static void StoreObjectInBss(ArtMethod* caller, static_assert(sizeof(*slot) == sizeof(*atomic_slot), "Size check"); atomic_slot->store(GcRoot<mirror::Object>(object), std::memory_order_release); // We need a write barrier for the class loader that holds the GC roots in the .bss. - ObjPtr<mirror::ClassLoader> class_loader = caller->GetClassLoader(); + ObjPtr<mirror::ClassLoader> class_loader = outer_method->GetClassLoader(); Runtime* runtime = Runtime::Current(); if (kIsDebugBuild) { ClassTable* class_table = runtime->GetClassLinker()->ClassTableForClassLoader(class_loader); CHECK(class_table != nullptr && !class_table->InsertOatFile(oat_file)) << "Oat file with .bss GC roots was not registered in class table: " - << oat_file->GetLocation(); + << oat_file->GetLocation() << ", " << outer_method->PrettyMethod(); } if (class_loader != nullptr) { WriteBarrier::ForEveryFieldWrite(class_loader); @@ -79,71 +81,91 @@ static void StoreObjectInBss(ArtMethod* caller, static inline void StoreTypeInBss(ArtMethod* caller, dex::TypeIndex type_idx, - ObjPtr<mirror::Class> resolved_type) - REQUIRES_SHARED(Locks::mutator_lock_) { + ObjPtr<mirror::Class> resolved_type, + ArtMethod* outer_method) REQUIRES_SHARED(Locks::mutator_lock_) { const DexFile* dex_file = caller->GetDexFile(); - DCHECK(dex_file != nullptr); + DCHECK_NE(dex_file, nullptr); + + if (outer_method->GetDexFile()->GetOatDexFile() == nullptr || + outer_method->GetDexFile()->GetOatDexFile()->GetOatFile() == nullptr) { + // No OatFile to update. + return; + } + const OatFile* outer_oat_file = outer_method->GetDexFile()->GetOatDexFile()->GetOatFile(); + + // DexFiles compiled together to an oat file case. const OatDexFile* oat_dex_file = dex_file->GetOatDexFile(); - if (oat_dex_file != nullptr) { - auto store = [=](const IndexBssMapping* mapping) REQUIRES_SHARED(Locks::mutator_lock_) { - size_t bss_offset = IndexBssMappingLookup::GetBssOffset(mapping, - type_idx.index_, - dex_file->NumTypeIds(), - sizeof(GcRoot<mirror::Class>)); + const IndexBssMapping* type_mapping = nullptr; + const IndexBssMapping* public_type_mapping = nullptr; + const IndexBssMapping* package_type_mapping = nullptr; + if (oat_dex_file != nullptr && oat_dex_file->GetOatFile() == outer_oat_file) { + type_mapping = oat_dex_file->GetTypeBssMapping(); + public_type_mapping = oat_dex_file->GetPublicTypeBssMapping(); + package_type_mapping = oat_dex_file->GetPackageTypeBssMapping(); + } else { + // Try to find the DexFile in the BCP of the outer_method. + const OatFile::BssMappingInfo* mapping_info = outer_oat_file->FindBcpMappingInfo(dex_file); + if (mapping_info != nullptr) { + type_mapping = mapping_info->type_bss_mapping; + public_type_mapping = mapping_info->public_type_bss_mapping; + package_type_mapping = mapping_info->package_type_bss_mapping; + } + } + + // Perform the update if we found a mapping. + auto store = [=](const IndexBssMapping* mapping) REQUIRES_SHARED(Locks::mutator_lock_) { + if (mapping != nullptr) { + size_t bss_offset = IndexBssMappingLookup::GetBssOffset( + mapping, type_idx.index_, dex_file->NumTypeIds(), sizeof(GcRoot<mirror::Class>)); if (bss_offset != IndexBssMappingLookup::npos) { - StoreObjectInBss(caller, oat_dex_file->GetOatFile(), bss_offset, resolved_type); + StoreObjectInBss(outer_method, outer_oat_file, bss_offset, resolved_type); } - }; - store(oat_dex_file->GetTypeBssMapping()); - if (resolved_type->IsPublic()) { - store(oat_dex_file->GetPublicTypeBssMapping()); - } - if (resolved_type->IsPublic() || - resolved_type->GetClassLoader() == caller->GetClassLoader()) { - store(oat_dex_file->GetPackageTypeBssMapping()); } + }; + store(type_mapping); + if (resolved_type->IsPublic()) { + store(public_type_mapping); + } + if (resolved_type->IsPublic() || resolved_type->GetClassLoader() == caller->GetClassLoader()) { + store(package_type_mapping); } } static inline void StoreStringInBss(ArtMethod* caller, dex::StringIndex string_idx, - ObjPtr<mirror::String> resolved_string) - REQUIRES_SHARED(Locks::mutator_lock_) { + ObjPtr<mirror::String> resolved_string, + ArtMethod* outer_method) REQUIRES_SHARED(Locks::mutator_lock_) { const DexFile* dex_file = caller->GetDexFile(); - DCHECK(dex_file != nullptr); + DCHECK_NE(dex_file, nullptr); + + if (outer_method->GetDexFile()->GetOatDexFile() == nullptr || + outer_method->GetDexFile()->GetOatDexFile()->GetOatFile() == nullptr) { + // No OatFile to update. + return; + } + const OatFile* outer_oat_file = outer_method->GetDexFile()->GetOatDexFile()->GetOatFile(); + const OatDexFile* oat_dex_file = dex_file->GetOatDexFile(); - if (oat_dex_file != nullptr) { - size_t bss_offset = IndexBssMappingLookup::GetBssOffset(oat_dex_file->GetStringBssMapping(), - string_idx.index_, - dex_file->NumStringIds(), - sizeof(GcRoot<mirror::Class>)); - if (bss_offset != IndexBssMappingLookup::npos) { - StoreObjectInBss(caller, oat_dex_file->GetOatFile(), bss_offset, resolved_string); + const IndexBssMapping* mapping = nullptr; + if (oat_dex_file != nullptr && oat_dex_file->GetOatFile() == outer_oat_file) { + // DexFiles compiled together to an oat file case. + mapping = oat_dex_file->GetStringBssMapping(); + } else { + // Try to find the DexFile in the BCP of the outer_method. + const OatFile::BssMappingInfo* mapping_info = outer_oat_file->FindBcpMappingInfo(dex_file); + if (mapping_info != nullptr) { + mapping = mapping_info->string_bss_mapping; } } -} -static ALWAYS_INLINE bool CanReferenceBss(ArtMethod* outer_method, ArtMethod* caller) - REQUIRES_SHARED(Locks::mutator_lock_) { - // .bss references are used only for AOT-compiled code. As we do not want to check if the call is - // coming from AOT-compiled code (that could be expensive), we can simply check if the caller has - // the same dex file. - // - // When we are JIT compiling, if the caller and outer method have the same dex file we may or may - // not find a .bss slot to update; if we do, this can still benefit AOT-compiled code executed - // later. - const DexFile* outer_dex_file = outer_method->GetDexFile(); - const DexFile* caller_dex_file = caller->GetDexFile(); - if (outer_dex_file == caller_dex_file) { - return true; + // Perform the update if we found a mapping. + if (mapping != nullptr) { + size_t bss_offset = IndexBssMappingLookup::GetBssOffset( + mapping, string_idx.index_, dex_file->NumStringIds(), sizeof(GcRoot<mirror::Class>)); + if (bss_offset != IndexBssMappingLookup::npos) { + StoreObjectInBss(outer_method, outer_oat_file, bss_offset, resolved_string); + } } - - // We allow AOT-compiled code to reference .bss slots for all dex files compiled together to an - // oat file. - return caller_dex_file->GetOatDexFile() != nullptr && - outer_dex_file->GetOatDexFile() != nullptr && - caller_dex_file->GetOatDexFile()->GetOatFile() == - outer_dex_file->GetOatDexFile()->GetOatFile(); } extern "C" mirror::Class* artInitializeStaticStorageFromCode(mirror::Class* klass, Thread* self) @@ -176,8 +198,9 @@ extern "C" mirror::Class* artResolveTypeFromCode(uint32_t type_idx, Thread* self self, /* can_run_clinit= */ false, /* verify_access= */ false); - if (LIKELY(result != nullptr) && CanReferenceBss(caller_and_outer.outer_method, caller)) { - StoreTypeInBss(caller, dex::TypeIndex(type_idx), result); + ArtMethod* outer_method = caller_and_outer.outer_method; + if (LIKELY(result != nullptr)) { + StoreTypeInBss(caller, dex::TypeIndex(type_idx), result, outer_method); } return result.Ptr(); } @@ -194,8 +217,9 @@ extern "C" mirror::Class* artResolveTypeAndVerifyAccessFromCode(uint32_t type_id self, /* can_run_clinit= */ false, /* verify_access= */ true); - if (LIKELY(result != nullptr) && CanReferenceBss(caller_and_outer.outer_method, caller)) { - StoreTypeInBss(caller, dex::TypeIndex(type_idx), result); + ArtMethod* outer_method = caller_and_outer.outer_method; + if (LIKELY(result != nullptr)) { + StoreTypeInBss(caller, dex::TypeIndex(type_idx), result, outer_method); } return result.Ptr(); } @@ -229,8 +253,9 @@ extern "C" mirror::String* artResolveStringFromCode(int32_t string_idx, Thread* ArtMethod* caller = caller_and_outer.caller; ObjPtr<mirror::String> result = Runtime::Current()->GetClassLinker()->ResolveString(dex::StringIndex(string_idx), caller); - if (LIKELY(result != nullptr) && CanReferenceBss(caller_and_outer.outer_method, caller)) { - StoreStringInBss(caller, dex::StringIndex(string_idx), result); + ArtMethod* outer_method = caller_and_outer.outer_method; + if (LIKELY(result != nullptr)) { + StoreStringInBss(caller, dex::StringIndex(string_idx), result, outer_method); } return result.Ptr(); } diff --git a/runtime/entrypoints/quick/quick_trampoline_entrypoints.cc b/runtime/entrypoints/quick/quick_trampoline_entrypoints.cc index 0b4398dc8c..e54126fb59 100644 --- a/runtime/entrypoints/quick/quick_trampoline_entrypoints.cc +++ b/runtime/entrypoints/quick/quick_trampoline_entrypoints.cc @@ -1375,7 +1375,8 @@ extern "C" const void* artQuickResolutionTrampoline( DCHECK_NE(called_method.index, dex::kDexNoIndex); } } - MaybeUpdateBssMethodEntry(called, called_method); + ArtMethod* outer_method = QuickArgumentVisitor::GetOuterMethod(sp); + MaybeUpdateBssMethodEntry(called, called_method, outer_method); } // Static invokes need class initialization check but instance invokes can proceed even if @@ -2405,7 +2406,9 @@ extern "C" TwoWordReturn artInvokeInterfaceTrampoline(ArtMethod* interface_metho CHECK(self->IsExceptionPending()); return GetTwoWordFailureValue(); // Failure. } - MaybeUpdateBssMethodEntry(interface_method, MethodReference(&dex_file, dex_method_idx)); + ArtMethod* outer_method = QuickArgumentVisitor::GetOuterMethod(sp); + MaybeUpdateBssMethodEntry( + interface_method, MethodReference(&dex_file, dex_method_idx), outer_method); // Refresh `raw_this_object` which may have changed after resolution. raw_this_object = this_object.Get(); diff --git a/runtime/oat.cc b/runtime/oat.cc index 3698ddfaed..64ed14ac41 100644 --- a/runtime/oat.cc +++ b/runtime/oat.cc @@ -71,6 +71,7 @@ OatHeader::OatHeader(InstructionSet instruction_set, instruction_set_features_bitmap_(instruction_set_features->AsBitmap()), dex_file_count_(dex_file_count), oat_dex_files_offset_(0), + bcp_bss_info_offset_(0), executable_offset_(0), jni_dlsym_lookup_trampoline_offset_(0), jni_dlsym_lookup_critical_trampoline_offset_(0), @@ -183,6 +184,22 @@ void OatHeader::SetOatDexFilesOffset(uint32_t oat_dex_files_offset) { oat_dex_files_offset_ = oat_dex_files_offset; } +uint32_t OatHeader::GetBcpBssInfoOffset() const { + DCHECK(IsValid()); + DCHECK(bcp_bss_info_offset_ == 0u || bcp_bss_info_offset_ > sizeof(OatHeader)) + << "bcp_bss_info_offset_: " << bcp_bss_info_offset_ + << "sizeof(OatHeader): " << sizeof(OatHeader); + return bcp_bss_info_offset_; +} + +void OatHeader::SetBcpBssInfoOffset(uint32_t bcp_info_offset) { + DCHECK_GT(bcp_info_offset, sizeof(OatHeader)); + DCHECK(IsValid()); + DCHECK_EQ(bcp_bss_info_offset_, 0u); + + bcp_bss_info_offset_ = bcp_info_offset; +} + uint32_t OatHeader::GetExecutableOffset() const { DCHECK(IsValid()); DCHECK_ALIGNED(executable_offset_, kPageSize); diff --git a/runtime/oat.h b/runtime/oat.h index f6a04d8d02..462d41cdf0 100644 --- a/runtime/oat.h +++ b/runtime/oat.h @@ -32,8 +32,8 @@ class InstructionSetFeatures; class PACKED(4) OatHeader { public: static constexpr std::array<uint8_t, 4> kOatMagic { { 'o', 'a', 't', '\n' } }; - // Last oat version changed reason: Revert "bss support for inlining BCP into non-BCP". - static constexpr std::array<uint8_t, 4> kOatVersion { { '2', '2', '3', '\0' } }; + // Last oat version changed reason: Revert^4 "bss support for inlining BCP into non-BCP". + static constexpr std::array<uint8_t, 4> kOatVersion { { '2', '2', '5', '\0' } }; static constexpr const char* kDex2OatCmdLineKey = "dex2oat-cmdline"; static constexpr const char* kDebuggableKey = "debuggable"; @@ -68,6 +68,8 @@ class PACKED(4) OatHeader { } uint32_t GetOatDexFilesOffset() const; void SetOatDexFilesOffset(uint32_t oat_dex_files_offset); + uint32_t GetBcpBssInfoOffset() const; + void SetBcpBssInfoOffset(uint32_t bcp_info_offset); uint32_t GetExecutableOffset() const; void SetExecutableOffset(uint32_t executable_offset); @@ -130,6 +132,7 @@ class PACKED(4) OatHeader { uint32_t instruction_set_features_bitmap_; uint32_t dex_file_count_; uint32_t oat_dex_files_offset_; + uint32_t bcp_bss_info_offset_; uint32_t executable_offset_; uint32_t jni_dlsym_lookup_trampoline_offset_; uint32_t jni_dlsym_lookup_critical_trampoline_offset_; diff --git a/runtime/oat_file-inl.h b/runtime/oat_file-inl.h index 772566fbe3..fd42e45dce 100644 --- a/runtime/oat_file-inl.h +++ b/runtime/oat_file-inl.h @@ -21,6 +21,7 @@ #include "base/utils.h" #include "oat_quick_method_header.h" +#include "runtime-inl.h" namespace art { @@ -97,6 +98,20 @@ inline const void* OatFile::OatMethod::GetQuickCode() const { return reinterpret_cast<const void *>(begin_ + code_offset_); } +inline const OatFile::BssMappingInfo* OatFile::FindBcpMappingInfo(const DexFile* dex_file) const { + ArrayRef<const OatFile::BssMappingInfo> mapping_info_vector(GetBcpBssInfo()); + ArrayRef<const DexFile* const> bcp_dexfiles( + Runtime::Current()->GetClassLinker()->GetBootClassPath()); + // Create a sub array to limit search range. + bcp_dexfiles = bcp_dexfiles.SubArray(/*pos=*/ 0u, mapping_info_vector.size()); + auto it = std::find(bcp_dexfiles.begin(), bcp_dexfiles.end(), dex_file); + if (it != bcp_dexfiles.end()) { + return &mapping_info_vector[std::distance(bcp_dexfiles.begin(), it)]; + } else { + return nullptr; + } +} + } // namespace art #endif // ART_RUNTIME_OAT_FILE_INL_H_ diff --git a/runtime/oat_file.cc b/runtime/oat_file.cc index afa3d4d6b6..7809095a27 100644 --- a/runtime/oat_file.cc +++ b/runtime/oat_file.cc @@ -1002,6 +1002,85 @@ bool OatFileBase::Setup(int zip_fd, oat_dex_files_.Put(canonical_key, oat_dex_file); } } + + size_t bcp_info_offset = GetOatHeader().GetBcpBssInfoOffset(); + // `bcp_info_offset` will be 0 for multi-image, or for the case of no mappings. + if (bcp_info_offset != 0) { + // Consistency check. + if (bcp_info_offset < GetOatHeader().GetHeaderSize() || bcp_info_offset > Size()) { + *error_msg = StringPrintf( + "In oat file '%s' found invalid bcp info offset: " + "%zu is not in [%zu, %zu]", + GetLocation().c_str(), + bcp_info_offset, + GetOatHeader().GetHeaderSize(), + Size()); + return false; + } + const uint8_t* bcp_info_begin = Begin() + bcp_info_offset; // Jump to the BCP_info records. + + uint32_t number_of_bcp_dexfiles; + if (UNLIKELY(!ReadOatDexFileData(*this, &bcp_info_begin, &number_of_bcp_dexfiles))) { + *error_msg = StringPrintf("Failed to read the number of BCP dex files"); + return false; + } + Runtime* const runtime = Runtime::Current(); + ClassLinker* const linker = runtime != nullptr ? runtime->GetClassLinker() : nullptr; + if (linker != nullptr && UNLIKELY(number_of_bcp_dexfiles > linker->GetBootClassPath().size())) { + // If we compiled with more DexFiles than what we have at runtime, we expect to discard this + // OatFile after verifying its checksum in OatFileAssistant. Therefore, we set + // `number_of_bcp_dexfiles` to 0 to avoid reading data that will ultimately be discarded. + number_of_bcp_dexfiles = 0; + } + + DCHECK(bcp_bss_info_.empty()); + bcp_bss_info_.resize(number_of_bcp_dexfiles); + // At runtime, there might be more DexFiles added to the BCP that we didn't compile with. + // We only care about the ones in [0..number_of_bcp_dexfiles). + for (size_t i = 0, size = number_of_bcp_dexfiles; i != size; ++i) { + const std::string& dex_file_location = linker != nullptr ? + linker->GetBootClassPath()[i]->GetLocation() : + "No runtime/linker therefore no DexFile location"; + if (!ReadIndexBssMapping(this, + &bcp_info_begin, + i, + dex_file_location, + "method", + &bcp_bss_info_[i].method_bss_mapping, + error_msg) || + !ReadIndexBssMapping(this, + &bcp_info_begin, + i, + dex_file_location, + "type", + &bcp_bss_info_[i].type_bss_mapping, + error_msg) || + !ReadIndexBssMapping(this, + &bcp_info_begin, + i, + dex_file_location, + "type", + &bcp_bss_info_[i].public_type_bss_mapping, + error_msg) || + !ReadIndexBssMapping(this, + &bcp_info_begin, + i, + dex_file_location, + "type", + &bcp_bss_info_[i].package_type_bss_mapping, + error_msg) || + !ReadIndexBssMapping(this, + &bcp_info_begin, + i, + dex_file_location, + "string", + &bcp_bss_info_[i].string_bss_mapping, + error_msg)) { + return false; + } + } + } + if (!dex_filenames.empty() && dex_filenames_pos != dex_filenames.size()) { *error_msg = StringPrintf("Oat file '%s' contains only %zu primary dex locations, expected %zu", GetLocation().c_str(), diff --git a/runtime/oat_file.h b/runtime/oat_file.h index 53a267ff90..c1b1acb368 100644 --- a/runtime/oat_file.h +++ b/runtime/oat_file.h @@ -379,6 +379,21 @@ class OatFile { // Returns whether an image (e.g. app image) is required to safely execute this OAT file. bool RequiresImage() const; + struct BssMappingInfo { + const IndexBssMapping* method_bss_mapping = nullptr; + const IndexBssMapping* type_bss_mapping = nullptr; + const IndexBssMapping* public_type_bss_mapping = nullptr; + const IndexBssMapping* package_type_bss_mapping = nullptr; + const IndexBssMapping* string_bss_mapping = nullptr; + }; + + ArrayRef<const BssMappingInfo> GetBcpBssInfo() const { + return ArrayRef<const BssMappingInfo>(bcp_bss_info_); + } + + // Returns the mapping info of `dex_file` if found in the BcpBssInfo, or nullptr otherwise. + const BssMappingInfo* FindBcpMappingInfo(const DexFile* dex_file) const; + protected: OatFile(const std::string& filename, bool executable); @@ -427,6 +442,9 @@ class OatFile { // Owning storage for the OatDexFile objects. std::vector<const OatDexFile*> oat_dex_files_storage_; + // Mapping info for DexFiles in the BCP. + std::vector<BssMappingInfo> bcp_bss_info_; + // NOTE: We use a std::string_view as the key type to avoid a memory allocation on every // lookup with a const char* key. The std::string_view doesn't own its backing storage, // therefore we're using the OatFile's stored dex location as the backing storage |