diff options
-rw-r--r-- | compiler/linker/linker_patch.h | 23 | ||||
-rw-r--r-- | compiler/optimizing/code_generator.cc | 1 | ||||
-rw-r--r-- | compiler/optimizing/code_generator_x86_64.cc | 72 | ||||
-rw-r--r-- | compiler/optimizing/code_generator_x86_64.h | 3 | ||||
-rw-r--r-- | dex2oat/linker/arm64/relative_patcher_arm64.cc | 1 | ||||
-rw-r--r-- | dex2oat/linker/oat_writer.cc | 120 | ||||
-rw-r--r-- | dex2oat/linker/oat_writer.h | 19 | ||||
-rw-r--r-- | libdexfile/Android.bp | 1 | ||||
-rw-r--r-- | libdexfile/dex/method_reference.h | 27 | ||||
-rw-r--r-- | libdexfile/dex/proto_reference.h | 91 | ||||
-rw-r--r-- | libdexfile/dex/proto_reference_test.cc | 100 | ||||
-rw-r--r-- | runtime/entrypoints/quick/quick_dexcache_entrypoints.cc | 44 | ||||
-rw-r--r-- | runtime/oat.h | 4 | ||||
-rw-r--r-- | runtime/oat_file.cc | 7 | ||||
-rw-r--r-- | runtime/oat_file.h | 7 | ||||
-rw-r--r-- | test/2265-const-method-type-cached/src/Main.java | 31 |
16 files changed, 509 insertions, 42 deletions
diff --git a/compiler/linker/linker_patch.h b/compiler/linker/linker_patch.h index 8ed7fce0ff..133088240b 100644 --- a/compiler/linker/linker_patch.h +++ b/compiler/linker/linker_patch.h @@ -56,6 +56,7 @@ class LinkerPatch { kPackageTypeBssEntry, kStringRelative, kStringBssEntry, + kMethodTypeBssEntry, kCallEntrypoint, kBakerReadBarrierBranch, }; @@ -176,6 +177,16 @@ class LinkerPatch { 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 @@ class LinkerPatch { 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 @@ class LinkerPatch { 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 34400c9d22..b0e07e32ea 100644 --- a/compiler/optimizing/code_generator.cc +++ b/compiler/optimizing/code_generator.cc @@ -1682,6 +1682,7 @@ void CodeGenerator::ValidateInvokeRuntimeWithoutRecordingPcInfo(HInstruction* in 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 24cb0c30b7..24630d2ae3 100644 --- a/compiler/optimizing/code_generator_x86_64.cc +++ b/compiler/optimizing/code_generator_x86_64.cc @@ -269,6 +269,38 @@ class BoundsCheckSlowPathX86_64 : public SlowPathCode { 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) @@ -528,6 +560,7 @@ class ReadBarrierMarkSlowPathX86_64 : public SlowPathCode { instruction_->IsArrayGet() || instruction_->IsArraySet() || instruction_->IsLoadClass() || + instruction_->IsLoadMethodType() || instruction_->IsLoadString() || instruction_->IsInstanceOf() || instruction_->IsCheckCast() || @@ -1318,6 +1351,12 @@ Label* CodeGeneratorX86_64::NewStringBssEntryPatch(HLoadString* load_string) { 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); @@ -1405,6 +1444,7 @@ void CodeGeneratorX86_64::EmitLinkerPatches(ArenaVector<linker::LinkerPatch>* li 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); @@ -1437,6 +1477,8 @@ void CodeGeneratorX86_64::EmitLinkerPatches(ArenaVector<linker::LinkerPatch>* li 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()); @@ -1561,6 +1603,7 @@ CodeGeneratorX86_64::CodeGeneratorX86_64(HGraph* graph, 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)), @@ -6668,13 +6711,34 @@ void InstructionCodeGeneratorX86_64::VisitLoadMethodHandle(HLoadMethodHandle* lo } 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); + 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>(); + + 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()); } 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 7da2e39583..e4d3eac6bc 100644 --- a/compiler/optimizing/code_generator_x86_64.h +++ b/compiler/optimizing/code_generator_x86_64.h @@ -523,6 +523,7 @@ class CodeGeneratorX86_64 : public CodeGenerator { 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 @@ class CodeGeneratorX86_64 : public CodeGenerator { 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/dex2oat/linker/arm64/relative_patcher_arm64.cc b/dex2oat/linker/arm64/relative_patcher_arm64.cc index 0c34cb8d38..db7ae74c72 100644 --- a/dex2oat/linker/arm64/relative_patcher_arm64.cc +++ b/dex2oat/linker/arm64/relative_patcher_arm64.cc @@ -71,6 +71,7 @@ inline bool IsAdrpPatch(const LinkerPatch& patch) { 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 a3efc4ac00..d1fa24fedc 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 @@ class OatWriter::OatDexFile { 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 @@ OatWriter::OatWriter(const CompilerOptions& compiler_options, 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 @@ class OatWriter::InitBssLayoutMethodVisitor : public DexMethodVisitor { 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 @@ struct OatWriter::BssMappingInfo { 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 @@ struct OatWriter::BssMappingInfo { 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 @@ class OatWriter::WriteCodeMethodVisitor : public OrderedMethodVisitor { 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 @@ size_t OatWriter::InitIndexBssMappings(size_t offset) { 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 OatWriter::InitIndexBssMappings(size_t offset) { size_t number_of_public_type_dex_files = 0u; size_t number_of_package_type_dex_files = 0u; size_t number_of_string_dex_files = 0u; + 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 @@ size_t OatWriter::InitIndexBssMappings(size_t offset) { 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 @@ size_t OatWriter::InitIndexBssMappings(size_t offset) { 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 @@ size_t OatWriter::InitIndexBssMappings(size_t offset) { 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 @@ size_t OatWriter::InitIndexBssMappingsHelper(size_t offset, /*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 @@ size_t OatWriter::InitIndexBssMappingsHelper(size_t offset, 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 @@ void OatWriter::InitBssLayout(InstructionSet instruction_set) { 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 @@ void OatWriter::InitBssLayout(InstructionSet instruction_set) { 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 @@ bool OatWriter::CheckOatSize(OutputStream* out, size_t file_offset, size_t relat DO_STAT(size_oat_dex_file_public_type_bss_mapping_offset_); DO_STAT(size_oat_dex_file_package_type_bss_mapping_offset_); DO_STAT(size_oat_dex_file_string_bss_mapping_offset_); + DO_STAT(size_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 @@ bool OatWriter::CheckOatSize(OutputStream* out, size_t file_offset, size_t relat 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 @@ size_t OatWriter::WriteIndexBssMappingsHelper(OutputStream* out, 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 @@ size_t OatWriter::WriteIndexBssMappingsHelper(OutputStream* out, 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 @@ size_t OatWriter::WriteIndexBssMappings(OutputStream* out, 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 @@ size_t OatWriter::WriteIndexBssMappings(OutputStream* out, 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 @@ size_t OatWriter::WriteIndexBssMappings(OutputStream* out, 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; } @@ -3768,6 +3850,7 @@ OatWriter::OatDexFile::OatDexFile(std::unique_ptr<const DexFile> dex_file) 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_() {} @@ -3777,7 +3860,8 @@ size_t OatWriter::OatDexFile::SizeOf() const { 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 { @@ -3871,6 +3955,13 @@ bool OatWriter::OatDexFile::Write(OatWriter* oat_writer, OutputStream* out) cons } 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; } @@ -3910,6 +4001,13 @@ bool OatWriter::BssMappingInfo::Write(OatWriter* oat_writer, OutputStream* out) } 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 5b66950bcb..9d83bcb2f9 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 @@ class OatWriter { 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 @@ class OatWriter { /*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 @@ class OatWriter { // 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 @@ class OatWriter { // 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 @@ class OatWriter { 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 @@ class OatWriter { 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 ce70a200b2..ad528c1dd2 100644 --- a/libdexfile/Android.bp +++ b/libdexfile/Android.bp @@ -293,6 +293,7 @@ art_cc_defaults { "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 f66ac30c53..9d4eabef2a 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 @@ class MethodReference : public DexFileReference { 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 @@ struct MethodReferenceValueComparator { 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 0000000000..dc9a447e63 --- /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 0000000000..f24106d87b --- /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 76bee2152a..9973d1aa47 100644 --- a/runtime/entrypoints/quick/quick_dexcache_entrypoints.cc +++ b/runtime/entrypoints/quick/quick_dexcache_entrypoints.cc @@ -162,13 +162,51 @@ static inline void StoreStringInBss(ArtMethod* caller, // 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 @@ extern "C" mirror::MethodType* artResolveMethodTypeFromCode(uint32_t proto_idx, 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 81ee6e4d7c..8ef5b010a2 100644 --- a/runtime/oat.h +++ b/runtime/oat.h @@ -44,8 +44,8 @@ std::ostream& operator<<(std::ostream& stream, StubType stub_type); class PACKED(4) OatHeader { public: static constexpr std::array<uint8_t, 4> kOatMagic { { 'o', 'a', 't', '\n' } }; - // Last oat version changed reason: Refactor OatQuickMethodHeader for assembly stubs. - static constexpr std::array<uint8_t, 4> kOatVersion{{'2', '3', '9', '\0'}}; + // Last oat version changed reason: store resolved MethodType-s in .bss. + static constexpr std::array<uint8_t, 4> kOatVersion{{'2', '4', '0', '\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 c4c6dca9f3..fc1e718a53 100644 --- a/runtime/oat_file.cc +++ b/runtime/oat_file.cc @@ -1016,6 +1016,7 @@ bool OatFileBase::Setup(int zip_fd, 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 @@ bool OatFileBase::Setup(int zip_fd, !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 @@ bool OatFileBase::Setup(int zip_fd, 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 @@ OatDexFile::OatDexFile(const OatFile* oat_file, 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 @@ OatDexFile::OatDexFile(const OatFile* oat_file, 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 2e1bd2e1ff..2af1921f0e 100644 --- a/runtime/oat_file.h +++ b/runtime/oat_file.h @@ -392,6 +392,7 @@ class OatFile { 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 @@ class OatDexFile final { 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 @@ class OatDexFile final { 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 @@ class OatDexFile final { 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 51c3374e64..b582e99e3d 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 @@ import java.util.Objects; 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 @@ public class Main { int[].class); assertSame(expected, actual); + assertSame(takesEverythingReturnsVoid(), takesEverythingReturnsVoid()); } public static void testNonEquality() throws Throwable { @@ -85,6 +90,32 @@ public class Main { 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; |