Use mmapped boot image class table for PIC app HLoadClass.
Implement new HLoadClass load kind for boot image classes
referenced by PIC-compiled apps (i.e. prebuilts) that uses
PC-relative load from a boot image ClassTable mmapped into
the apps .bss. This reduces the size of the PIC prebuilts
that reference boot image classes compared to the kBssEntry
as we can completely avoid the slow path and stack map
unless we need to do the class initialization check.
Prebuilt services.odex for aosp_angler-userdebug (arm64):
- before: 20312800
- after: 19775352 (-525KiB)
Test: m test-art-host-gtest
Test: testrunner.py --host
Test: testrunner.py --host --pictest
Test: testrunner.py --target on Nexus 6P.
Test: testrunner.py --target --pictest on Nexus 6P.
Test: Nexus 6P boots.
Bug: 31951624
Change-Id: I13adb19a1fa7d095a72a41f09daa6101876e77a8
diff --git a/compiler/optimizing/code_generator_arm64.cc b/compiler/optimizing/code_generator_arm64.cc
index 1b62868..19e5d06 100644
--- a/compiler/optimizing/code_generator_arm64.cc
+++ b/compiler/optimizing/code_generator_arm64.cc
@@ -21,6 +21,7 @@
#include "art_method.h"
#include "base/bit_utils.h"
#include "base/bit_utils_iterator.h"
+#include "class_table.h"
#include "code_generator_utils.h"
#include "compiled_method.h"
#include "entrypoints/quick/quick_entrypoints.h"
@@ -4784,7 +4785,8 @@
linker_patches);
} else {
DCHECK(pc_relative_method_patches_.empty());
- DCHECK(pc_relative_type_patches_.empty());
+ EmitPcRelativeLinkerPatches<LinkerPatch::TypeClassTablePatch>(pc_relative_type_patches_,
+ linker_patches);
EmitPcRelativeLinkerPatches<LinkerPatch::StringInternTablePatch>(pc_relative_string_patches_,
linker_patches);
}
@@ -4861,6 +4863,7 @@
case HLoadClass::LoadKind::kReferrersClass:
break;
case HLoadClass::LoadKind::kBootImageLinkTimePcRelative:
+ case HLoadClass::LoadKind::kBootImageClassTable:
case HLoadClass::LoadKind::kBssEntry:
DCHECK(!Runtime::Current()->UseJitCompilation());
break;
@@ -4972,6 +4975,25 @@
__ Ldr(out.W(), codegen_->DeduplicateBootImageAddressLiteral(address));
break;
}
+ case HLoadClass::LoadKind::kBootImageClassTable: {
+ DCHECK(!codegen_->GetCompilerOptions().IsBootImage());
+ // Add ADRP with its PC-relative type patch.
+ const DexFile& dex_file = cls->GetDexFile();
+ dex::TypeIndex type_index = cls->GetTypeIndex();
+ vixl::aarch64::Label* adrp_label = codegen_->NewPcRelativeTypePatch(dex_file, type_index);
+ codegen_->EmitAdrpPlaceholder(adrp_label, out.X());
+ // Add LDR with its PC-relative type patch.
+ vixl::aarch64::Label* ldr_label =
+ codegen_->NewPcRelativeTypePatch(dex_file, type_index, adrp_label);
+ codegen_->EmitLdrOffsetPlaceholder(ldr_label, out.W(), out.X());
+ // Extract the reference from the slot data, i.e. clear the hash bits.
+ int32_t masked_hash = ClassTable::TableSlot::MaskHash(
+ ComputeModifiedUtf8Hash(dex_file.StringByTypeIdx(type_index)));
+ if (masked_hash != 0) {
+ __ Sub(out.W(), out.W(), Operand(masked_hash));
+ }
+ break;
+ }
case HLoadClass::LoadKind::kBssEntry: {
// Add ADRP with its PC-relative Class .bss entry patch.
const DexFile& dex_file = cls->GetDexFile();
diff --git a/compiler/optimizing/code_generator_arm_vixl.cc b/compiler/optimizing/code_generator_arm_vixl.cc
index 8288141..8b9495d 100644
--- a/compiler/optimizing/code_generator_arm_vixl.cc
+++ b/compiler/optimizing/code_generator_arm_vixl.cc
@@ -21,6 +21,7 @@
#include "art_method.h"
#include "base/bit_utils.h"
#include "base/bit_utils_iterator.h"
+#include "class_table.h"
#include "code_generator_utils.h"
#include "common_arm.h"
#include "compiled_method.h"
@@ -7122,6 +7123,7 @@
case HLoadClass::LoadKind::kReferrersClass:
break;
case HLoadClass::LoadKind::kBootImageLinkTimePcRelative:
+ case HLoadClass::LoadKind::kBootImageClassTable:
case HLoadClass::LoadKind::kBssEntry:
DCHECK(!Runtime::Current()->UseJitCompilation());
break;
@@ -7234,6 +7236,20 @@
__ Ldr(out, codegen_->DeduplicateBootImageAddressLiteral(address));
break;
}
+ case HLoadClass::LoadKind::kBootImageClassTable: {
+ DCHECK(!codegen_->GetCompilerOptions().IsBootImage());
+ CodeGeneratorARMVIXL::PcRelativePatchInfo* labels =
+ codegen_->NewPcRelativeTypePatch(cls->GetDexFile(), cls->GetTypeIndex());
+ codegen_->EmitMovwMovtPlaceholder(labels, out);
+ __ Ldr(out, MemOperand(out, /* offset */ 0));
+ // Extract the reference from the slot data, i.e. clear the hash bits.
+ int32_t masked_hash = ClassTable::TableSlot::MaskHash(
+ ComputeModifiedUtf8Hash(cls->GetDexFile().StringByTypeIdx(cls->GetTypeIndex())));
+ if (masked_hash != 0) {
+ __ Sub(out, out, Operand(masked_hash));
+ }
+ break;
+ }
case HLoadClass::LoadKind::kBssEntry: {
vixl32::Register temp = (!kUseReadBarrier || kUseBakerReadBarrier)
? RegisterFrom(locations->GetTemp(0))
@@ -9214,7 +9230,8 @@
linker_patches);
} else {
DCHECK(pc_relative_method_patches_.empty());
- DCHECK(pc_relative_type_patches_.empty());
+ EmitPcRelativeLinkerPatches<LinkerPatch::TypeClassTablePatch>(pc_relative_type_patches_,
+ linker_patches);
EmitPcRelativeLinkerPatches<LinkerPatch::StringInternTablePatch>(pc_relative_string_patches_,
linker_patches);
}
diff --git a/compiler/optimizing/code_generator_mips.cc b/compiler/optimizing/code_generator_mips.cc
index ac8f675..f0ef007 100644
--- a/compiler/optimizing/code_generator_mips.cc
+++ b/compiler/optimizing/code_generator_mips.cc
@@ -20,6 +20,7 @@
#include "arch/mips/entrypoints_direct_mips.h"
#include "arch/mips/instruction_set_features_mips.h"
#include "art_method.h"
+#include "class_table.h"
#include "code_generator_utils.h"
#include "compiled_method.h"
#include "entrypoints/quick/quick_entrypoints.h"
@@ -1664,7 +1665,8 @@
linker_patches);
} else {
DCHECK(pc_relative_method_patches_.empty());
- DCHECK(pc_relative_type_patches_.empty());
+ EmitPcRelativeLinkerPatches<LinkerPatch::TypeClassTablePatch>(pc_relative_type_patches_,
+ linker_patches);
EmitPcRelativeLinkerPatches<LinkerPatch::StringInternTablePatch>(pc_relative_string_patches_,
linker_patches);
}
@@ -7413,6 +7415,7 @@
fallback_load = false;
break;
case HLoadClass::LoadKind::kBootImageLinkTimePcRelative:
+ case HLoadClass::LoadKind::kBootImageClassTable:
case HLoadClass::LoadKind::kBssEntry:
DCHECK(!Runtime::Current()->UseJitCompilation());
break;
@@ -7643,6 +7646,7 @@
// We need an extra register for PC-relative literals on R2.
case HLoadClass::LoadKind::kBootImageLinkTimePcRelative:
case HLoadClass::LoadKind::kBootImageAddress:
+ case HLoadClass::LoadKind::kBootImageClassTable:
case HLoadClass::LoadKind::kBssEntry:
if (isR6) {
break;
@@ -7741,6 +7745,24 @@
codegen_->DeduplicateBootImageAddressLiteral(address));
break;
}
+ case HLoadClass::LoadKind::kBootImageClassTable: {
+ DCHECK(!codegen_->GetCompilerOptions().IsBootImage());
+ CodeGeneratorMIPS::PcRelativePatchInfo* info_high =
+ codegen_->NewPcRelativeTypePatch(cls->GetDexFile(), cls->GetTypeIndex());
+ CodeGeneratorMIPS::PcRelativePatchInfo* info_low =
+ codegen_->NewPcRelativeTypePatch(cls->GetDexFile(), cls->GetTypeIndex(), info_high);
+ codegen_->EmitPcRelativeAddressPlaceholderHigh(info_high,
+ out,
+ base_or_current_method_reg);
+ __ Lw(out, out, /* placeholder */ 0x5678, &info_low->label);
+ // Extract the reference from the slot data, i.e. clear the hash bits.
+ int32_t masked_hash = ClassTable::TableSlot::MaskHash(
+ ComputeModifiedUtf8Hash(cls->GetDexFile().StringByTypeIdx(cls->GetTypeIndex())));
+ if (masked_hash != 0) {
+ __ Addiu(out, out, -masked_hash);
+ }
+ break;
+ }
case HLoadClass::LoadKind::kBssEntry: {
bss_info_high = codegen_->NewTypeBssEntryPatch(cls->GetDexFile(), cls->GetTypeIndex());
CodeGeneratorMIPS::PcRelativePatchInfo* info_low =
diff --git a/compiler/optimizing/code_generator_mips64.cc b/compiler/optimizing/code_generator_mips64.cc
index 71c2bff..201b1b0 100644
--- a/compiler/optimizing/code_generator_mips64.cc
+++ b/compiler/optimizing/code_generator_mips64.cc
@@ -18,6 +18,7 @@
#include "arch/mips64/asm_support_mips64.h"
#include "art_method.h"
+#include "class_table.h"
#include "code_generator_utils.h"
#include "compiled_method.h"
#include "entrypoints/quick/quick_entrypoints.h"
@@ -1573,7 +1574,8 @@
linker_patches);
} else {
DCHECK(pc_relative_method_patches_.empty());
- DCHECK(pc_relative_type_patches_.empty());
+ EmitPcRelativeLinkerPatches<LinkerPatch::TypeClassTablePatch>(pc_relative_type_patches_,
+ linker_patches);
EmitPcRelativeLinkerPatches<LinkerPatch::StringInternTablePatch>(pc_relative_string_patches_,
linker_patches);
}
@@ -5767,6 +5769,7 @@
case HLoadClass::LoadKind::kReferrersClass:
break;
case HLoadClass::LoadKind::kBootImageLinkTimePcRelative:
+ case HLoadClass::LoadKind::kBootImageClassTable:
case HLoadClass::LoadKind::kBssEntry:
DCHECK(!Runtime::Current()->UseJitCompilation());
break;
@@ -6016,6 +6019,22 @@
codegen_->DeduplicateBootImageAddressLiteral(address));
break;
}
+ case HLoadClass::LoadKind::kBootImageClassTable: {
+ DCHECK(!codegen_->GetCompilerOptions().IsBootImage());
+ CodeGeneratorMIPS64::PcRelativePatchInfo* info_high =
+ codegen_->NewPcRelativeTypePatch(cls->GetDexFile(), cls->GetTypeIndex());
+ CodeGeneratorMIPS64::PcRelativePatchInfo* info_low =
+ codegen_->NewPcRelativeTypePatch(cls->GetDexFile(), cls->GetTypeIndex(), info_high);
+ codegen_->EmitPcRelativeAddressPlaceholderHigh(info_high, AT, info_low);
+ __ Lwu(out, AT, /* placeholder */ 0x5678);
+ // Extract the reference from the slot data, i.e. clear the hash bits.
+ int32_t masked_hash = ClassTable::TableSlot::MaskHash(
+ ComputeModifiedUtf8Hash(cls->GetDexFile().StringByTypeIdx(cls->GetTypeIndex())));
+ if (masked_hash != 0) {
+ __ Daddiu(out, out, -masked_hash);
+ }
+ break;
+ }
case HLoadClass::LoadKind::kBssEntry: {
bss_info_high = codegen_->NewTypeBssEntryPatch(cls->GetDexFile(), cls->GetTypeIndex());
CodeGeneratorMIPS64::PcRelativePatchInfo* info_low =
diff --git a/compiler/optimizing/code_generator_x86.cc b/compiler/optimizing/code_generator_x86.cc
index 512968f..e45ad0a 100644
--- a/compiler/optimizing/code_generator_x86.cc
+++ b/compiler/optimizing/code_generator_x86.cc
@@ -17,6 +17,7 @@
#include "code_generator_x86.h"
#include "art_method.h"
+#include "class_table.h"
#include "code_generator_utils.h"
#include "compiled_method.h"
#include "entrypoints/quick/quick_entrypoints.h"
@@ -4702,7 +4703,8 @@
EmitPcRelativeLinkerPatches<LinkerPatch::RelativeStringPatch>(string_patches_, linker_patches);
} else {
DCHECK(boot_image_method_patches_.empty());
- DCHECK(boot_image_type_patches_.empty());
+ EmitPcRelativeLinkerPatches<LinkerPatch::TypeClassTablePatch>(boot_image_type_patches_,
+ linker_patches);
EmitPcRelativeLinkerPatches<LinkerPatch::StringInternTablePatch>(string_patches_,
linker_patches);
}
@@ -6038,6 +6040,7 @@
case HLoadClass::LoadKind::kReferrersClass:
break;
case HLoadClass::LoadKind::kBootImageLinkTimePcRelative:
+ case HLoadClass::LoadKind::kBootImageClassTable:
case HLoadClass::LoadKind::kBssEntry:
DCHECK(!Runtime::Current()->UseJitCompilation());
break;
@@ -6075,6 +6078,7 @@
if (load_kind == HLoadClass::LoadKind::kReferrersClass ||
load_kind == HLoadClass::LoadKind::kBootImageLinkTimePcRelative ||
+ load_kind == HLoadClass::LoadKind::kBootImageClassTable ||
load_kind == HLoadClass::LoadKind::kBssEntry) {
locations->SetInAt(0, Location::RequiresRegister());
}
@@ -6151,6 +6155,19 @@
__ movl(out, Immediate(address));
break;
}
+ case HLoadClass::LoadKind::kBootImageClassTable: {
+ DCHECK(!codegen_->GetCompilerOptions().IsBootImage());
+ Register method_address = locations->InAt(0).AsRegister<Register>();
+ __ movl(out, Address(method_address, CodeGeneratorX86::kDummy32BitOffset));
+ codegen_->RecordBootTypePatch(cls);
+ // Extract the reference from the slot data, i.e. clear the hash bits.
+ int32_t masked_hash = ClassTable::TableSlot::MaskHash(
+ ComputeModifiedUtf8Hash(cls->GetDexFile().StringByTypeIdx(cls->GetTypeIndex())));
+ if (masked_hash != 0) {
+ __ subl(out, Immediate(masked_hash));
+ }
+ break;
+ }
case HLoadClass::LoadKind::kBssEntry: {
Register method_address = locations->InAt(0).AsRegister<Register>();
Address address(method_address, CodeGeneratorX86::kDummy32BitOffset);
diff --git a/compiler/optimizing/code_generator_x86_64.cc b/compiler/optimizing/code_generator_x86_64.cc
index 0c3b2ad..8c4374d 100644
--- a/compiler/optimizing/code_generator_x86_64.cc
+++ b/compiler/optimizing/code_generator_x86_64.cc
@@ -17,6 +17,7 @@
#include "code_generator_x86_64.h"
#include "art_method.h"
+#include "class_table.h"
#include "code_generator_utils.h"
#include "compiled_method.h"
#include "entrypoints/quick/quick_entrypoints.h"
@@ -1133,7 +1134,8 @@
EmitPcRelativeLinkerPatches<LinkerPatch::RelativeStringPatch>(string_patches_, linker_patches);
} else {
DCHECK(boot_image_method_patches_.empty());
- DCHECK(boot_image_type_patches_.empty());
+ EmitPcRelativeLinkerPatches<LinkerPatch::TypeClassTablePatch>(boot_image_type_patches_,
+ linker_patches);
EmitPcRelativeLinkerPatches<LinkerPatch::StringInternTablePatch>(string_patches_,
linker_patches);
}
@@ -5456,6 +5458,7 @@
case HLoadClass::LoadKind::kReferrersClass:
break;
case HLoadClass::LoadKind::kBootImageLinkTimePcRelative:
+ case HLoadClass::LoadKind::kBootImageClassTable:
case HLoadClass::LoadKind::kBssEntry:
DCHECK(!Runtime::Current()->UseJitCompilation());
break;
@@ -5564,6 +5567,18 @@
__ movl(out, Immediate(static_cast<int32_t>(address))); // Zero-extended.
break;
}
+ case HLoadClass::LoadKind::kBootImageClassTable: {
+ DCHECK(!codegen_->GetCompilerOptions().IsBootImage());
+ __ movl(out, Address::Absolute(CodeGeneratorX86_64::kDummy32BitOffset, /* no_rip */ false));
+ codegen_->RecordBootTypePatch(cls);
+ // Extract the reference from the slot data, i.e. clear the hash bits.
+ int32_t masked_hash = ClassTable::TableSlot::MaskHash(
+ ComputeModifiedUtf8Hash(cls->GetDexFile().StringByTypeIdx(cls->GetTypeIndex())));
+ if (masked_hash != 0) {
+ __ subl(out, Immediate(masked_hash));
+ }
+ break;
+ }
case HLoadClass::LoadKind::kBssEntry: {
Address address = Address::Absolute(CodeGeneratorX86_64::kDummy32BitOffset,
/* no_rip */ false);
diff --git a/compiler/optimizing/nodes.cc b/compiler/optimizing/nodes.cc
index ebbea27..2a7017c 100644
--- a/compiler/optimizing/nodes.cc
+++ b/compiler/optimizing/nodes.cc
@@ -2736,6 +2736,7 @@
}
switch (GetLoadKind()) {
case LoadKind::kBootImageAddress:
+ case LoadKind::kBootImageClassTable:
case LoadKind::kJitTableAddress: {
ScopedObjectAccess soa(Thread::Current());
return GetClass().Get() == other_load_class->GetClass().Get();
@@ -2769,6 +2770,8 @@
return os << "BootImageLinkTimePcRelative";
case HLoadClass::LoadKind::kBootImageAddress:
return os << "BootImageAddress";
+ case HLoadClass::LoadKind::kBootImageClassTable:
+ return os << "BootImageClassTable";
case HLoadClass::LoadKind::kBssEntry:
return os << "BssEntry";
case HLoadClass::LoadKind::kJitTableAddress:
diff --git a/compiler/optimizing/nodes.h b/compiler/optimizing/nodes.h
index 5e8c771..b551f37 100644
--- a/compiler/optimizing/nodes.h
+++ b/compiler/optimizing/nodes.h
@@ -5675,6 +5675,10 @@
// Used for boot image classes referenced by apps in AOT- and JIT-compiled code.
kBootImageAddress,
+ // Use a PC-relative load from a boot image ClassTable mmapped into the .bss
+ // of the oat file.
+ kBootImageClassTable,
+
// Load from an entry in the .bss section using a PC-relative load.
// Used for classes outside boot image when .bss is accessible with a PC-relative load.
kBssEntry,
@@ -5820,6 +5824,7 @@
static bool HasTypeReference(LoadKind load_kind) {
return load_kind == LoadKind::kReferrersClass ||
load_kind == LoadKind::kBootImageLinkTimePcRelative ||
+ load_kind == LoadKind::kBootImageClassTable ||
load_kind == LoadKind::kBssEntry ||
load_kind == LoadKind::kRuntimeCall;
}
@@ -5853,6 +5858,7 @@
// including literal pool loads, which are PC-relative too.
DCHECK(GetLoadKind() == LoadKind::kBootImageLinkTimePcRelative ||
GetLoadKind() == LoadKind::kBootImageAddress ||
+ GetLoadKind() == LoadKind::kBootImageClassTable ||
GetLoadKind() == LoadKind::kBssEntry) << GetLoadKind();
DCHECK(special_input_.GetInstruction() == nullptr);
special_input_ = HUserRecord<HInstruction*>(special_input);
diff --git a/compiler/optimizing/pc_relative_fixups_mips.cc b/compiler/optimizing/pc_relative_fixups_mips.cc
index 4cb99f9..e569b78 100644
--- a/compiler/optimizing/pc_relative_fixups_mips.cc
+++ b/compiler/optimizing/pc_relative_fixups_mips.cc
@@ -75,6 +75,7 @@
switch (load_kind) {
case HLoadClass::LoadKind::kBootImageLinkTimePcRelative:
case HLoadClass::LoadKind::kBootImageAddress:
+ case HLoadClass::LoadKind::kBootImageClassTable:
case HLoadClass::LoadKind::kBssEntry:
// Add a base register for PC-relative literals on R2.
InitializePCRelativeBasePointer();
diff --git a/compiler/optimizing/pc_relative_fixups_x86.cc b/compiler/optimizing/pc_relative_fixups_x86.cc
index c463ecd..9877e10 100644
--- a/compiler/optimizing/pc_relative_fixups_x86.cc
+++ b/compiler/optimizing/pc_relative_fixups_x86.cc
@@ -83,6 +83,7 @@
void VisitLoadClass(HLoadClass* load_class) OVERRIDE {
HLoadClass::LoadKind load_kind = load_class->GetLoadKind();
if (load_kind == HLoadClass::LoadKind::kBootImageLinkTimePcRelative ||
+ load_kind == HLoadClass::LoadKind::kBootImageClassTable ||
load_kind == HLoadClass::LoadKind::kBssEntry) {
HX86ComputeBaseMethodAddress* method_address = GetPCRelativeBasePointer(load_class);
load_class->AddSpecialInput(method_address);
diff --git a/compiler/optimizing/sharpening.cc b/compiler/optimizing/sharpening.cc
index 1ca63f4..e46c9a7 100644
--- a/compiler/optimizing/sharpening.cc
+++ b/compiler/optimizing/sharpening.cc
@@ -205,11 +205,15 @@
// TODO(ngeoffray): Generate HDeoptimize instead.
desired_load_kind = HLoadClass::LoadKind::kRuntimeCall;
}
- } else if (is_in_boot_image && !codegen->GetCompilerOptions().GetCompilePic()) {
- // AOT app compilation. Check if the class is in the boot image.
- desired_load_kind = HLoadClass::LoadKind::kBootImageAddress;
+ } else if (is_in_boot_image) {
+ // AOT app compilation, boot image class.
+ if (codegen->GetCompilerOptions().GetCompilePic()) {
+ desired_load_kind = HLoadClass::LoadKind::kBootImageClassTable;
+ } else {
+ desired_load_kind = HLoadClass::LoadKind::kBootImageAddress;
+ }
} else {
- // Not JIT and either the klass is not in boot image or we are compiling in PIC mode.
+ // Not JIT and the klass is not in boot image.
desired_load_kind = HLoadClass::LoadKind::kBssEntry;
}
}