Add bss support for inlining BCP DexFiles for single image
This CL extends the .bss metadata section to allow for BCP methods
to be inlined into other DexFiles, even when requiring a bss entry.
Test: ART tests, compiling and launching top 100 apps
Bug: 154012332
Change-Id: Ib541e69a9c52b3fad003d286a5b57060770e1395
diff --git a/compiler/optimizing/code_generator_arm64.cc b/compiler/optimizing/code_generator_arm64.cc
index 548b2d4..037c81a 100644
--- a/compiler/optimizing/code_generator_arm64.cc
+++ b/compiler/optimizing/code_generator_arm64.cc
@@ -283,7 +283,9 @@
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 bafa89f..2104f79 100644
--- a/compiler/optimizing/code_generator_arm_vixl.cc
+++ b/compiler/optimizing/code_generator_arm_vixl.cc
@@ -531,7 +531,9 @@
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 0efd51c..4025684 100644
--- a/compiler/optimizing/code_generator_x86.cc
+++ b/compiler/optimizing/code_generator_x86.cc
@@ -290,7 +290,9 @@
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 @@
? 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 1016652..bbbaa82 100644
--- a/compiler/optimizing/code_generator_x86_64.cc
+++ b/compiler/optimizing/code_generator_x86_64.cc
@@ -274,7 +274,9 @@
// 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::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 ac71ce9..4cce9f7 100644
--- a/compiler/optimizing/inliner.cc
+++ b/compiler/optimizing/inliner.cc
@@ -1717,11 +1717,12 @@
// 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/compiler/optimizing/sharpening.cc b/compiler/optimizing/sharpening.cc
index 1fd76f7..eb4c206 100644
--- a/compiler/optimizing/sharpening.cc
+++ b/compiler/optimizing/sharpening.cc
@@ -283,6 +283,7 @@
// We actually cannot reference this class, we're forced to bail.
// We cannot reference this class with Bss, as the entrypoint will lookup the class
// in the caller's dex file, but that dex file does not reference the class.
+ // TODO(solanes, 154012332): Add the support for the cross-dex cases.
return HLoadClass::LoadKind::kInvalid;
}
}
diff --git a/dex2oat/linker/oat_writer.cc b/dex2oat/linker/oat_writer.cc
index eccc3d5..7ca1204 100644
--- a/dex2oat/linker/oat_writer.cc
+++ b/dex2oat/linker/oat_writer.cc
@@ -470,6 +470,12 @@
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 @@
offset = InitOatDexFiles(offset);
}
{
+ TimingLogger::ScopedTiming split("InitBcpBssInfo", timings_);
+ offset = InitBcpBssInfo(offset);
+ }
+ {
TimingLogger::ScopedTiming split("InitOatCode", timings_);
offset = InitOatCode(offset);
}
@@ -944,10 +954,8 @@
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 @@
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.
@@ -2197,67 +2228,123 @@
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});
- });
- }
+ 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_);
+ }
- 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)});
- });
+ 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;
}
@@ -2270,6 +2357,23 @@
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;
@@ -2500,6 +2604,12 @@
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_;
@@ -2673,6 +2783,12 @@
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_);
@@ -2862,6 +2978,111 @@
[=](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) {
@@ -2875,104 +3096,45 @@
}
// 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_);
+ 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 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) {
+ 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_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_);
- }
-
- 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) {
- 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;
@@ -2996,6 +3158,34 @@
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();
@@ -3982,6 +4172,45 @@
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 ad14d60..21ae77a 100644
--- a/dex2oat/linker/oat_writer.h
+++ b/dex2oat/linker/oat_writer.h
@@ -244,6 +244,7 @@
}
private:
+ struct BssMappingInfo;
class ChecksumUpdatingOutputStream;
class DexFileSource;
class OatClassHeader;
@@ -307,6 +308,7 @@
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 @@
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 @@
// 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 @@
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 b0ff362..6b2198d 100644
--- a/dex2oat/linker/oat_writer_test.cc
+++ b/dex2oat/linker/oat_writer_test.cc
@@ -502,7 +502,7 @@
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 f8d8128..68eab7c 100644
--- a/oatdump/oatdump.cc
+++ b/oatdump/oatdump.cc
@@ -528,42 +528,48 @@
}
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 @@
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/oat.cc b/runtime/oat.cc
index 3698ddf..64ed14a 100644
--- a/runtime/oat.cc
+++ b/runtime/oat.cc
@@ -71,6 +71,7 @@
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 @@
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 30f7264..e817351 100644
--- a/runtime/oat.h
+++ b/runtime/oat.h
@@ -32,8 +32,8 @@
class PACKED(4) OatHeader {
public:
static constexpr std::array<uint8_t, 4> kOatMagic { { 'o', 'a', 't', '\n' } };
- // Last oat version changed reason: ARM64: Disable implicit suspend checks, again.
- static constexpr std::array<uint8_t, 4> kOatVersion { { '2', '2', '1', '\0' } };
+ // Last oat version changed reason: bss support for inlining BCP into non-BCP.
+ static constexpr std::array<uint8_t, 4> kOatVersion { { '2', '2', '2', '\0' } };
static constexpr const char* kDex2OatCmdLineKey = "dex2oat-cmdline";
static constexpr const char* kDebuggableKey = "debuggable";
@@ -68,6 +68,8 @@
}
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 @@
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.cc b/runtime/oat_file.cc
index c80feaf..b887133 100644
--- a/runtime/oat_file.cc
+++ b/runtime/oat_file.cc
@@ -1002,6 +1002,82 @@
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.
+ 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) {
+ // At runtime, there might be more DexFiles added to the BCP link that we didn't compile with.
+ // We only care about the ones in [0..number_of_bcp_dexfiles_).
+ CHECK_LE(number_of_bcp_dexfiles, linker->GetBootClassPath().size());
+ }
+
+ DCHECK(bcp_bss_info.empty());
+ bcp_bss_info.resize(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 c979c7e..696ca37 100644
--- a/runtime/oat_file.h
+++ b/runtime/oat_file.h
@@ -387,6 +387,16 @@
// 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;
+ };
+
+ std::vector<BssMappingInfo> bcp_bss_info;
+
protected:
OatFile(const std::string& filename, bool executable);