Revert^2 "x86_64: Store resolved MethodType-s in .bss."
This reverts commit d014fd019e84471665ac02f2de285541009892cd.
Reason for revert: fix codegen to do runtime call in JIT for now.
Bug: 297147201
Test: ./art/test/testrunner/testrunner.py --host --64 --optimizing -b
Test: ./art/test/testrunner/testrunner.py --jvm -b
Test: ./art/test.py --host -b
Test: ./art/test/testrunner/testrunner.py --host --64 --jit -b
Change-Id: I0f01c8391b09659bb6195955ecd8f88159141872
diff --git a/compiler/linker/linker_patch.h b/compiler/linker/linker_patch.h
index 8ed7fce..1330882 100644
--- a/compiler/linker/linker_patch.h
+++ b/compiler/linker/linker_patch.h
@@ -56,6 +56,7 @@
kPackageTypeBssEntry,
kStringRelative,
kStringBssEntry,
+ kMethodTypeBssEntry,
kCallEntrypoint,
kBakerReadBarrierBranch,
};
@@ -176,6 +177,16 @@
return patch;
}
+ static LinkerPatch MethodTypeBssEntryPatch(size_t literal_offset,
+ const DexFile* target_dex_file,
+ uint32_t pc_insn_offset,
+ uint32_t target_proto_idx) {
+ LinkerPatch patch(literal_offset, Type::kMethodTypeBssEntry, target_dex_file);
+ patch.proto_idx_ = target_proto_idx;
+ patch.pc_insn_offset_ = pc_insn_offset;
+ return patch;
+ }
+
static LinkerPatch CallEntrypointPatch(size_t literal_offset,
uint32_t entrypoint_offset) {
LinkerPatch patch(literal_offset,
@@ -253,6 +264,16 @@
return dex::StringIndex(string_idx_);
}
+ const DexFile* TargetProtoDexFile() const {
+ DCHECK(patch_type_ == Type::kMethodTypeBssEntry);
+ return target_dex_file_;
+ }
+
+ dex::ProtoIndex TargetProtoIndex() const {
+ DCHECK(patch_type_ == Type::kMethodTypeBssEntry);
+ return dex::ProtoIndex(proto_idx_);
+ }
+
uint32_t PcInsnOffset() const {
DCHECK(patch_type_ == Type::kIntrinsicReference ||
patch_type_ == Type::kDataBimgRelRo ||
@@ -305,12 +326,14 @@
uint32_t method_idx_; // Method index for Call/Method patches.
uint32_t type_idx_; // Type index for Type patches.
uint32_t string_idx_; // String index for String patches.
+ uint32_t proto_idx_; // Proto index for MethodType patches.
uint32_t intrinsic_data_; // Data for IntrinsicObjects.
uint32_t entrypoint_offset_; // Entrypoint offset in the Thread object.
uint32_t baker_custom_value1_;
static_assert(sizeof(method_idx_) == sizeof(cmp1_), "needed by relational operators");
static_assert(sizeof(type_idx_) == sizeof(cmp1_), "needed by relational operators");
static_assert(sizeof(string_idx_) == sizeof(cmp1_), "needed by relational operators");
+ static_assert(sizeof(proto_idx_) == sizeof(cmp1_), "needed by relational operators");
static_assert(sizeof(intrinsic_data_) == sizeof(cmp1_), "needed by relational operators");
static_assert(sizeof(baker_custom_value1_) == sizeof(cmp1_), "needed by relational operators");
};
diff --git a/compiler/optimizing/code_generator.cc b/compiler/optimizing/code_generator.cc
index 34400c9..b0e07e3 100644
--- a/compiler/optimizing/code_generator.cc
+++ b/compiler/optimizing/code_generator.cc
@@ -1682,6 +1682,7 @@
instruction->IsArrayGet() ||
instruction->IsArraySet() ||
instruction->IsLoadClass() ||
+ instruction->IsLoadMethodType() ||
instruction->IsLoadString() ||
instruction->IsInstanceOf() ||
instruction->IsCheckCast() ||
diff --git a/compiler/optimizing/code_generator_x86_64.cc b/compiler/optimizing/code_generator_x86_64.cc
index d43d3dd..69fde66 100644
--- a/compiler/optimizing/code_generator_x86_64.cc
+++ b/compiler/optimizing/code_generator_x86_64.cc
@@ -270,6 +270,38 @@
DISALLOW_COPY_AND_ASSIGN(BoundsCheckSlowPathX86_64);
};
+class LoadMethodTypeSlowPathX86_64: public SlowPathCode {
+ public:
+ explicit LoadMethodTypeSlowPathX86_64(HLoadMethodType* mt) : SlowPathCode(mt) {}
+
+ void EmitNativeCode(CodeGenerator* codegen) override {
+ LocationSummary* locations = instruction_->GetLocations();
+ DCHECK(!locations->GetLiveRegisters()->ContainsCoreRegister(locations->Out().reg()));
+
+ CodeGeneratorX86_64* x86_64_codegen = down_cast<CodeGeneratorX86_64*>(codegen);
+ __ Bind(GetEntryLabel());
+ SaveLiveRegisters(codegen, locations);
+
+ const dex::ProtoIndex proto_index = instruction_->AsLoadMethodType()->GetProtoIndex();
+ // Custom calling convention: RAX serves as both input and output.
+ __ movl(CpuRegister(RAX), Immediate(proto_index.index_));
+ x86_64_codegen->InvokeRuntime(kQuickResolveMethodType,
+ instruction_,
+ instruction_->GetDexPc(),
+ this);
+ CheckEntrypointTypes<kQuickResolveMethodType, void*, uint32_t>();
+ x86_64_codegen->Move(locations->Out(), Location::RegisterLocation(RAX));
+ RestoreLiveRegisters(codegen, locations);
+
+ __ jmp(GetExitLabel());
+ }
+
+ const char* GetDescription() const override { return "LoadMethodTypeSlowPathX86_64"; }
+
+ private:
+ DISALLOW_COPY_AND_ASSIGN(LoadMethodTypeSlowPathX86_64);
+};
+
class LoadClassSlowPathX86_64 : public SlowPathCode {
public:
LoadClassSlowPathX86_64(HLoadClass* cls, HInstruction* at)
@@ -529,6 +561,7 @@
instruction_->IsArrayGet() ||
instruction_->IsArraySet() ||
instruction_->IsLoadClass() ||
+ instruction_->IsLoadMethodType() ||
instruction_->IsLoadString() ||
instruction_->IsInstanceOf() ||
instruction_->IsCheckCast() ||
@@ -1319,6 +1352,12 @@
return &string_bss_entry_patches_.back().label;
}
+Label* CodeGeneratorX86_64::NewMethodTypeBssEntryPatch(HLoadMethodType* load_method_type) {
+ method_type_bss_entry_patches_.emplace_back(
+ &load_method_type->GetDexFile(), load_method_type->GetProtoIndex().index_);
+ return &method_type_bss_entry_patches_.back().label;
+}
+
void CodeGeneratorX86_64::RecordBootImageJniEntrypointPatch(HInvokeStaticOrDirect* invoke) {
boot_image_jni_entrypoint_patches_.emplace_back(invoke->GetResolvedMethodReference().dex_file,
invoke->GetResolvedMethodReference().index);
@@ -1406,6 +1445,7 @@
package_type_bss_entry_patches_.size() +
boot_image_string_patches_.size() +
string_bss_entry_patches_.size() +
+ method_type_bss_entry_patches_.size() +
boot_image_jni_entrypoint_patches_.size() +
boot_image_other_patches_.size();
linker_patches->reserve(size);
@@ -1438,6 +1478,8 @@
package_type_bss_entry_patches_, linker_patches);
EmitPcRelativeLinkerPatches<linker::LinkerPatch::StringBssEntryPatch>(
string_bss_entry_patches_, linker_patches);
+ EmitPcRelativeLinkerPatches<linker::LinkerPatch::MethodTypeBssEntryPatch>(
+ method_type_bss_entry_patches_, linker_patches);
EmitPcRelativeLinkerPatches<linker::LinkerPatch::RelativeJniEntrypointPatch>(
boot_image_jni_entrypoint_patches_, linker_patches);
DCHECK_EQ(size, linker_patches->size());
@@ -1562,6 +1604,7 @@
package_type_bss_entry_patches_(graph->GetAllocator()->Adapter(kArenaAllocCodeGenerator)),
boot_image_string_patches_(graph->GetAllocator()->Adapter(kArenaAllocCodeGenerator)),
string_bss_entry_patches_(graph->GetAllocator()->Adapter(kArenaAllocCodeGenerator)),
+ method_type_bss_entry_patches_(graph->GetAllocator()->Adapter(kArenaAllocCodeGenerator)),
boot_image_jni_entrypoint_patches_(graph->GetAllocator()->Adapter(kArenaAllocCodeGenerator)),
boot_image_other_patches_(graph->GetAllocator()->Adapter(kArenaAllocCodeGenerator)),
jit_string_patches_(graph->GetAllocator()->Adapter(kArenaAllocCodeGenerator)),
@@ -6673,13 +6716,50 @@
}
void LocationsBuilderX86_64::VisitLoadMethodType(HLoadMethodType* load) {
- // Custom calling convention: RAX serves as both input and output.
- Location location = Location::RegisterLocation(RAX);
- CodeGenerator::CreateLoadMethodTypeRuntimeCallLocationSummary(load, location, location);
+ LocationSummary* locations =
+ new (GetGraph()->GetAllocator()) LocationSummary(load, LocationSummary::kCallOnSlowPath);
+ if (load->GetLoadKind() == HLoadMethodType::LoadKind::kRuntimeCall) {
+ Location location = Location::RegisterLocation(RAX);
+ CodeGenerator::CreateLoadMethodTypeRuntimeCallLocationSummary(load, location, location);
+ } else {
+ DCHECK_EQ(load->GetLoadKind(), HLoadMethodType::LoadKind::kBssEntry);
+ locations->SetOut(Location::RequiresRegister());
+ if (codegen_->EmitNonBakerReadBarrier()) {
+ // For non-Baker read barrier we have a temp-clobbering call.
+ } else {
+ // Rely on the pResolveMethodType to save everything.
+ locations->SetCustomSlowPathCallerSaves(OneRegInReferenceOutSaveEverythingCallerSaves());
+ }
+ }
}
void InstructionCodeGeneratorX86_64::VisitLoadMethodType(HLoadMethodType* load) {
- codegen_->GenerateLoadMethodTypeRuntimeCall(load);
+ LocationSummary* locations = load->GetLocations();
+ Location out_loc = locations->Out();
+ CpuRegister out = out_loc.AsRegister<CpuRegister>();
+
+ switch (load->GetLoadKind()) {
+ case HLoadMethodType::LoadKind::kBssEntry: {
+ Address address = Address::Absolute(CodeGeneratorX86_64::kPlaceholder32BitOffset,
+ /* no_rip= */ false);
+ Label* fixup_label = codegen_->NewMethodTypeBssEntryPatch(load);
+ // /* GcRoot<mirror::MethodType> */ out = *address /* PC-relative */
+ GenerateGcRootFieldLoad(
+ load, out_loc, address, fixup_label, codegen_->GetCompilerReadBarrierOption());
+ // No need for memory fence, thanks to the x86-64 memory model.
+ SlowPathCode* slow_path =
+ new (codegen_->GetScopedAllocator()) LoadMethodTypeSlowPathX86_64(load);
+ codegen_->AddSlowPath(slow_path);
+ __ testl(out, out);
+ __ j(kEqual, slow_path->GetEntryLabel());
+ __ Bind(slow_path->GetExitLabel());
+ return;
+ }
+ default:
+ DCHECK_EQ(load->GetLoadKind(), HLoadMethodType::LoadKind::kRuntimeCall);
+ codegen_->GenerateLoadMethodTypeRuntimeCall(load);
+ break;
+ }
}
void InstructionCodeGeneratorX86_64::VisitClinitCheck(HClinitCheck* check) {
diff --git a/compiler/optimizing/code_generator_x86_64.h b/compiler/optimizing/code_generator_x86_64.h
index 7da2e39..e4d3eac 100644
--- a/compiler/optimizing/code_generator_x86_64.h
+++ b/compiler/optimizing/code_generator_x86_64.h
@@ -523,6 +523,7 @@
Label* NewTypeBssEntryPatch(HLoadClass* load_class);
void RecordBootImageStringPatch(HLoadString* load_string);
Label* NewStringBssEntryPatch(HLoadString* load_string);
+ Label* NewMethodTypeBssEntryPatch(HLoadMethodType* load_method_type);
void RecordBootImageJniEntrypointPatch(HInvokeStaticOrDirect* invoke);
Label* NewJitRootStringPatch(const DexFile& dex_file,
dex::StringIndex string_index,
@@ -735,6 +736,8 @@
ArenaDeque<PatchInfo<Label>> boot_image_string_patches_;
// PC-relative String patch info for kBssEntry.
ArenaDeque<PatchInfo<Label>> string_bss_entry_patches_;
+ // PC-relative MethodType patch info for kBssEntry.
+ ArenaDeque<PatchInfo<Label>> method_type_bss_entry_patches_;
// PC-relative method patch info for kBootImageLinkTimePcRelative+kCallCriticalNative.
ArenaDeque<PatchInfo<Label>> boot_image_jni_entrypoint_patches_;
// PC-relative patch info for IntrinsicObjects for the boot image,
diff --git a/compiler/optimizing/instruction_builder.cc b/compiler/optimizing/instruction_builder.cc
index 281da6f..fe0f3fe 100644
--- a/compiler/optimizing/instruction_builder.cc
+++ b/compiler/optimizing/instruction_builder.cc
@@ -2699,6 +2699,9 @@
const DexFile& dex_file = *dex_compilation_unit_->GetDexFile();
HLoadMethodType* load_method_type =
new (allocator_) HLoadMethodType(graph_->GetCurrentMethod(), proto_index, dex_file, dex_pc);
+ if (!code_generator_->GetCompilerOptions().IsJitCompiler()) {
+ load_method_type->SetLoadKind(HLoadMethodType::LoadKind::kBssEntry);
+ }
AppendInstruction(load_method_type);
}
diff --git a/compiler/optimizing/nodes.h b/compiler/optimizing/nodes.h
index d84ff7b..0efe8f4 100644
--- a/compiler/optimizing/nodes.h
+++ b/compiler/optimizing/nodes.h
@@ -7313,6 +7313,16 @@
class HLoadMethodType final : public HInstruction {
public:
+ // Determines how to load the MethodType.
+ enum class LoadKind {
+ // Load from an entry in the .bss section using a PC-relative load.
+ kBssEntry,
+ // Load using a single runtime call.
+ kRuntimeCall,
+
+ kLast = kRuntimeCall,
+ };
+
HLoadMethodType(HCurrentMethod* current_method,
dex::ProtoIndex proto_index,
const DexFile& dex_file,
@@ -7324,6 +7334,7 @@
special_input_(HUserRecord<HInstruction*>(current_method)),
proto_index_(proto_index),
dex_file_(dex_file) {
+ SetPackedField<LoadKindField>(LoadKind::kRuntimeCall);
}
using HInstruction::GetInputRecords; // Keep the const version visible.
@@ -7334,6 +7345,12 @@
bool IsClonable() const override { return true; }
+ void SetLoadKind(LoadKind load_kind);
+
+ LoadKind GetLoadKind() const {
+ return GetPackedField<LoadKindField>();
+ }
+
dex::ProtoIndex GetProtoIndex() const { return proto_index_; }
const DexFile& GetDexFile() const { return dex_file_; }
@@ -7352,6 +7369,14 @@
DEFAULT_COPY_CONSTRUCTOR(LoadMethodType);
private:
+ static constexpr size_t kFieldLoadKind = kNumberOfGenericPackedBits;
+ static constexpr size_t kFieldLoadKindSize =
+ MinimumBitsToStore(static_cast<size_t>(LoadKind::kLast));
+ static constexpr size_t kNumberOfLoadMethodTypePackedBits = kFieldLoadKind + kFieldLoadKindSize;
+ static_assert(kNumberOfLoadMethodTypePackedBits <= kMaxNumberOfPackedBits,
+ "Too many packed fields.");
+ using LoadKindField = BitField<LoadKind, kFieldLoadKind, kFieldLoadKindSize>;
+
// The special input is the HCurrentMethod for kRuntimeCall.
HUserRecord<HInstruction*> special_input_;
@@ -7359,6 +7384,17 @@
const DexFile& dex_file_;
};
+std::ostream& operator<<(std::ostream& os, HLoadMethodType::LoadKind rhs);
+
+// Note: defined outside class to see operator<<(., HLoadMethodType::LoadKind).
+inline void HLoadMethodType::SetLoadKind(LoadKind load_kind) {
+ // The load kind should be determined before inserting the instruction to the graph.
+ DCHECK(GetBlock() == nullptr);
+ DCHECK(GetEnvironment() == nullptr);
+ DCHECK_EQ(GetLoadKind(), LoadKind::kRuntimeCall);
+ SetPackedField<LoadKindField>(load_kind);
+}
+
/**
* Performs an initialization check on its Class object input.
*/
diff --git a/dex2oat/linker/arm64/relative_patcher_arm64.cc b/dex2oat/linker/arm64/relative_patcher_arm64.cc
index 0c34cb8..db7ae74 100644
--- a/dex2oat/linker/arm64/relative_patcher_arm64.cc
+++ b/dex2oat/linker/arm64/relative_patcher_arm64.cc
@@ -71,6 +71,7 @@
case LinkerPatch::Type::kPackageTypeBssEntry:
case LinkerPatch::Type::kStringRelative:
case LinkerPatch::Type::kStringBssEntry:
+ case LinkerPatch::Type::kMethodTypeBssEntry:
return patch.LiteralOffset() == patch.PcInsnOffset();
}
}
diff --git a/dex2oat/linker/oat_writer.cc b/dex2oat/linker/oat_writer.cc
index f85d817..1564d50 100644
--- a/dex2oat/linker/oat_writer.cc
+++ b/dex2oat/linker/oat_writer.cc
@@ -47,6 +47,7 @@
#include "dex/dex_file_loader.h"
#include "dex/dex_file_types.h"
#include "dex/dex_file_verifier.h"
+#include "dex/proto_reference.h"
#include "dex/standard_dex_file.h"
#include "dex/type_lookup_table.h"
#include "dex/verification_results.h"
@@ -296,6 +297,7 @@
uint32_t public_type_bss_mapping_offset_;
uint32_t package_type_bss_mapping_offset_;
uint32_t string_bss_mapping_offset_;
+ uint32_t method_type_bss_mapping_offset_;
// Offset of dex sections that will have different runtime madvise states.
// Set in WriteDexLayoutSections.
@@ -357,6 +359,7 @@
bss_public_type_entries_(),
bss_package_type_entries_(),
bss_string_entries_(),
+ bss_method_type_entries_(),
oat_data_offset_(0u),
oat_header_(nullptr),
relative_patcher_(nullptr),
@@ -750,6 +753,12 @@
target_string.dex_file->NumStringIds(),
&writer_->bss_string_entry_references_);
writer_->bss_string_entries_.Overwrite(target_string, /* placeholder */ 0u);
+ } else if (patch.GetType() == LinkerPatch::Type::kMethodTypeBssEntry) {
+ ProtoReference target_proto(patch.TargetProtoDexFile(), patch.TargetProtoIndex());
+ AddBssReference(target_proto,
+ target_proto.dex_file->NumProtoIds(),
+ &writer_->bss_method_type_entry_references_);
+ writer_->bss_method_type_entries_.Overwrite(target_proto, /* placeholder */ 0u);
}
}
} else {
@@ -869,6 +878,7 @@
uint32_t public_type_bss_mapping_offset = 0u;
uint32_t package_type_bss_mapping_offset = 0u;
uint32_t string_bss_mapping_offset = 0u;
+ uint32_t method_type_bss_mapping_offset = 0u;
// Offset of the BSSInfo start from beginning of OatHeader. It is used to validate file position
// when writing.
@@ -879,7 +889,8 @@
sizeof(type_bss_mapping_offset) +
sizeof(public_type_bss_mapping_offset) +
sizeof(package_type_bss_mapping_offset) +
- sizeof(string_bss_mapping_offset);
+ sizeof(string_bss_mapping_offset) +
+ sizeof(method_type_bss_mapping_offset);
}
bool Write(OatWriter* oat_writer, OutputStream* out) const;
};
@@ -1684,6 +1695,16 @@
target_offset);
break;
}
+ case LinkerPatch::Type::kMethodTypeBssEntry: {
+ ProtoReference ref(patch.TargetProtoDexFile(), patch.TargetProtoIndex());
+ uint32_t target_offset =
+ writer_->bss_start_ + writer_->bss_method_type_entries_.Get(ref);
+ writer_->relative_patcher_->PatchPcRelativeReference(&patched_code_,
+ patch,
+ offset_ + literal_offset,
+ target_offset);
+ break;
+ }
case LinkerPatch::Type::kTypeRelative: {
uint32_t target_offset = GetTargetObjectOffset(GetTargetType(patch));
writer_->relative_patcher_->PatchPcRelativeReference(&patched_code_,
@@ -2038,7 +2059,8 @@
bss_type_entry_references_.empty() &&
bss_public_type_entry_references_.empty() &&
bss_package_type_entry_references_.empty() &&
- bss_string_entry_references_.empty()) {
+ bss_string_entry_references_.empty() &&
+ bss_method_type_entry_references_.empty()) {
return offset;
}
// If there are any classes, the class offsets allocation aligns the offset
@@ -2051,6 +2073,7 @@
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;
+ size_t number_of_method_type_dex_files = 0u;
for (size_t i = 0, size = dex_files_->size(); i != size; ++i) {
const DexFile* dex_file = (*dex_files_)[i];
offset = InitIndexBssMappingsHelper(offset,
@@ -2060,11 +2083,13 @@
number_of_public_type_dex_files,
number_of_package_type_dex_files,
number_of_string_dex_files,
+ number_of_method_type_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_);
+ oat_dex_files_[i].string_bss_mapping_offset_,
+ oat_dex_files_[i].method_type_bss_mapping_offset_);
}
if (!(compiler_options_.IsBootImage() || compiler_options_.IsBootImageExtension())) {
@@ -2086,11 +2111,13 @@
number_of_public_type_dex_files,
number_of_package_type_dex_files,
number_of_string_dex_files,
+ number_of_method_type_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);
+ bcp_bss_info_[i].string_bss_mapping_offset,
+ bcp_bss_info_[i].method_type_bss_mapping_offset);
}
}
@@ -2101,6 +2128,7 @@
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());
+ CHECK_EQ(number_of_method_type_dex_files, bss_method_type_entry_references_.size());
return offset;
}
@@ -2112,11 +2140,13 @@
/*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*/ size_t& number_of_method_type_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) {
+ /*inout*/ uint32_t& string_bss_mapping_offset,
+ /*inout*/ uint32_t& method_type_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()) {
@@ -2168,6 +2198,21 @@
return bss_string_entries_.Get({dex_file, dex::StringIndex(index)});
});
}
+
+ auto method_type_it = bss_method_type_entry_references_.find(dex_file);
+ if (method_type_it != bss_method_type_entry_references_.end()) {
+ const BitVector& proto_indexes = method_type_it->second;
+ ++number_of_method_type_dex_files;
+ method_type_bss_mapping_offset = offset;
+ offset += CalculateIndexBssMappingSize(
+ dex_file->NumProtoIds(),
+ sizeof(GcRoot<mirror::MethodType>),
+ proto_indexes,
+ [=](uint32_t index) {
+ return bss_method_type_entries_.Get({dex_file, dex::ProtoIndex(index)});
+ });
+ }
+
return offset;
}
@@ -2339,7 +2384,8 @@
bss_type_entries_.empty() &&
bss_public_type_entries_.empty() &&
bss_package_type_entries_.empty() &&
- bss_string_entries_.empty()) {
+ bss_string_entries_.empty() &&
+ bss_method_type_entries_.empty()) {
// Nothing to put to the .bss section.
return;
}
@@ -2380,6 +2426,12 @@
entry.second = bss_size_;
bss_size_ += sizeof(GcRoot<mirror::String>);
}
+ // Prepare offsets for .bss MethodType entries.
+ for (auto& entry : bss_method_type_entries_) {
+ DCHECK_EQ(entry.second, 0u);
+ entry.second = bss_size_;
+ bss_size_ += sizeof(GcRoot<mirror::MethodType>);
+ }
}
bool OatWriter::WriteRodata(OutputStream* out) {
@@ -2599,12 +2651,14 @@
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_oat_dex_file_method_type_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_bcp_bss_info_method_type_bss_mapping_offset_);
DO_STAT(size_oat_class_offsets_alignment_);
DO_STAT(size_oat_class_offsets_);
DO_STAT(size_oat_class_type_);
@@ -2617,6 +2671,7 @@
DO_STAT(size_public_type_bss_mappings_);
DO_STAT(size_package_type_bss_mappings_);
DO_STAT(size_string_bss_mappings_);
+ DO_STAT(size_method_type_bss_mappings_);
#undef DO_STAT
VLOG(compiler) << "size_total=" << PrettySize(size_total) << " (" << size_total << "B)";
@@ -2802,7 +2857,8 @@
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) {
+ uint32_t string_bss_mapping_offset,
+ uint32_t method_type_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()) {
@@ -2896,6 +2952,29 @@
DCHECK_EQ(0u, string_bss_mapping_offset);
}
+ auto method_type_it = bss_method_type_entry_references_.find(dex_file);
+ if (method_type_it != bss_method_type_entry_references_.end()) {
+ const BitVector& method_type_indexes = method_type_it->second;
+ DCHECK_EQ(relative_offset, method_type_bss_mapping_offset);
+ DCHECK_OFFSET();
+ size_t method_type_mappings_size =
+ WriteIndexBssMapping(out,
+ dex_file->NumProtoIds(),
+ sizeof(GcRoot<mirror::MethodType>),
+ method_type_indexes,
+ [=](uint32_t index) {
+ return bss_method_type_entries_
+ .Get({dex_file, dex::ProtoIndex(index)});
+ });
+ if (method_type_mappings_size == 0u) {
+ return 0u;
+ }
+ size_method_type_bss_mappings_ += method_type_mappings_size;
+ relative_offset += method_type_mappings_size;
+ } else {
+ DCHECK_EQ(0u, method_type_bss_mapping_offset);
+ }
+
return relative_offset;
}
@@ -2907,7 +2986,8 @@
bss_type_entry_references_.empty() &&
bss_public_type_entry_references_.empty() &&
bss_package_type_entry_references_.empty() &&
- bss_string_entry_references_.empty()) {
+ bss_string_entry_references_.empty() &&
+ bss_method_type_entry_references_.empty()) {
return relative_offset;
}
// If there are any classes, the class offsets allocation aligns the offset
@@ -2926,7 +3006,8 @@
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_);
+ oat_dex_file->string_bss_mapping_offset_,
+ oat_dex_file->method_type_bss_mapping_offset_);
if (relative_offset == 0u) {
return 0u;
}
@@ -2947,7 +3028,8 @@
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);
+ bcp_bss_info_[i].string_bss_mapping_offset,
+ bcp_bss_info_[i].method_type_bss_mapping_offset);
if (relative_offset == 0u) {
return 0u;
}
@@ -3782,6 +3864,7 @@
public_type_bss_mapping_offset_(0u),
package_type_bss_mapping_offset_(0u),
string_bss_mapping_offset_(0u),
+ method_type_bss_mapping_offset_(0u),
dex_sections_layout_offset_(0u),
class_offsets_() {}
@@ -3791,7 +3874,8 @@
sizeof(class_offsets_offset_) + sizeof(lookup_table_offset_) +
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_) + sizeof(dex_sections_layout_offset_);
+ sizeof(string_bss_mapping_offset_) + sizeof(method_type_bss_mapping_offset_) +
+ sizeof(dex_sections_layout_offset_);
}
bool OatWriter::OatDexFile::Write(OatWriter* oat_writer, OutputStream* out) const {
@@ -3885,6 +3969,13 @@
}
oat_writer->size_oat_dex_file_string_bss_mapping_offset_ += sizeof(string_bss_mapping_offset_);
+ if (!out->WriteFully(&method_type_bss_mapping_offset_, sizeof(method_type_bss_mapping_offset_))) {
+ PLOG(ERROR) << "Failed to write MethodType bss mapping offset to " << out->GetLocation();
+ return false;
+ }
+ oat_writer->size_oat_dex_file_method_type_bss_mapping_offset_ +=
+ sizeof(method_type_bss_mapping_offset_);
+
return true;
}
@@ -3924,6 +4015,13 @@
}
oat_writer->size_bcp_bss_info_string_bss_mapping_offset_ += sizeof(string_bss_mapping_offset);
+ if (!out->WriteFully(&method_type_bss_mapping_offset, sizeof(method_type_bss_mapping_offset))) {
+ PLOG(ERROR) << "Failed to write method type bss mapping offset to " << out->GetLocation();
+ return false;
+ }
+ oat_writer->size_bcp_bss_info_method_type_bss_mapping_offset_ +=
+ sizeof(method_type_bss_mapping_offset);
+
return true;
}
diff --git a/dex2oat/linker/oat_writer.h b/dex2oat/linker/oat_writer.h
index 5b66950..9d83bcb 100644
--- a/dex2oat/linker/oat_writer.h
+++ b/dex2oat/linker/oat_writer.h
@@ -32,6 +32,7 @@
#include "dex/compact_dex_level.h"
#include "dex/method_reference.h"
#include "dex/string_reference.h"
+#include "dex/proto_reference.h"
#include "dex/type_reference.h"
#include "linker/relative_patcher.h" // For RelativePatcherTargetProvider.
#include "mirror/class.h"
@@ -321,7 +322,8 @@
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);
+ uint32_t string_bss_mapping_offset,
+ uint32_t method_type_bss_mapping_offset);
size_t InitIndexBssMappingsHelper(size_t offset,
const DexFile* dex_file,
/*inout*/ size_t& number_of_method_dex_files,
@@ -329,11 +331,13 @@
/*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*/ size_t& number_of_method_type_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);
+ /*inout*/ uint32_t& string_bss_mapping_offset,
+ /*inout*/ uint32_t& method_type_bss_mapping_offset);
bool RecordOatDataOffset(OutputStream* out);
void InitializeTypeLookupTables(
@@ -449,6 +453,9 @@
// Map for recording references to GcRoot<mirror::String> entries in .bss.
SafeMap<const DexFile*, BitVector> bss_string_entry_references_;
+ // Map for recording references to GcRoot<mirror::MethodType> entries in .bss.
+ SafeMap<const DexFile*, BitVector> bss_method_type_entry_references_;
+
// Map for allocating ArtMethod entries in .bss. Indexed by MethodReference for the target
// method in the dex file with the "method reference value comparator" for deduplication.
// The value is the target offset for patching, starting at `bss_start_ + bss_methods_offset_`.
@@ -474,6 +481,11 @@
// is the target offset for patching, starting at `bss_start_ + bss_roots_offset_`.
SafeMap<StringReference, size_t, StringReferenceValueComparator> bss_string_entries_;
+ // Map for allocating MethodType entries in .bss. Indexed by ProtoReference for the source
+ // proto in the dex file with the "proto value comparator" for deduplication. The value
+ // is the target offset for patching, starting at `bss_start_ + bss_roots_offset_`.
+ SafeMap<ProtoReference, size_t, ProtoReferenceValueComparator> bss_method_type_entries_;
+
// Offset of the oat data from the start of the mmapped region of the elf file.
size_t oat_data_offset_;
@@ -540,12 +552,14 @@
uint32_t size_oat_dex_file_public_type_bss_mapping_offset_ = 0;
uint32_t size_oat_dex_file_package_type_bss_mapping_offset_ = 0;
uint32_t size_oat_dex_file_string_bss_mapping_offset_ = 0;
+ uint32_t size_oat_dex_file_method_type_bss_mapping_offset_ = 0;
uint32_t size_bcp_bss_info_size_ = 0;
uint32_t size_bcp_bss_info_method_bss_mapping_offset_ = 0;
uint32_t size_bcp_bss_info_type_bss_mapping_offset_ = 0;
uint32_t size_bcp_bss_info_public_type_bss_mapping_offset_ = 0;
uint32_t size_bcp_bss_info_package_type_bss_mapping_offset_ = 0;
uint32_t size_bcp_bss_info_string_bss_mapping_offset_ = 0;
+ uint32_t size_bcp_bss_info_method_type_bss_mapping_offset_ = 0;
uint32_t size_oat_class_offsets_alignment_ = 0;
uint32_t size_oat_class_offsets_ = 0;
uint32_t size_oat_class_type_ = 0;
@@ -558,6 +572,7 @@
uint32_t size_public_type_bss_mappings_ = 0;
uint32_t size_package_type_bss_mappings_ = 0;
uint32_t size_string_bss_mappings_ = 0;
+ uint32_t size_method_type_bss_mappings_ = 0;
// The helper for processing relative patches is external so that we can patch across oat files.
MultiOatRelativePatcher* relative_patcher_;
diff --git a/libdexfile/Android.bp b/libdexfile/Android.bp
index ce70a20..ad528c1 100644
--- a/libdexfile/Android.bp
+++ b/libdexfile/Android.bp
@@ -293,6 +293,7 @@
"dex/dex_instruction_test.cc",
"dex/fuzzer_corpus_test.cc",
"dex/primitive_test.cc",
+ "dex/proto_reference_test.cc",
"dex/string_reference_test.cc",
"dex/test_dex_file_builder_test.cc",
"dex/type_lookup_table_test.cc",
diff --git a/libdexfile/dex/method_reference.h b/libdexfile/dex/method_reference.h
index f66ac30..9d4eabe 100644
--- a/libdexfile/dex/method_reference.h
+++ b/libdexfile/dex/method_reference.h
@@ -21,6 +21,7 @@
#include <string>
#include "dex/dex_file.h"
#include "dex/dex_file_reference.h"
+#include "dex/proto_reference.h"
namespace art {
@@ -34,6 +35,9 @@
const dex::MethodId& GetMethodId() const {
return dex_file->GetMethodId(index);
}
+ const art::ProtoReference GetProtoReference() const {
+ return ProtoReference(dex_file, GetMethodId().proto_idx_);
+ }
};
// Compare the actual referenced method signatures. Used for method reference deduplication.
@@ -62,27 +66,8 @@
if (name_diff != 0) {
return name_diff < 0;
}
- // And then compare proto ids, starting with return type comparison.
- const dex::ProtoId& prid1 = mr1.dex_file->GetProtoId(mid1.proto_idx_);
- const dex::ProtoId& prid2 = mr2.dex_file->GetProtoId(mid2.proto_idx_);
- int return_type_diff = strcmp(mr1.dex_file->StringByTypeIdx(prid1.return_type_idx_),
- mr2.dex_file->StringByTypeIdx(prid2.return_type_idx_));
- if (return_type_diff != 0) {
- return return_type_diff < 0;
- }
- // And finishing with lexicographical parameter comparison.
- const dex::TypeList* params1 = mr1.dex_file->GetProtoParameters(prid1);
- size_t param1_size = (params1 != nullptr) ? params1->Size() : 0u;
- const dex::TypeList* params2 = mr2.dex_file->GetProtoParameters(prid2);
- size_t param2_size = (params2 != nullptr) ? params2->Size() : 0u;
- for (size_t i = 0, num = std::min(param1_size, param2_size); i != num; ++i) {
- int param_diff = strcmp(mr1.dex_file->StringByTypeIdx(params1->GetTypeItem(i).type_idx_),
- mr2.dex_file->StringByTypeIdx(params2->GetTypeItem(i).type_idx_));
- if (param_diff != 0) {
- return param_diff < 0;
- }
- }
- return param1_size < param2_size;
+ // Then compare protos.
+ return ProtoReferenceValueComparator()(mr1.GetProtoReference(), mr2.GetProtoReference());
}
};
diff --git a/libdexfile/dex/proto_reference.h b/libdexfile/dex/proto_reference.h
new file mode 100644
index 0000000..dc9a447
--- /dev/null
+++ b/libdexfile/dex/proto_reference.h
@@ -0,0 +1,91 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef ART_LIBDEXFILE_DEX_PROTO_REFERENCE_H_
+#define ART_LIBDEXFILE_DEX_PROTO_REFERENCE_H_
+
+#include <stdint.h>
+
+#include <android-base/logging.h>
+#include <string_view>
+
+#include "dex/dex_file-inl.h"
+#include "dex/dex_file_reference.h"
+#include "dex/dex_file_types.h"
+
+namespace art {
+
+// A proto is located by its DexFile and the proto_ids_ table index into that DexFile.
+class ProtoReference : public DexFileReference {
+ public:
+ ProtoReference(const DexFile* file, dex::ProtoIndex index)
+ : DexFileReference(file, index.index_) {}
+
+ dex::ProtoIndex ProtoIndex() const {
+ return dex::ProtoIndex(index);
+ }
+
+ const dex::ProtoId& ProtoId() const {
+ return dex_file->GetProtoId(ProtoIndex());
+ }
+
+ std::string_view ReturnType() const {
+ return dex_file->GetTypeDescriptorView(dex_file->GetTypeId(ProtoId().return_type_idx_));
+ }
+};
+
+struct ProtoReferenceValueComparator {
+ bool operator()(const ProtoReference& lhs, const ProtoReference& rhs) const {
+ if (lhs.dex_file == rhs.dex_file) {
+ DCHECK_EQ(lhs.index < rhs.index, SlowCompare(lhs, rhs));
+
+ return lhs.index < rhs.index;
+ } else {
+ return SlowCompare(lhs, rhs);
+ }
+ }
+
+ bool SlowCompare(const ProtoReference& lhs, const ProtoReference& rhs) const {
+ // Compare return type first.
+ const dex::ProtoId& prid1 = lhs.ProtoId();
+ const dex::ProtoId& prid2 = rhs.ProtoId();
+ int return_type_diff = lhs.ReturnType().compare(rhs.ReturnType());
+ if (return_type_diff != 0) {
+ return return_type_diff < 0;
+ }
+ // And then compare parameters lexicographically.
+ const dex::TypeList* params1 = lhs.dex_file->GetProtoParameters(prid1);
+ size_t param1_size = (params1 != nullptr) ? params1->Size() : 0u;
+ const dex::TypeList* params2 = rhs.dex_file->GetProtoParameters(prid2);
+ size_t param2_size = (params2 != nullptr) ? params2->Size() : 0u;
+ for (size_t i = 0, num = std::min(param1_size, param2_size); i != num; ++i) {
+ std::string_view l_param = lhs.dex_file->GetTypeDescriptorView(
+ lhs.dex_file->GetTypeId(params1->GetTypeItem(i).type_idx_));
+ std::string_view r_param = rhs.dex_file->GetTypeDescriptorView(
+ rhs.dex_file->GetTypeId(params2->GetTypeItem(i).type_idx_));
+
+ int param_diff = l_param.compare(r_param);
+ if (param_diff != 0) {
+ return param_diff < 0;
+ }
+ }
+ return param1_size < param2_size;
+ }
+};
+
+} // namespace art
+
+#endif // ART_LIBDEXFILE_DEX_PROTO_REFERENCE_H_
diff --git a/libdexfile/dex/proto_reference_test.cc b/libdexfile/dex/proto_reference_test.cc
new file mode 100644
index 0000000..f24106d
--- /dev/null
+++ b/libdexfile/dex/proto_reference_test.cc
@@ -0,0 +1,100 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "dex/proto_reference.h"
+#include <vector>
+
+#include "dex/dex_file_types.h"
+#include "dex/test_dex_file_builder.h"
+#include "gtest/gtest.h"
+
+namespace art {
+
+TEST(ProtoReference, WithinOneDexFile) {
+ TestDexFileBuilder builder;
+ builder.AddMethod("LClass", "()I", "sideEffect2");
+ builder.AddMethod("LClass", "(I)Ljava/lang/String;", "toString");
+ builder.AddMethod("LClass", "(II)Ljava/lang/String;", "toString");
+ builder.AddMethod("LClass", "(IJ)Ljava/lang/String;", "toString");
+ builder.AddMethod("LClass", "(JJ)Ljava/lang/String;", "toString");
+ builder.AddMethod("LClass", "()V", "sideEffect1");
+
+ std::unique_ptr<const DexFile> dex_file = builder.Build("fake location");
+ const size_t num_protos = 6u;
+ EXPECT_EQ(num_protos, dex_file->NumProtoIds());
+
+ std::vector<ProtoReference> protos;
+
+ for (size_t i = 0; i < num_protos; ++i) {
+ protos.emplace_back(ProtoReference(dex_file.get(), dex::ProtoIndex(i)));
+ }
+
+ ProtoReferenceValueComparator cmp;
+ for (size_t i = 0; i < num_protos; ++i) {
+ for (size_t j = 0; j < num_protos; ++j) {
+ EXPECT_EQ(cmp(protos[i], protos[j]), i < j)
+ << "Inconsistent at i=" << i << " and j=" << j;
+ }
+ }
+}
+
+TEST(ProtoReference, AcrossDifferentDexFiles) {
+ TestDexFileBuilder builder1;
+ builder1.AddMethod("LClass", "()I", "sideEffect2");
+ builder1.AddMethod("LClass", "(I)Ljava/lang/String;", "toString");
+ builder1.AddMethod("LClass", "(II)Ljava/lang/String;", "toString");
+ builder1.AddMethod("LClass", "(IJ)Ljava/lang/String;", "toString");
+ builder1.AddMethod("LClass", "(IJZ)Ljava/lang/String;", "toString");
+ builder1.AddMethod("LClass", "()V", "sideEffect1");
+
+ std::unique_ptr<const DexFile> dex_file1 = builder1.Build("fake location");
+ EXPECT_EQ(6u, dex_file1->NumProtoIds());
+
+ TestDexFileBuilder builder2;
+ builder2.AddMethod("LClass2", "(IJ)Ljava/lang/String;", "toString");
+ builder2.AddMethod("LClass2", "()V", "sideEffect1");
+ builder2.AddMethod("LClass2", "(I)V", "sideEffect2");
+
+ std::unique_ptr<const DexFile> dex_file2 = builder2.Build("fake location 2");
+ EXPECT_EQ(3u, dex_file2->NumProtoIds());
+
+ ProtoReference V_dex1 = ProtoReference(dex_file1.get(), dex::ProtoIndex(5));
+ ProtoReference V_dex2 = ProtoReference(dex_file2.get(), dex::ProtoIndex(1));
+
+ ProtoReferenceValueComparator cmp;
+
+ EXPECT_FALSE(cmp(V_dex1, V_dex2));
+ EXPECT_FALSE(cmp(V_dex2, V_dex1));
+
+ ProtoReference IString_dex1 = ProtoReference(dex_file1.get(), dex::ProtoIndex(1));
+ ProtoReference IIString_dex1 = ProtoReference(dex_file1.get(), dex::ProtoIndex(2));
+ ProtoReference IJString_dex1 = ProtoReference(dex_file1.get(), dex::ProtoIndex(3));
+ ProtoReference IJZString_dex1 = ProtoReference(dex_file1.get(), dex::ProtoIndex(4));
+
+ ProtoReference IJString_dex2 = ProtoReference(dex_file2.get(), dex::ProtoIndex(0));
+
+ EXPECT_TRUE(cmp(IString_dex1, V_dex2));
+
+ EXPECT_TRUE(cmp(IString_dex1, IJString_dex2));
+ EXPECT_TRUE(cmp(IIString_dex1, IJString_dex2));
+ EXPECT_FALSE(cmp(IJString_dex1, IJString_dex2));
+ EXPECT_FALSE(cmp(IJString_dex2, IJString_dex1));
+ EXPECT_FALSE(cmp(IJZString_dex1, IJString_dex2));
+
+ EXPECT_TRUE(cmp(IJString_dex2, IJZString_dex1));
+}
+
+} // namespace art
diff --git a/runtime/entrypoints/quick/quick_dexcache_entrypoints.cc b/runtime/entrypoints/quick/quick_dexcache_entrypoints.cc
index 76bee21..9973d1a 100644
--- a/runtime/entrypoints/quick/quick_dexcache_entrypoints.cc
+++ b/runtime/entrypoints/quick/quick_dexcache_entrypoints.cc
@@ -162,13 +162,51 @@
// 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>));
+ mapping, string_idx.index_, dex_file->NumStringIds(), sizeof(GcRoot<mirror::String>));
if (bss_offset != IndexBssMappingLookup::npos) {
StoreObjectInBss(outer_method, outer_oat_file, bss_offset, resolved_string);
}
}
}
+static inline void StoreMethodTypeInBss(ArtMethod* caller,
+ dex::ProtoIndex proto_idx,
+ ObjPtr<mirror::MethodType> resolved_method_type,
+ ArtMethod* outer_method)
+ REQUIRES_SHARED(Locks::mutator_lock_) {
+ const DexFile* dex_file = caller->GetDexFile();
+ 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();
+ 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->GetMethodTypeBssMapping();
+ } 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_type_bss_mapping;
+ }
+ }
+
+ // Perform the update if we found a mapping.
+ if (mapping != nullptr) {
+ size_t bss_offset = IndexBssMappingLookup::GetBssOffset(
+ mapping, proto_idx.index_, dex_file->NumProtoIds(), sizeof(GcRoot<mirror::MethodType>));
+ if (bss_offset != IndexBssMappingLookup::npos) {
+ StoreObjectInBss(outer_method, outer_oat_file, bss_offset, resolved_method_type);
+ }
+ }
+}
+
extern "C" mirror::Class* artInitializeStaticStorageFromCode(mirror::Class* klass, Thread* self)
REQUIRES_SHARED(Locks::mutator_lock_) {
// Called to ensure static storage base is initialized for direct static field reads and writes.
@@ -243,6 +281,10 @@
CalleeSaveType::kSaveEverything);
ArtMethod* caller = caller_and_outer.caller;
ObjPtr<mirror::MethodType> result = ResolveMethodTypeFromCode(caller, dex::ProtoIndex(proto_idx));
+ ArtMethod* outer_method = caller_and_outer.outer_method;
+ if (LIKELY(result != nullptr)) {
+ StoreMethodTypeInBss(caller, dex::ProtoIndex(proto_idx), result, outer_method);
+ }
return result.Ptr();
}
diff --git a/runtime/oat.h b/runtime/oat.h
index 48b7c5f..7ea97fd 100644
--- a/runtime/oat.h
+++ b/runtime/oat.h
@@ -44,8 +44,8 @@
class PACKED(4) OatHeader {
public:
static constexpr std::array<uint8_t, 4> kOatMagic { { 'o', 'a', 't', '\n' } };
- // Last oat version changed reason: Change suspend barrier data structure.
- static constexpr std::array<uint8_t, 4> kOatVersion{{'2', '4', '0', '\0'}};
+ // Last oat version changed reason: store resolved MethodType-s in .bss.
+ static constexpr std::array<uint8_t, 4> kOatVersion{{'2', '4', '1', '\0'}};
static constexpr const char* kDex2OatCmdLineKey = "dex2oat-cmdline";
static constexpr const char* kDebuggableKey = "debuggable";
diff --git a/runtime/oat_file.cc b/runtime/oat_file.cc
index 347ad7f..ce2d4fe 100644
--- a/runtime/oat_file.cc
+++ b/runtime/oat_file.cc
@@ -1016,6 +1016,7 @@
const IndexBssMapping* public_type_bss_mapping;
const IndexBssMapping* package_type_bss_mapping;
const IndexBssMapping* string_bss_mapping;
+ const IndexBssMapping* method_type_bss_mapping = nullptr;
auto read_index_bss_mapping = [&](const char* tag, /*out*/const IndexBssMapping** mapping) {
return ReadIndexBssMapping(this, &oat, i, dex_file_location, tag, mapping, error_msg);
};
@@ -1023,7 +1024,8 @@
!read_index_bss_mapping("type", &type_bss_mapping) ||
!read_index_bss_mapping("public type", &public_type_bss_mapping) ||
!read_index_bss_mapping("package type", &package_type_bss_mapping) ||
- !read_index_bss_mapping("string", &string_bss_mapping)) {
+ !read_index_bss_mapping("string", &string_bss_mapping) ||
+ !read_index_bss_mapping("method type", &method_type_bss_mapping)) {
return false;
}
@@ -1043,6 +1045,7 @@
public_type_bss_mapping,
package_type_bss_mapping,
string_bss_mapping,
+ method_type_bss_mapping,
class_offsets_pointer,
dex_layout_sections);
oat_dex_files_storage_.push_back(oat_dex_file);
@@ -2192,6 +2195,7 @@
const IndexBssMapping* public_type_bss_mapping_data,
const IndexBssMapping* package_type_bss_mapping_data,
const IndexBssMapping* string_bss_mapping_data,
+ const IndexBssMapping* method_type_bss_mapping_data,
const uint32_t* oat_class_offsets_pointer,
const DexLayoutSections* dex_layout_sections)
: oat_file_(oat_file),
@@ -2208,6 +2212,7 @@
public_type_bss_mapping_(public_type_bss_mapping_data),
package_type_bss_mapping_(package_type_bss_mapping_data),
string_bss_mapping_(string_bss_mapping_data),
+ method_type_bss_mapping_(method_type_bss_mapping_data),
oat_class_offsets_pointer_(oat_class_offsets_pointer),
lookup_table_(),
dex_layout_sections_(dex_layout_sections) {
diff --git a/runtime/oat_file.h b/runtime/oat_file.h
index 2e1bd2e..2af1921 100644
--- a/runtime/oat_file.h
+++ b/runtime/oat_file.h
@@ -392,6 +392,7 @@
const IndexBssMapping* public_type_bss_mapping = nullptr;
const IndexBssMapping* package_type_bss_mapping = nullptr;
const IndexBssMapping* string_bss_mapping = nullptr;
+ const IndexBssMapping* method_type_bss_mapping = nullptr;
};
ArrayRef<const BssMappingInfo> GetBcpBssInfo() const {
@@ -570,6 +571,10 @@
return string_bss_mapping_;
}
+ const IndexBssMapping* GetMethodTypeBssMapping() const {
+ return method_type_bss_mapping_;
+ }
+
const uint8_t* GetDexFilePointer() const {
return dex_file_pointer_;
}
@@ -609,6 +614,7 @@
const IndexBssMapping* public_type_bss_mapping,
const IndexBssMapping* package_type_bss_mapping,
const IndexBssMapping* string_bss_mapping,
+ const IndexBssMapping* method_type_bss_mapping,
const uint32_t* oat_class_offsets_pointer,
const DexLayoutSections* dex_layout_sections);
@@ -643,6 +649,7 @@
const IndexBssMapping* const public_type_bss_mapping_ = nullptr;
const IndexBssMapping* const package_type_bss_mapping_ = nullptr;
const IndexBssMapping* const string_bss_mapping_ = nullptr;
+ const IndexBssMapping* const method_type_bss_mapping_ = nullptr;
const uint32_t* const oat_class_offsets_pointer_ = nullptr;
TypeLookupTable lookup_table_;
const DexLayoutSections* const dex_layout_sections_ = nullptr;
diff --git a/test/2265-const-method-type-cached/src/Main.java b/test/2265-const-method-type-cached/src/Main.java
index 51c3374..b582e99 100644
--- a/test/2265-const-method-type-cached/src/Main.java
+++ b/test/2265-const-method-type-cached/src/Main.java
@@ -22,7 +22,11 @@
public class Main {
public static void main(String... args) throws Throwable {
testEquality();
+ // Subsequent const-method-type call should take value from from .bss.
+ testEquality();
testNonEquality();
+ testNonEquality();
+ testWithUninitializableClass();
}
private static void unreachable() {
@@ -64,6 +68,7 @@
int[].class);
assertSame(expected, actual);
+ assertSame(takesEverythingReturnsVoid(), takesEverythingReturnsVoid());
}
public static void testNonEquality() throws Throwable {
@@ -85,6 +90,32 @@
assertNotEqual(expected, actual);
}
+ @ConstantMethodType(
+ returnType = void.class,
+ parameterTypes = { UnloadableClass.class })
+ private static MethodType takesUnloadableReturnsVoid() {
+ unreachable();
+ return null;
+ }
+
+ public static volatile int x = 0;
+
+ private static class UnloadableClass {
+ static {
+ if (x == x) {
+ throw new RuntimeException("don't init me");
+ }
+ }
+ }
+
+ public static void testWithUninitializableClass() {
+ MethodType actual = takesUnloadableReturnsVoid();
+
+ MethodType expected = MethodType.methodType(void.class, UnloadableClass.class);
+
+ assertSame(expected, actual);
+ }
+
public static void assertNotEqual(Object expected, Object actual) {
if (Objects.equals(expected, actual)) {
String msg = "Expected to be non equal, but got: " + expected;