From dbb7f5bef10138ade0fb202da1d61f562b2df649 Mon Sep 17 00:00:00 2001 From: Vladimir Marko Date: Wed, 30 Mar 2016 13:23:58 +0100 Subject: Improve HLoadClass code generation. For classes in the boot image, use either direct pointers or PC-relative addresses. For other classes, use PC-relative access to the dex cache arrays for AOT and direct address of the type's dex cache slot for JIT. For aosp_flounder-userdebug: - 32-bit boot.oat: -252KiB (-0.3%) - 64-bit boot.oat: -412KiB (-0.4%) - 32-bit dalvik cache total: -392KiB (-0.4%) - 64-bit dalvik-cache total: -2312KiB (-1.0%) (contains more files than the 32-bit dalvik cache) For aosp_flounder-userdebug forced to compile PIC: - 32-bit boot.oat: -124KiB (-0.2%) - 64-bit boot.oat: -420KiB (-0.5%) - 32-bit dalvik cache total: -136KiB (-0.1%) - 64-bit dalvik-cache total: -1136KiB (-0.5%) (contains more files than the 32-bit dalvik cache) Bug: 27950288 Change-Id: I4da991a4b7e53c63c92558b97923d18092acf139 --- compiler/optimizing/code_generator.h | 21 +- compiler/optimizing/code_generator_arm.cc | 240 ++++++++++++++++++---- compiler/optimizing/code_generator_arm.h | 25 ++- compiler/optimizing/code_generator_arm64.cc | 225 +++++++++++++++++--- compiler/optimizing/code_generator_arm64.h | 28 ++- compiler/optimizing/code_generator_mips.cc | 7 + compiler/optimizing/code_generator_mips.h | 5 + compiler/optimizing/code_generator_mips64.cc | 7 + compiler/optimizing/code_generator_mips64.h | 5 + compiler/optimizing/code_generator_x86.cc | 204 ++++++++++++++---- compiler/optimizing/code_generator_x86.h | 8 + compiler/optimizing/code_generator_x86_64.cc | 189 +++++++++++++---- compiler/optimizing/code_generator_x86_64.h | 8 + compiler/optimizing/dex_cache_array_fixups_arm.cc | 17 +- compiler/optimizing/graph_visualizer.cc | 4 + compiler/optimizing/instruction_builder.cc | 14 +- compiler/optimizing/nodes.cc | 61 ++++++ compiler/optimizing/nodes.h | 189 ++++++++++++++--- compiler/optimizing/pc_relative_fixups_x86.cc | 9 + compiler/optimizing/sharpening.cc | 147 +++++++++++-- compiler/optimizing/sharpening.h | 1 + 21 files changed, 1210 insertions(+), 204 deletions(-) (limited to 'compiler/optimizing') diff --git a/compiler/optimizing/code_generator.h b/compiler/optimizing/code_generator.h index 82a54d2ed1..81c1a7fe16 100644 --- a/compiler/optimizing/code_generator.h +++ b/compiler/optimizing/code_generator.h @@ -449,10 +449,15 @@ class CodeGenerator : public DeletableArenaObject { SlowPathCode* slow_path) = 0; // Check if the desired_string_load_kind is supported. If it is, return it, - // otherwise return a fall-back info that should be used instead. + // otherwise return a fall-back kind that should be used instead. virtual HLoadString::LoadKind GetSupportedLoadStringKind( HLoadString::LoadKind desired_string_load_kind) = 0; + // Check if the desired_class_load_kind is supported. If it is, return it, + // otherwise return a fall-back kind that should be used instead. + virtual HLoadClass::LoadKind GetSupportedLoadClassKind( + HLoadClass::LoadKind desired_class_load_kind) = 0; + // Check if the desired_dispatch_info is supported. If it is, return it, // otherwise return a fall-back info that should be used instead. virtual HInvokeStaticOrDirect::DispatchInfo GetSupportedInvokeStaticOrDirectDispatch( @@ -496,6 +501,20 @@ class CodeGenerator : public DeletableArenaObject { LabelType label; }; + // Type patch info used for recording locations of required linker patches and + // target types. The actual type address can be absolute or PC-relative. + // TODO: Consider merging with MethodPatchInfo and StringPatchInfo - all these + // classes contain the dex file, some index and the label. + template + struct TypePatchInfo { + TypePatchInfo(const DexFile& df, uint32_t index) + : dex_file(df), type_index(index), label() { } + + const DexFile& dex_file; + uint32_t type_index; + LabelType label; + }; + CodeGenerator(HGraph* graph, size_t number_of_core_registers, size_t number_of_fpu_registers, diff --git a/compiler/optimizing/code_generator_arm.cc b/compiler/optimizing/code_generator_arm.cc index eca9e2c299..f5befa65c1 100644 --- a/compiler/optimizing/code_generator_arm.cc +++ b/compiler/optimizing/code_generator_arm.cc @@ -792,6 +792,9 @@ CodeGeneratorARM::CodeGeneratorARM(HGraph* graph, boot_image_string_patches_(StringReferenceValueComparator(), graph->GetArena()->Adapter(kArenaAllocCodeGenerator)), pc_relative_string_patches_(graph->GetArena()->Adapter(kArenaAllocCodeGenerator)), + boot_image_type_patches_(TypeReferenceValueComparator(), + graph->GetArena()->Adapter(kArenaAllocCodeGenerator)), + pc_relative_type_patches_(graph->GetArena()->Adapter(kArenaAllocCodeGenerator)), boot_image_address_patches_(std::less(), graph->GetArena()->Adapter(kArenaAllocCodeGenerator)) { // Always save the LR register to mimic Quick. @@ -5077,13 +5080,71 @@ void ParallelMoveResolverARM::RestoreScratch(int reg) { __ Pop(static_cast(reg)); } +HLoadClass::LoadKind CodeGeneratorARM::GetSupportedLoadClassKind( + HLoadClass::LoadKind desired_class_load_kind) { + if (kEmitCompilerReadBarrier) { + switch (desired_class_load_kind) { + case HLoadClass::LoadKind::kBootImageLinkTimeAddress: + case HLoadClass::LoadKind::kBootImageLinkTimePcRelative: + case HLoadClass::LoadKind::kBootImageAddress: + // TODO: Implement for read barrier. + return HLoadClass::LoadKind::kDexCacheViaMethod; + default: + break; + } + } + switch (desired_class_load_kind) { + case HLoadClass::LoadKind::kReferrersClass: + break; + case HLoadClass::LoadKind::kBootImageLinkTimeAddress: + DCHECK(!GetCompilerOptions().GetCompilePic()); + break; + case HLoadClass::LoadKind::kBootImageLinkTimePcRelative: + DCHECK(GetCompilerOptions().GetCompilePic()); + break; + case HLoadClass::LoadKind::kBootImageAddress: + break; + case HLoadClass::LoadKind::kDexCacheAddress: + DCHECK(Runtime::Current()->UseJitCompilation()); + break; + case HLoadClass::LoadKind::kDexCachePcRelative: + DCHECK(!Runtime::Current()->UseJitCompilation()); + // We disable pc-relative load when there is an irreducible loop, as the optimization + // is incompatible with it. + // TODO: Create as many ArmDexCacheArraysBase instructions as needed for methods + // with irreducible loops. + if (GetGraph()->HasIrreducibleLoops()) { + return HLoadClass::LoadKind::kDexCacheViaMethod; + } + break; + case HLoadClass::LoadKind::kDexCacheViaMethod: + break; + } + return desired_class_load_kind; +} + void LocationsBuilderARM::VisitLoadClass(HLoadClass* cls) { - InvokeRuntimeCallingConvention calling_convention; - CodeGenerator::CreateLoadClassLocationSummary( - cls, - Location::RegisterLocation(calling_convention.GetRegisterAt(0)), - Location::RegisterLocation(R0), - /* code_generator_supports_read_barrier */ true); + if (cls->NeedsAccessCheck()) { + InvokeRuntimeCallingConvention calling_convention; + CodeGenerator::CreateLoadClassLocationSummary( + cls, + Location::RegisterLocation(calling_convention.GetRegisterAt(0)), + Location::RegisterLocation(R0), + /* code_generator_supports_read_barrier */ true); + return; + } + + LocationSummary::CallKind call_kind = (cls->NeedsEnvironment() || kEmitCompilerReadBarrier) + ? LocationSummary::kCallOnSlowPath + : LocationSummary::kNoCall; + LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(cls, call_kind); + HLoadClass::LoadKind load_kind = cls->GetLoadKind(); + if (load_kind == HLoadClass::LoadKind::kReferrersClass || + load_kind == HLoadClass::LoadKind::kDexCacheViaMethod || + load_kind == HLoadClass::LoadKind::kDexCachePcRelative) { + locations->SetInAt(0, Location::RequiresRegister()); + } + locations->SetOut(Location::RequiresRegister()); } void InstructionCodeGeneratorARM::VisitLoadClass(HLoadClass* cls) { @@ -5100,37 +5161,97 @@ void InstructionCodeGeneratorARM::VisitLoadClass(HLoadClass* cls) { Location out_loc = locations->Out(); Register out = out_loc.AsRegister(); - Register current_method = locations->InAt(0).AsRegister(); - - if (cls->IsReferrersClass()) { - DCHECK(!cls->CanCallRuntime()); - DCHECK(!cls->MustGenerateClinitCheck()); - // /* GcRoot */ out = current_method->declaring_class_ - GenerateGcRootFieldLoad( - cls, out_loc, current_method, ArtMethod::DeclaringClassOffset().Int32Value()); - } else { - // /* GcRoot[] */ out = - // current_method.ptr_sized_fields_->dex_cache_resolved_types_ - __ LoadFromOffset(kLoadWord, - out, - current_method, - ArtMethod::DexCacheResolvedTypesOffset(kArmPointerSize).Int32Value()); - // /* GcRoot */ out = out[type_index] - GenerateGcRootFieldLoad(cls, out_loc, out, CodeGenerator::GetCacheOffset(cls->GetTypeIndex())); - - if (!cls->IsInDexCache() || cls->MustGenerateClinitCheck()) { - DCHECK(cls->CanCallRuntime()); - SlowPathCode* slow_path = new (GetGraph()->GetArena()) LoadClassSlowPathARM( - cls, cls, cls->GetDexPc(), cls->MustGenerateClinitCheck()); - codegen_->AddSlowPath(slow_path); - if (!cls->IsInDexCache()) { - __ CompareAndBranchIfZero(out, slow_path->GetEntryLabel()); - } - if (cls->MustGenerateClinitCheck()) { - GenerateClassInitializationCheck(slow_path, out); - } else { - __ Bind(slow_path->GetExitLabel()); - } + + bool generate_null_check = false; + switch (cls->GetLoadKind()) { + case HLoadClass::LoadKind::kReferrersClass: { + DCHECK(!cls->CanCallRuntime()); + DCHECK(!cls->MustGenerateClinitCheck()); + // /* GcRoot */ out = current_method->declaring_class_ + Register current_method = locations->InAt(0).AsRegister(); + GenerateGcRootFieldLoad( + cls, out_loc, current_method, ArtMethod::DeclaringClassOffset().Int32Value()); + break; + } + case HLoadClass::LoadKind::kBootImageLinkTimeAddress: { + DCHECK(!kEmitCompilerReadBarrier); + __ LoadLiteral(out, codegen_->DeduplicateBootImageTypeLiteral(cls->GetDexFile(), + cls->GetTypeIndex())); + break; + } + case HLoadClass::LoadKind::kBootImageLinkTimePcRelative: { + DCHECK(!kEmitCompilerReadBarrier); + CodeGeneratorARM::PcRelativePatchInfo* labels = + codegen_->NewPcRelativeTypePatch(cls->GetDexFile(), cls->GetTypeIndex()); + __ BindTrackedLabel(&labels->movw_label); + __ movw(out, /* placeholder */ 0u); + __ BindTrackedLabel(&labels->movt_label); + __ movt(out, /* placeholder */ 0u); + __ BindTrackedLabel(&labels->add_pc_label); + __ add(out, out, ShifterOperand(PC)); + break; + } + case HLoadClass::LoadKind::kBootImageAddress: { + DCHECK(!kEmitCompilerReadBarrier); + DCHECK_NE(cls->GetAddress(), 0u); + uint32_t address = dchecked_integral_cast(cls->GetAddress()); + __ LoadLiteral(out, codegen_->DeduplicateBootImageAddressLiteral(address)); + break; + } + case HLoadClass::LoadKind::kDexCacheAddress: { + DCHECK_NE(cls->GetAddress(), 0u); + uint32_t address = dchecked_integral_cast(cls->GetAddress()); + // 16-bit LDR immediate has a 5-bit offset multiplied by the size and that gives + // a 128B range. To try and reduce the number of literals if we load multiple types, + // simply split the dex cache address to a 128B aligned base loaded from a literal + // and the remaining offset embedded in the load. + static_assert(sizeof(GcRoot) == 4u, "Expected GC root to be 4 bytes."); + DCHECK_ALIGNED(cls->GetAddress(), 4u); + constexpr size_t offset_bits = /* encoded bits */ 5 + /* scale */ 2; + uint32_t base_address = address & ~MaxInt(offset_bits); + uint32_t offset = address & MaxInt(offset_bits); + __ LoadLiteral(out, codegen_->DeduplicateDexCacheAddressLiteral(base_address)); + // /* GcRoot */ out = *(base_address + offset) + GenerateGcRootFieldLoad(cls, out_loc, out, offset); + generate_null_check = !cls->IsInDexCache(); + break; + } + case HLoadClass::LoadKind::kDexCachePcRelative: { + Register base_reg = locations->InAt(0).AsRegister(); + HArmDexCacheArraysBase* base = cls->InputAt(0)->AsArmDexCacheArraysBase(); + int32_t offset = cls->GetDexCacheElementOffset() - base->GetElementOffset(); + // /* GcRoot */ out = *(dex_cache_arrays_base + offset) + GenerateGcRootFieldLoad(cls, out_loc, base_reg, offset); + generate_null_check = !cls->IsInDexCache(); + break; + } + case HLoadClass::LoadKind::kDexCacheViaMethod: { + // /* GcRoot[] */ out = + // current_method.ptr_sized_fields_->dex_cache_resolved_types_ + Register current_method = locations->InAt(0).AsRegister(); + __ LoadFromOffset(kLoadWord, + out, + current_method, + ArtMethod::DexCacheResolvedTypesOffset(kArmPointerSize).Int32Value()); + // /* GcRoot */ out = out[type_index] + size_t offset = CodeGenerator::GetCacheOffset(cls->GetTypeIndex()); + GenerateGcRootFieldLoad(cls, out_loc, out, offset); + generate_null_check = !cls->IsInDexCache(); + } + } + + if (generate_null_check || cls->MustGenerateClinitCheck()) { + DCHECK(cls->CanCallRuntime()); + SlowPathCode* slow_path = new (GetGraph()->GetArena()) LoadClassSlowPathARM( + cls, cls, cls->GetDexPc(), cls->MustGenerateClinitCheck()); + codegen_->AddSlowPath(slow_path); + if (generate_null_check) { + __ CompareAndBranchIfZero(out, slow_path->GetEntryLabel()); + } + if (cls->MustGenerateClinitCheck()) { + GenerateClassInitializationCheck(slow_path, out); + } else { + __ Bind(slow_path->GetExitLabel()); } } } @@ -5262,6 +5383,7 @@ void InstructionCodeGeneratorARM::VisitLoadString(HLoadString* load) { uint32_t base_address = address & ~MaxInt(offset_bits); uint32_t offset = address & MaxInt(offset_bits); __ LoadLiteral(out, codegen_->DeduplicateDexCacheAddressLiteral(base_address)); + // /* GcRoot */ out = *(base_address + offset) GenerateGcRootFieldLoad(load, out_loc, out, offset); break; } @@ -5269,6 +5391,7 @@ void InstructionCodeGeneratorARM::VisitLoadString(HLoadString* load) { Register base_reg = locations->InAt(0).AsRegister(); HArmDexCacheArraysBase* base = load->InputAt(0)->AsArmDexCacheArraysBase(); int32_t offset = load->GetDexCacheElementOffset() - base->GetElementOffset(); + // /* GcRoot */ out = *(dex_cache_arrays_base + offset) GenerateGcRootFieldLoad(load, out_loc, base_reg, offset); break; } @@ -6452,6 +6575,11 @@ CodeGeneratorARM::PcRelativePatchInfo* CodeGeneratorARM::NewPcRelativeStringPatc return NewPcRelativePatch(dex_file, string_index, &pc_relative_string_patches_); } +CodeGeneratorARM::PcRelativePatchInfo* CodeGeneratorARM::NewPcRelativeTypePatch( + const DexFile& dex_file, uint32_t type_index) { + return NewPcRelativePatch(dex_file, type_index, &pc_relative_type_patches_); +} + CodeGeneratorARM::PcRelativePatchInfo* CodeGeneratorARM::NewPcRelativeDexCacheArrayPatch( const DexFile& dex_file, uint32_t element_offset) { return NewPcRelativePatch(dex_file, element_offset, &pc_relative_dex_cache_patches_); @@ -6470,6 +6598,13 @@ Literal* CodeGeneratorARM::DeduplicateBootImageStringLiteral(const DexFile& dex_ [this]() { return __ NewLiteral(/* placeholder */ 0u); }); } +Literal* CodeGeneratorARM::DeduplicateBootImageTypeLiteral(const DexFile& dex_file, + uint32_t type_index) { + return boot_image_type_patches_.GetOrCreate( + TypeReference(&dex_file, type_index), + [this]() { return __ NewLiteral(/* placeholder */ 0u); }); +} + Literal* CodeGeneratorARM::DeduplicateBootImageAddressLiteral(uint32_t address) { bool needs_patch = GetCompilerOptions().GetIncludePatchInformation(); Uint32ToLiteralMap* map = needs_patch ? &boot_image_address_patches_ : &uint32_literals_; @@ -6489,6 +6624,8 @@ void CodeGeneratorARM::EmitLinkerPatches(ArenaVector* linker_patche /* MOVW+MOVT for each base */ 2u * pc_relative_dex_cache_patches_.size() + boot_image_string_patches_.size() + /* MOVW+MOVT for each base */ 2u * pc_relative_string_patches_.size() + + boot_image_type_patches_.size() + + /* MOVW+MOVT for each base */ 2u * pc_relative_type_patches_.size() + boot_image_address_patches_.size(); linker_patches->reserve(size); for (const auto& entry : method_patches_) { @@ -6564,6 +6701,35 @@ void CodeGeneratorARM::EmitLinkerPatches(ArenaVector* linker_patche add_pc_offset, string_index)); } + for (const auto& entry : boot_image_type_patches_) { + const TypeReference& target_type = entry.first; + Literal* literal = entry.second; + DCHECK(literal->GetLabel()->IsBound()); + uint32_t literal_offset = literal->GetLabel()->Position(); + linker_patches->push_back(LinkerPatch::TypePatch(literal_offset, + target_type.dex_file, + target_type.type_index)); + } + for (const PcRelativePatchInfo& info : pc_relative_type_patches_) { + const DexFile& dex_file = info.target_dex_file; + uint32_t type_index = info.offset_or_index; + DCHECK(info.add_pc_label.IsBound()); + uint32_t add_pc_offset = dchecked_integral_cast(info.add_pc_label.Position()); + // Add MOVW patch. + DCHECK(info.movw_label.IsBound()); + uint32_t movw_offset = dchecked_integral_cast(info.movw_label.Position()); + linker_patches->push_back(LinkerPatch::RelativeTypePatch(movw_offset, + &dex_file, + add_pc_offset, + type_index)); + // Add MOVT patch. + DCHECK(info.movt_label.IsBound()); + uint32_t movt_offset = dchecked_integral_cast(info.movt_label.Position()); + linker_patches->push_back(LinkerPatch::RelativeTypePatch(movt_offset, + &dex_file, + add_pc_offset, + type_index)); + } for (const auto& entry : boot_image_address_patches_) { DCHECK(GetCompilerOptions().GetIncludePatchInformation()); Literal* literal = entry.second; diff --git a/compiler/optimizing/code_generator_arm.h b/compiler/optimizing/code_generator_arm.h index 0020f7b4f4..4fce5af8e6 100644 --- a/compiler/optimizing/code_generator_arm.h +++ b/compiler/optimizing/code_generator_arm.h @@ -24,6 +24,7 @@ #include "parallel_move_resolver.h" #include "utils/arm/assembler_thumb2.h" #include "utils/string_reference.h" +#include "utils/type_reference.h" namespace art { namespace arm { @@ -407,6 +408,11 @@ class CodeGeneratorARM : public CodeGenerator { HLoadString::LoadKind GetSupportedLoadStringKind( HLoadString::LoadKind desired_string_load_kind) OVERRIDE; + // Check if the desired_class_load_kind is supported. If it is, return it, + // otherwise return a fall-back kind that should be used instead. + HLoadClass::LoadKind GetSupportedLoadClassKind( + HLoadClass::LoadKind desired_class_load_kind) OVERRIDE; + // Check if the desired_dispatch_info is supported. If it is, return it, // otherwise return a fall-back info that should be used instead. HInvokeStaticOrDirect::DispatchInfo GetSupportedInvokeStaticOrDirectDispatch( @@ -419,10 +425,10 @@ class CodeGeneratorARM : public CodeGenerator { void MoveFromReturnRegister(Location trg, Primitive::Type type) OVERRIDE; // The PcRelativePatchInfo is used for PC-relative addressing of dex cache arrays - // and boot image strings. The only difference is the interpretation of the offset_or_index. - // The PC-relative address is loaded with three instructions, MOVW+MOVT - // to load the offset to base_reg and then ADD base_reg, PC. The offset is - // calculated from the ADD's effective PC, i.e. PC+4 on Thumb2. Though we + // and boot image strings/types. The only difference is the interpretation of the + // offset_or_index. The PC-relative address is loaded with three instructions, + // MOVW+MOVT to load the offset to base_reg and then ADD base_reg, PC. The offset + // is calculated from the ADD's effective PC, i.e. PC+4 on Thumb2. Though we // currently emit these 3 instructions together, instruction scheduling could // split this sequence apart, so we keep separate labels for each of them. struct PcRelativePatchInfo { @@ -431,7 +437,7 @@ class CodeGeneratorARM : public CodeGenerator { PcRelativePatchInfo(PcRelativePatchInfo&& other) = default; const DexFile& target_dex_file; - // Either the dex cache array element offset or the string index. + // Either the dex cache array element offset or the string/type index. uint32_t offset_or_index; Label movw_label; Label movt_label; @@ -439,9 +445,11 @@ class CodeGeneratorARM : public CodeGenerator { }; PcRelativePatchInfo* NewPcRelativeStringPatch(const DexFile& dex_file, uint32_t string_index); + PcRelativePatchInfo* NewPcRelativeTypePatch(const DexFile& dex_file, uint32_t type_index); PcRelativePatchInfo* NewPcRelativeDexCacheArrayPatch(const DexFile& dex_file, uint32_t element_offset); Literal* DeduplicateBootImageStringLiteral(const DexFile& dex_file, uint32_t string_index); + Literal* DeduplicateBootImageTypeLiteral(const DexFile& dex_file, uint32_t type_index); Literal* DeduplicateBootImageAddressLiteral(uint32_t address); Literal* DeduplicateDexCacheAddressLiteral(uint32_t address); @@ -536,6 +544,9 @@ class CodeGeneratorARM : public CodeGenerator { using BootStringToLiteralMap = ArenaSafeMap; + using BootTypeToLiteralMap = ArenaSafeMap; Literal* DeduplicateUint32Literal(uint32_t value, Uint32ToLiteralMap* map); Literal* DeduplicateMethodLiteral(MethodReference target_method, MethodToLiteralMap* map); @@ -568,6 +579,10 @@ class CodeGeneratorARM : public CodeGenerator { BootStringToLiteralMap boot_image_string_patches_; // PC-relative String patch info. ArenaDeque pc_relative_string_patches_; + // Deduplication map for boot type literals for kBootImageLinkTimeAddress. + BootTypeToLiteralMap boot_image_type_patches_; + // PC-relative type patch info. + ArenaDeque pc_relative_type_patches_; // Deduplication map for patchable boot image addresses. Uint32ToLiteralMap boot_image_address_patches_; diff --git a/compiler/optimizing/code_generator_arm64.cc b/compiler/optimizing/code_generator_arm64.cc index 5d3c8c5590..f748898c13 100644 --- a/compiler/optimizing/code_generator_arm64.cc +++ b/compiler/optimizing/code_generator_arm64.cc @@ -920,6 +920,9 @@ CodeGeneratorARM64::CodeGeneratorARM64(HGraph* graph, boot_image_string_patches_(StringReferenceValueComparator(), graph->GetArena()->Adapter(kArenaAllocCodeGenerator)), pc_relative_string_patches_(graph->GetArena()->Adapter(kArenaAllocCodeGenerator)), + boot_image_type_patches_(TypeReferenceValueComparator(), + graph->GetArena()->Adapter(kArenaAllocCodeGenerator)), + pc_relative_type_patches_(graph->GetArena()->Adapter(kArenaAllocCodeGenerator)), boot_image_address_patches_(std::less(), graph->GetArena()->Adapter(kArenaAllocCodeGenerator)) { // Save the link register (containing the return address) to mimic Quick. @@ -3725,6 +3728,12 @@ vixl::Label* CodeGeneratorARM64::NewPcRelativeStringPatch(const DexFile& dex_fil return NewPcRelativePatch(dex_file, string_index, adrp_label, &pc_relative_string_patches_); } +vixl::Label* CodeGeneratorARM64::NewPcRelativeTypePatch(const DexFile& dex_file, + uint32_t type_index, + vixl::Label* adrp_label) { + return NewPcRelativePatch(dex_file, type_index, adrp_label, &pc_relative_type_patches_); +} + vixl::Label* CodeGeneratorARM64::NewPcRelativeDexCacheArrayPatch(const DexFile& dex_file, uint32_t element_offset, vixl::Label* adrp_label) { @@ -3751,6 +3760,13 @@ vixl::Literal* CodeGeneratorARM64::DeduplicateBootImageStringLiteral( [this]() { return __ CreateLiteralDestroyedWithPool(/* placeholder */ 0u); }); } +vixl::Literal* CodeGeneratorARM64::DeduplicateBootImageTypeLiteral( + const DexFile& dex_file, uint32_t type_index) { + return boot_image_type_patches_.GetOrCreate( + TypeReference(&dex_file, type_index), + [this]() { return __ CreateLiteralDestroyedWithPool(/* placeholder */ 0u); }); +} + vixl::Literal* CodeGeneratorARM64::DeduplicateBootImageAddressLiteral(uint64_t address) { bool needs_patch = GetCompilerOptions().GetIncludePatchInformation(); Uint32ToLiteralMap* map = needs_patch ? &boot_image_address_patches_ : &uint32_literals_; @@ -3770,6 +3786,8 @@ void CodeGeneratorARM64::EmitLinkerPatches(ArenaVector* linker_patc pc_relative_dex_cache_patches_.size() + boot_image_string_patches_.size() + pc_relative_string_patches_.size() + + boot_image_type_patches_.size() + + pc_relative_type_patches_.size() + boot_image_address_patches_.size(); linker_patches->reserve(size); for (const auto& entry : method_patches_) { @@ -3810,6 +3828,19 @@ void CodeGeneratorARM64::EmitLinkerPatches(ArenaVector* linker_patc info.pc_insn_label->location(), info.offset_or_index)); } + for (const auto& entry : boot_image_type_patches_) { + const TypeReference& target_type = entry.first; + vixl::Literal* literal = entry.second; + linker_patches->push_back(LinkerPatch::TypePatch(literal->offset(), + target_type.dex_file, + target_type.type_index)); + } + for (const PcRelativePatchInfo& info : pc_relative_type_patches_) { + linker_patches->push_back(LinkerPatch::RelativeTypePatch(info.label.location(), + &info.target_dex_file, + info.pc_insn_label->location(), + info.offset_or_index)); + } for (const auto& entry : boot_image_address_patches_) { DCHECK(GetCompilerOptions().GetIncludePatchInformation()); vixl::Literal* literal = entry.second; @@ -3875,13 +3906,63 @@ void InstructionCodeGeneratorARM64::VisitInvokeVirtual(HInvokeVirtual* invoke) { codegen_->RecordPcInfo(invoke, invoke->GetDexPc()); } +HLoadClass::LoadKind CodeGeneratorARM64::GetSupportedLoadClassKind( + HLoadClass::LoadKind desired_class_load_kind) { + if (kEmitCompilerReadBarrier) { + switch (desired_class_load_kind) { + case HLoadClass::LoadKind::kBootImageLinkTimeAddress: + case HLoadClass::LoadKind::kBootImageLinkTimePcRelative: + case HLoadClass::LoadKind::kBootImageAddress: + // TODO: Implement for read barrier. + return HLoadClass::LoadKind::kDexCacheViaMethod; + default: + break; + } + } + switch (desired_class_load_kind) { + case HLoadClass::LoadKind::kReferrersClass: + break; + case HLoadClass::LoadKind::kBootImageLinkTimeAddress: + DCHECK(!GetCompilerOptions().GetCompilePic()); + break; + case HLoadClass::LoadKind::kBootImageLinkTimePcRelative: + DCHECK(GetCompilerOptions().GetCompilePic()); + break; + case HLoadClass::LoadKind::kBootImageAddress: + break; + case HLoadClass::LoadKind::kDexCacheAddress: + DCHECK(Runtime::Current()->UseJitCompilation()); + break; + case HLoadClass::LoadKind::kDexCachePcRelative: + DCHECK(!Runtime::Current()->UseJitCompilation()); + break; + case HLoadClass::LoadKind::kDexCacheViaMethod: + break; + } + return desired_class_load_kind; +} + void LocationsBuilderARM64::VisitLoadClass(HLoadClass* cls) { - InvokeRuntimeCallingConvention calling_convention; - CodeGenerator::CreateLoadClassLocationSummary( - cls, - LocationFrom(calling_convention.GetRegisterAt(0)), - LocationFrom(vixl::x0), - /* code_generator_supports_read_barrier */ true); + if (cls->NeedsAccessCheck()) { + InvokeRuntimeCallingConvention calling_convention; + CodeGenerator::CreateLoadClassLocationSummary( + cls, + LocationFrom(calling_convention.GetRegisterAt(0)), + LocationFrom(vixl::x0), + /* code_generator_supports_read_barrier */ true); + return; + } + + LocationSummary::CallKind call_kind = (cls->NeedsEnvironment() || kEmitCompilerReadBarrier) + ? LocationSummary::kCallOnSlowPath + : LocationSummary::kNoCall; + LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(cls, call_kind); + HLoadClass::LoadKind load_kind = cls->GetLoadKind(); + if (load_kind == HLoadClass::LoadKind::kReferrersClass || + load_kind == HLoadClass::LoadKind::kDexCacheViaMethod) { + locations->SetInAt(0, Location::RequiresRegister()); + } + locations->SetOut(Location::RequiresRegister()); } void InstructionCodeGeneratorARM64::VisitLoadClass(HLoadClass* cls) { @@ -3897,35 +3978,111 @@ void InstructionCodeGeneratorARM64::VisitLoadClass(HLoadClass* cls) { Location out_loc = cls->GetLocations()->Out(); Register out = OutputRegister(cls); - Register current_method = InputRegisterAt(cls, 0); - if (cls->IsReferrersClass()) { - DCHECK(!cls->CanCallRuntime()); - DCHECK(!cls->MustGenerateClinitCheck()); - // /* GcRoot */ out = current_method->declaring_class_ - GenerateGcRootFieldLoad( - cls, out_loc, current_method, ArtMethod::DeclaringClassOffset().Int32Value()); - } else { - MemberOffset resolved_types_offset = ArtMethod::DexCacheResolvedTypesOffset(kArm64PointerSize); - // /* GcRoot[] */ out = - // current_method.ptr_sized_fields_->dex_cache_resolved_types_ - __ Ldr(out.X(), MemOperand(current_method, resolved_types_offset.Int32Value())); - // /* GcRoot */ out = out[type_index] - GenerateGcRootFieldLoad( - cls, out_loc, out.X(), CodeGenerator::GetCacheOffset(cls->GetTypeIndex())); - - if (!cls->IsInDexCache() || cls->MustGenerateClinitCheck()) { - DCHECK(cls->CanCallRuntime()); - SlowPathCodeARM64* slow_path = new (GetGraph()->GetArena()) LoadClassSlowPathARM64( - cls, cls, cls->GetDexPc(), cls->MustGenerateClinitCheck()); - codegen_->AddSlowPath(slow_path); - if (!cls->IsInDexCache()) { - __ Cbz(out, slow_path->GetEntryLabel()); + + bool generate_null_check = false; + switch (cls->GetLoadKind()) { + case HLoadClass::LoadKind::kReferrersClass: { + DCHECK(!cls->CanCallRuntime()); + DCHECK(!cls->MustGenerateClinitCheck()); + // /* GcRoot */ out = current_method->declaring_class_ + Register current_method = InputRegisterAt(cls, 0); + GenerateGcRootFieldLoad( + cls, out_loc, current_method, ArtMethod::DeclaringClassOffset().Int32Value()); + break; + } + case HLoadClass::LoadKind::kBootImageLinkTimeAddress: + DCHECK(!kEmitCompilerReadBarrier); + __ Ldr(out, codegen_->DeduplicateBootImageTypeLiteral(cls->GetDexFile(), + cls->GetTypeIndex())); + break; + case HLoadClass::LoadKind::kBootImageLinkTimePcRelative: { + DCHECK(!kEmitCompilerReadBarrier); + // Add ADRP with its PC-relative type patch. + const DexFile& dex_file = cls->GetDexFile(); + uint32_t type_index = cls->GetTypeIndex(); + vixl::Label* adrp_label = codegen_->NewPcRelativeTypePatch(dex_file, type_index); + { + vixl::SingleEmissionCheckScope guard(GetVIXLAssembler()); + __ Bind(adrp_label); + __ adrp(out.X(), /* offset placeholder */ 0); } - if (cls->MustGenerateClinitCheck()) { - GenerateClassInitializationCheck(slow_path, out); - } else { - __ Bind(slow_path->GetExitLabel()); + // Add ADD with its PC-relative type patch. + vixl::Label* add_label = codegen_->NewPcRelativeTypePatch(dex_file, type_index, adrp_label); + { + vixl::SingleEmissionCheckScope guard(GetVIXLAssembler()); + __ Bind(add_label); + __ add(out.X(), out.X(), Operand(/* offset placeholder */ 0)); + } + break; + } + case HLoadClass::LoadKind::kBootImageAddress: { + DCHECK(!kEmitCompilerReadBarrier); + DCHECK(cls->GetAddress() != 0u && IsUint<32>(cls->GetAddress())); + __ Ldr(out.W(), codegen_->DeduplicateBootImageAddressLiteral(cls->GetAddress())); + break; + } + case HLoadClass::LoadKind::kDexCacheAddress: { + DCHECK_NE(cls->GetAddress(), 0u); + // LDR immediate has a 12-bit offset multiplied by the size and for 32-bit loads + // that gives a 16KiB range. To try and reduce the number of literals if we load + // multiple types, simply split the dex cache address to a 16KiB aligned base + // loaded from a literal and the remaining offset embedded in the load. + static_assert(sizeof(GcRoot) == 4u, "Expected GC root to be 4 bytes."); + DCHECK_ALIGNED(cls->GetAddress(), 4u); + constexpr size_t offset_bits = /* encoded bits */ 12 + /* scale */ 2; + uint64_t base_address = cls->GetAddress() & ~MaxInt(offset_bits); + uint32_t offset = cls->GetAddress() & MaxInt(offset_bits); + __ Ldr(out.X(), codegen_->DeduplicateDexCacheAddressLiteral(base_address)); + // /* GcRoot */ out = *(base_address + offset) + GenerateGcRootFieldLoad(cls, out_loc, out.X(), offset); + generate_null_check = !cls->IsInDexCache(); + break; + } + case HLoadClass::LoadKind::kDexCachePcRelative: { + // Add ADRP with its PC-relative DexCache access patch. + const DexFile& dex_file = cls->GetDexFile(); + uint32_t element_offset = cls->GetDexCacheElementOffset(); + vixl::Label* adrp_label = codegen_->NewPcRelativeDexCacheArrayPatch(dex_file, element_offset); + { + vixl::SingleEmissionCheckScope guard(GetVIXLAssembler()); + __ Bind(adrp_label); + __ adrp(out.X(), /* offset placeholder */ 0); } + // Add LDR with its PC-relative DexCache access patch. + vixl::Label* ldr_label = + codegen_->NewPcRelativeDexCacheArrayPatch(dex_file, element_offset, adrp_label); + // /* GcRoot */ out = *(base_address + offset) /* PC-relative */ + GenerateGcRootFieldLoad(cls, out_loc, out.X(), /* offset placeholder */ 0, ldr_label); + generate_null_check = !cls->IsInDexCache(); + break; + } + case HLoadClass::LoadKind::kDexCacheViaMethod: { + MemberOffset resolved_types_offset = + ArtMethod::DexCacheResolvedTypesOffset(kArm64PointerSize); + // /* GcRoot[] */ out = + // current_method.ptr_sized_fields_->dex_cache_resolved_types_ + Register current_method = InputRegisterAt(cls, 0); + __ Ldr(out.X(), MemOperand(current_method, resolved_types_offset.Int32Value())); + // /* GcRoot */ out = out[type_index] + GenerateGcRootFieldLoad( + cls, out_loc, out.X(), CodeGenerator::GetCacheOffset(cls->GetTypeIndex())); + generate_null_check = !cls->IsInDexCache(); + break; + } + } + + if (generate_null_check || cls->MustGenerateClinitCheck()) { + DCHECK(cls->CanCallRuntime()); + SlowPathCodeARM64* slow_path = new (GetGraph()->GetArena()) LoadClassSlowPathARM64( + cls, cls, cls->GetDexPc(), cls->MustGenerateClinitCheck()); + codegen_->AddSlowPath(slow_path); + if (generate_null_check) { + __ Cbz(out, slow_path->GetEntryLabel()); + } + if (cls->MustGenerateClinitCheck()) { + GenerateClassInitializationCheck(slow_path, out); + } else { + __ Bind(slow_path->GetExitLabel()); } } } @@ -4046,6 +4203,7 @@ void InstructionCodeGeneratorARM64::VisitLoadString(HLoadString* load) { uint64_t base_address = load->GetAddress() & ~MaxInt(offset_bits); uint32_t offset = load->GetAddress() & MaxInt(offset_bits); __ Ldr(out.X(), codegen_->DeduplicateDexCacheAddressLiteral(base_address)); + // /* GcRoot */ out = *(base_address + offset) GenerateGcRootFieldLoad(load, out_loc, out.X(), offset); break; } @@ -4062,6 +4220,7 @@ void InstructionCodeGeneratorARM64::VisitLoadString(HLoadString* load) { // Add LDR with its PC-relative DexCache access patch. vixl::Label* ldr_label = codegen_->NewPcRelativeDexCacheArrayPatch(dex_file, element_offset, adrp_label); + // /* GcRoot */ out = *(base_address + offset) /* PC-relative */ GenerateGcRootFieldLoad(load, out_loc, out.X(), /* offset placeholder */ 0, ldr_label); break; } diff --git a/compiler/optimizing/code_generator_arm64.h b/compiler/optimizing/code_generator_arm64.h index 422963e7d0..e6fd336be7 100644 --- a/compiler/optimizing/code_generator_arm64.h +++ b/compiler/optimizing/code_generator_arm64.h @@ -26,6 +26,7 @@ #include "parallel_move_resolver.h" #include "utils/arm64/assembler_arm64.h" #include "utils/string_reference.h" +#include "utils/type_reference.h" #include "vixl/a64/disasm-a64.h" #include "vixl/a64/macro-assembler-a64.h" @@ -460,6 +461,11 @@ class CodeGeneratorARM64 : public CodeGenerator { HLoadString::LoadKind GetSupportedLoadStringKind( HLoadString::LoadKind desired_string_load_kind) OVERRIDE; + // Check if the desired_class_load_kind is supported. If it is, return it, + // otherwise return a fall-back kind that should be used instead. + HLoadClass::LoadKind GetSupportedLoadClassKind( + HLoadClass::LoadKind desired_class_load_kind) OVERRIDE; + // Check if the desired_dispatch_info is supported. If it is, return it, // otherwise return a fall-back info that should be used instead. HInvokeStaticOrDirect::DispatchInfo GetSupportedInvokeStaticOrDirectDispatch( @@ -482,6 +488,14 @@ class CodeGeneratorARM64 : public CodeGenerator { uint32_t string_index, vixl::Label* adrp_label = nullptr); + // Add a new PC-relative type patch for an instruction and return the label + // to be bound before the instruction. The instruction will be either the + // ADRP (pass `adrp_label = null`) or the ADD (pass `adrp_label` pointing + // to the associated ADRP patch label). + vixl::Label* NewPcRelativeTypePatch(const DexFile& dex_file, + uint32_t type_index, + vixl::Label* adrp_label = nullptr); + // Add a new PC-relative dex cache array patch for an instruction and return // the label to be bound before the instruction. The instruction will be // either the ADRP (pass `adrp_label = null`) or the LDR (pass `adrp_label` @@ -492,6 +506,8 @@ class CodeGeneratorARM64 : public CodeGenerator { vixl::Literal* DeduplicateBootImageStringLiteral(const DexFile& dex_file, uint32_t string_index); + vixl::Literal* DeduplicateBootImageTypeLiteral(const DexFile& dex_file, + uint32_t type_index); vixl::Literal* DeduplicateBootImageAddressLiteral(uint64_t address); vixl::Literal* DeduplicateDexCacheAddressLiteral(uint64_t address); @@ -589,6 +605,9 @@ class CodeGeneratorARM64 : public CodeGenerator { using BootStringToLiteralMap = ArenaSafeMap*, StringReferenceValueComparator>; + using BootTypeToLiteralMap = ArenaSafeMap*, + TypeReferenceValueComparator>; vixl::Literal* DeduplicateUint32Literal(uint32_t value, Uint32ToLiteralMap* map); vixl::Literal* DeduplicateUint64Literal(uint64_t value); @@ -598,13 +617,14 @@ class CodeGeneratorARM64 : public CodeGenerator { vixl::Literal* DeduplicateMethodCodeLiteral(MethodReference target_method); // The PcRelativePatchInfo is used for PC-relative addressing of dex cache arrays - // and boot image strings. The only difference is the interpretation of the offset_or_index. + // and boot image strings/types. The only difference is the interpretation of the + // offset_or_index. struct PcRelativePatchInfo { PcRelativePatchInfo(const DexFile& dex_file, uint32_t off_or_idx) : target_dex_file(dex_file), offset_or_index(off_or_idx), label(), pc_insn_label() { } const DexFile& target_dex_file; - // Either the dex cache array element offset or the string index. + // Either the dex cache array element offset or the string/type index. uint32_t offset_or_index; vixl::Label label; vixl::Label* pc_insn_label; @@ -646,6 +666,10 @@ class CodeGeneratorARM64 : public CodeGenerator { BootStringToLiteralMap boot_image_string_patches_; // PC-relative String patch info. ArenaDeque pc_relative_string_patches_; + // Deduplication map for boot type literals for kBootImageLinkTimeAddress. + BootTypeToLiteralMap boot_image_type_patches_; + // PC-relative type patch info. + ArenaDeque pc_relative_type_patches_; // Deduplication map for patchable boot image addresses. Uint32ToLiteralMap boot_image_address_patches_; diff --git a/compiler/optimizing/code_generator_mips.cc b/compiler/optimizing/code_generator_mips.cc index d5bad28dab..b2cebc0dbd 100644 --- a/compiler/optimizing/code_generator_mips.cc +++ b/compiler/optimizing/code_generator_mips.cc @@ -3769,6 +3769,13 @@ HLoadString::LoadKind CodeGeneratorMIPS::GetSupportedLoadStringKind( return HLoadString::LoadKind::kDexCacheViaMethod; } +HLoadClass::LoadKind CodeGeneratorMIPS::GetSupportedLoadClassKind( + HLoadClass::LoadKind desired_class_load_kind) { + DCHECK_NE(desired_class_load_kind, HLoadClass::LoadKind::kReferrersClass); + // TODO: Implement other kinds. + return HLoadClass::LoadKind::kDexCacheViaMethod; +} + HInvokeStaticOrDirect::DispatchInfo CodeGeneratorMIPS::GetSupportedInvokeStaticOrDirectDispatch( const HInvokeStaticOrDirect::DispatchInfo& desired_dispatch_info, MethodReference target_method ATTRIBUTE_UNUSED) { diff --git a/compiler/optimizing/code_generator_mips.h b/compiler/optimizing/code_generator_mips.h index 8c0bae628e..6487f28ad5 100644 --- a/compiler/optimizing/code_generator_mips.h +++ b/compiler/optimizing/code_generator_mips.h @@ -349,6 +349,11 @@ class CodeGeneratorMIPS : public CodeGenerator { HLoadString::LoadKind GetSupportedLoadStringKind( HLoadString::LoadKind desired_string_load_kind) OVERRIDE; + // Check if the desired_class_load_kind is supported. If it is, return it, + // otherwise return a fall-back kind that should be used instead. + HLoadClass::LoadKind GetSupportedLoadClassKind( + HLoadClass::LoadKind desired_class_load_kind) OVERRIDE; + // Check if the desired_dispatch_info is supported. If it is, return it, // otherwise return a fall-back info that should be used instead. HInvokeStaticOrDirect::DispatchInfo GetSupportedInvokeStaticOrDirectDispatch( diff --git a/compiler/optimizing/code_generator_mips64.cc b/compiler/optimizing/code_generator_mips64.cc index 539abf1de8..1a20f5c0fe 100644 --- a/compiler/optimizing/code_generator_mips64.cc +++ b/compiler/optimizing/code_generator_mips64.cc @@ -3016,6 +3016,13 @@ HLoadString::LoadKind CodeGeneratorMIPS64::GetSupportedLoadStringKind( return HLoadString::LoadKind::kDexCacheViaMethod; } +HLoadClass::LoadKind CodeGeneratorMIPS64::GetSupportedLoadClassKind( + HLoadClass::LoadKind desired_class_load_kind) { + DCHECK_NE(desired_class_load_kind, HLoadClass::LoadKind::kReferrersClass); + // TODO: Implement other kinds. + return HLoadClass::LoadKind::kDexCacheViaMethod; +} + HInvokeStaticOrDirect::DispatchInfo CodeGeneratorMIPS64::GetSupportedInvokeStaticOrDirectDispatch( const HInvokeStaticOrDirect::DispatchInfo& desired_dispatch_info, MethodReference target_method ATTRIBUTE_UNUSED) { diff --git a/compiler/optimizing/code_generator_mips64.h b/compiler/optimizing/code_generator_mips64.h index 9785a2e8a8..4b462cc800 100644 --- a/compiler/optimizing/code_generator_mips64.h +++ b/compiler/optimizing/code_generator_mips64.h @@ -340,6 +340,11 @@ class CodeGeneratorMIPS64 : public CodeGenerator { HLoadString::LoadKind GetSupportedLoadStringKind( HLoadString::LoadKind desired_string_load_kind) OVERRIDE; + // Check if the desired_class_load_kind is supported. If it is, return it, + // otherwise return a fall-back kind that should be used instead. + HLoadClass::LoadKind GetSupportedLoadClassKind( + HLoadClass::LoadKind desired_class_load_kind) OVERRIDE; + // Check if the desired_dispatch_info is supported. If it is, return it, // otherwise return a fall-back info that should be used instead. HInvokeStaticOrDirect::DispatchInfo GetSupportedInvokeStaticOrDirectDispatch( diff --git a/compiler/optimizing/code_generator_x86.cc b/compiler/optimizing/code_generator_x86.cc index a21c295274..a816d5f0e8 100644 --- a/compiler/optimizing/code_generator_x86.cc +++ b/compiler/optimizing/code_generator_x86.cc @@ -804,6 +804,7 @@ CodeGeneratorX86::CodeGeneratorX86(HGraph* graph, pc_relative_dex_cache_patches_(graph->GetArena()->Adapter(kArenaAllocCodeGenerator)), simple_patches_(graph->GetArena()->Adapter(kArenaAllocCodeGenerator)), string_patches_(graph->GetArena()->Adapter(kArenaAllocCodeGenerator)), + type_patches_(graph->GetArena()->Adapter(kArenaAllocCodeGenerator)), constant_area_start_(-1), fixups_to_jump_tables_(graph->GetArena()->Adapter(kArenaAllocCodeGenerator)), method_address_offset_(-1) { @@ -4452,6 +4453,11 @@ void CodeGeneratorX86::RecordStringPatch(HLoadString* load_string) { __ Bind(&string_patches_.back().label); } +void CodeGeneratorX86::RecordTypePatch(HLoadClass* load_class) { + type_patches_.emplace_back(load_class->GetDexFile(), load_class->GetTypeIndex()); + __ Bind(&type_patches_.back().label); +} + Label* CodeGeneratorX86::NewPcRelativeDexCacheArrayPatch(const DexFile& dex_file, uint32_t element_offset) { // Add the patch entry and bind its label at the end of the instruction. @@ -4466,7 +4472,8 @@ void CodeGeneratorX86::EmitLinkerPatches(ArenaVector* linker_patche relative_call_patches_.size() + pc_relative_dex_cache_patches_.size() + simple_patches_.size() + - string_patches_.size(); + string_patches_.size() + + type_patches_.size(); linker_patches->reserve(size); // The label points to the end of the "movl" insn but the literal offset for method // patch needs to point to the embedded constant which occupies the last 4 bytes. @@ -4502,6 +4509,13 @@ void CodeGeneratorX86::EmitLinkerPatches(ArenaVector* linker_patche GetMethodAddressOffset(), info.string_index)); } + for (const TypePatchInfo