summaryrefslogtreecommitdiff
path: root/compiler/oat_writer.cc
diff options
context:
space:
mode:
author Vladimir Marko <vmarko@google.com> 2017-07-25 13:26:39 +0100
committer Vladimir Marko <vmarko@google.com> 2017-09-07 17:52:35 +0100
commit6cfbdbc359ec5414d3e49f70d28f8c0e65b98d63 (patch)
treef92b309ddc43c2254b6067346a653170fbbf7316 /compiler/oat_writer.cc
parent0f3c7003e08a42a4ed8c9f8dfffb1bee1118de59 (diff)
Use mmapped boot image intern table for PIC app HLoadString.
Implement new HLoadString load kind for boot image strings referenced by PIC-compiled apps (i.e. prebuilts) that uses PC-relative load from a boot image InternTable mmapped into the apps .bss. This reduces the size of the PIC prebuilts that reference boot image strings compared to the kBssEntry as we can completely avoid the slow path and stack map. We separate the InternedStrings and ClassTable sections of the boot image (.art) file from the rest, aligning the start of the InternedStrings section to a page boundary. This may actually increase the size of the boot image file by a page but it also allows mprotecting() these tables as read-only. The ClassTable section is included in anticipation of a similar load kind for HLoadClass. Prebuilt services.odex for aosp_angler-userdebug (arm64): - before: 20862776 - after: 20308512 (-541KiB) Note that 92KiB savings could have been achieved by simply avoiding the read barrier, similar to the HLoadClass flag IsInBootImage(). Such flag is now unnecessary. Test: m test-art-host-gtest Test: testrunner.py --host Test: testrunner.py --host --pictest Test: testrunner.py --target on Nexus 6P. Test: testrunner.py --target --pictest on Nexus 6P. Test: Nexus 6P boots. Bug: 31951624 Change-Id: I5f2bf1fc0bb36a8483244317cfdfa69e192ef6c5
Diffstat (limited to 'compiler/oat_writer.cc')
-rw-r--r--compiler/oat_writer.cc65
1 files changed, 63 insertions, 2 deletions
diff --git a/compiler/oat_writer.cc b/compiler/oat_writer.cc
index 58b6137c7a..a33081e033 100644
--- a/compiler/oat_writer.cc
+++ b/compiler/oat_writer.cc
@@ -335,6 +335,7 @@ OatWriter::OatWriter(bool compiling_boot_image, TimingLogger* timings, ProfileCo
bss_method_entries_(),
bss_type_entries_(),
bss_string_entries_(),
+ map_boot_image_tables_to_bss_(false),
oat_data_offset_(0u),
oat_header_(nullptr),
size_vdex_header_(0),
@@ -771,6 +772,8 @@ class OatWriter::InitBssLayoutMethodVisitor : public DexMethodVisitor {
} else if (patch.GetType() == LinkerPatch::Type::kStringBssEntry) {
StringReference ref(patch.TargetStringDexFile(), patch.TargetStringIndex());
writer_->bss_string_entries_.Overwrite(ref, /* placeholder */ 0u);
+ } else if (patch.GetType() == LinkerPatch::Type::kStringInternTable) {
+ writer_->map_boot_image_tables_to_bss_ = true;
}
}
} else {
@@ -1398,6 +1401,14 @@ class OatWriter::WriteCodeMethodVisitor : public OatDexMethodVisitor {
target_offset);
break;
}
+ case LinkerPatch::Type::kStringInternTable: {
+ uint32_t target_offset = GetInternTableEntryOffset(patch);
+ writer_->relative_patcher_->PatchPcRelativeReference(&patched_code_,
+ patch,
+ offset_ + literal_offset,
+ target_offset);
+ break;
+ }
case LinkerPatch::Type::kStringBssEntry: {
StringReference ref(patch.TargetStringDexFile(), patch.TargetStringIndex());
uint32_t target_offset =
@@ -1535,7 +1546,6 @@ class OatWriter::WriteCodeMethodVisitor : public OatDexMethodVisitor {
}
mirror::String* GetTargetString(const LinkerPatch& patch) REQUIRES_SHARED(Locks::mutator_lock_) {
- ScopedObjectAccessUnchecked soa(Thread::Current());
ClassLinker* linker = Runtime::Current()->GetClassLinker();
mirror::String* string = linker->LookupString(*patch.TargetStringDexFile(),
patch.TargetStringIndex(),
@@ -1603,6 +1613,28 @@ class OatWriter::WriteCodeMethodVisitor : public OatDexMethodVisitor {
data[2] = (address >> 16) & 0xffu;
data[3] = (address >> 24) & 0xffu;
}
+
+ // Calculate the offset of the InternTable slot (GcRoot<String>) when mmapped to the .bss.
+ uint32_t GetInternTableEntryOffset(const LinkerPatch& patch)
+ REQUIRES_SHARED(Locks::mutator_lock_) {
+ DCHECK(!writer_->HasBootImage());
+ const uint8_t* string_root = writer_->LookupBootImageInternTableSlot(
+ *patch.TargetStringDexFile(), patch.TargetStringIndex());
+ DCHECK(string_root != nullptr);
+ uint32_t base_offset = writer_->bss_start_;
+ for (gc::space::ImageSpace* space : Runtime::Current()->GetHeap()->GetBootImageSpaces()) {
+ const uint8_t* const_tables_begin =
+ space->Begin() + space->GetImageHeader().GetBootImageConstantTablesOffset();
+ size_t offset = static_cast<size_t>(string_root - const_tables_begin);
+ if (offset < space->GetImageHeader().GetBootImageConstantTablesSize()) {
+ DCHECK_LE(base_offset + offset, writer_->bss_start_ + writer_->bss_methods_offset_);
+ return base_offset + offset;
+ }
+ base_offset += space->GetImageHeader().GetBootImageConstantTablesSize();
+ }
+ LOG(FATAL) << "Didn't find boot image string in boot image intern tables!";
+ UNREACHABLE();
+ }
};
class OatWriter::WriteMapMethodVisitor : public OatDexMethodVisitor {
@@ -1942,16 +1974,24 @@ void OatWriter::InitBssLayout(InstructionSet instruction_set) {
DCHECK_EQ(bss_size_, 0u);
if (HasBootImage()) {
+ DCHECK(!map_boot_image_tables_to_bss_);
DCHECK(bss_string_entries_.empty());
}
- if (bss_method_entries_.empty() &&
+ if (!map_boot_image_tables_to_bss_ &&
+ bss_method_entries_.empty() &&
bss_type_entries_.empty() &&
bss_string_entries_.empty()) {
// Nothing to put to the .bss section.
return;
}
+ // Allocate space for boot image tables in the .bss section.
PointerSize pointer_size = GetInstructionSetPointerSize(instruction_set);
+ if (map_boot_image_tables_to_bss_) {
+ for (gc::space::ImageSpace* space : Runtime::Current()->GetHeap()->GetBootImageSpaces()) {
+ bss_size_ += space->GetImageHeader().GetBootImageConstantTablesSize();
+ }
+ }
bss_methods_offset_ = bss_size_;
@@ -3500,4 +3540,25 @@ bool OatWriter::OatClass::Write(OatWriter* oat_writer, OutputStream* out) const
return true;
}
+const uint8_t* OatWriter::LookupBootImageInternTableSlot(const DexFile& dex_file,
+ dex::StringIndex string_idx)
+ NO_THREAD_SAFETY_ANALYSIS {
+ // Single-threaded OatWriter can avoid locking.
+ uint32_t utf16_length;
+ const char* utf8_data = dex_file.StringDataAndUtf16LengthByIdx(string_idx, &utf16_length);
+ DCHECK_EQ(utf16_length, CountModifiedUtf8Chars(utf8_data));
+ InternTable::Utf8String string(utf16_length,
+ utf8_data,
+ ComputeUtf16HashFromModifiedUtf8(utf8_data, utf16_length));
+ const InternTable* intern_table = Runtime::Current()->GetClassLinker()->intern_table_;
+ for (const InternTable::Table::UnorderedSet& table : intern_table->strong_interns_.tables_) {
+ auto it = table.Find(string);
+ if (it != table.end()) {
+ return reinterpret_cast<const uint8_t*>(std::addressof(*it));
+ }
+ }
+ LOG(FATAL) << "Did not find boot image string " << utf8_data;
+ UNREACHABLE();
+}
+
} // namespace art