diff options
Diffstat (limited to 'compiler/optimizing')
27 files changed, 421 insertions, 295 deletions
diff --git a/compiler/optimizing/bounds_check_elimination.cc b/compiler/optimizing/bounds_check_elimination.cc index 994d394a2a..529fc9e261 100644 --- a/compiler/optimizing/bounds_check_elimination.cc +++ b/compiler/optimizing/bounds_check_elimination.cc @@ -1361,6 +1361,11 @@ class BCEVisitor : public HGraphVisitor { ValueBound other_value = ValueBound::AsValueBound(other_index); int32_t other_c = other_value.GetConstant(); if (array_length == other_array_length && base == other_value.GetInstruction()) { + // Ensure every candidate could be picked for code generation. + bool b1 = false, b2 = false; + if (!induction_range_.CanGenerateRange(other_bounds_check, other_index, &b1, &b2)) { + continue; + } // Does the current basic block dominate all back edges? If not, // add this candidate later only if it falls into the range. if (!loop->DominatesAllBackEdges(user->GetBlock())) { diff --git a/compiler/optimizing/builder.cc b/compiler/optimizing/builder.cc index 86742e6526..2927e1f7c0 100644 --- a/compiler/optimizing/builder.cc +++ b/compiler/optimizing/builder.cc @@ -51,7 +51,7 @@ bool HGraphBuilder::SkipCompilation(size_t number_of_branches) { if (compiler_options.IsHugeMethod(code_item_.insns_size_in_code_units_)) { VLOG(compiler) << "Skip compilation of huge method " - << PrettyMethod(dex_compilation_unit_->GetDexMethodIndex(), *dex_file_) + << dex_file_->PrettyMethod(dex_compilation_unit_->GetDexMethodIndex()) << ": " << code_item_.insns_size_in_code_units_ << " code units"; MaybeRecordStat(MethodCompilationStat::kNotCompiledHugeMethod); return true; @@ -61,7 +61,7 @@ bool HGraphBuilder::SkipCompilation(size_t number_of_branches) { if (compiler_options.IsLargeMethod(code_item_.insns_size_in_code_units_) && (number_of_branches == 0)) { VLOG(compiler) << "Skip compilation of large method with no branch " - << PrettyMethod(dex_compilation_unit_->GetDexMethodIndex(), *dex_file_) + << dex_file_->PrettyMethod(dex_compilation_unit_->GetDexMethodIndex()) << ": " << code_item_.insns_size_in_code_units_ << " code units"; MaybeRecordStat(MethodCompilationStat::kNotCompiledLargeMethodNoBranches); return true; diff --git a/compiler/optimizing/code_generator.h b/compiler/optimizing/code_generator.h index 49f4f18390..a81f24e3d8 100644 --- a/compiler/optimizing/code_generator.h +++ b/compiler/optimizing/code_generator.h @@ -560,8 +560,6 @@ class CodeGenerator : public DeletableArenaObject<kArenaAllocCodeGenerator> { kArenaAllocCodeGenerator)), blocked_fpu_registers_(graph->GetArena()->AllocArray<bool>(number_of_fpu_registers, kArenaAllocCodeGenerator)), - blocked_register_pairs_(graph->GetArena()->AllocArray<bool>(number_of_register_pairs, - kArenaAllocCodeGenerator)), number_of_core_registers_(number_of_core_registers), number_of_fpu_registers_(number_of_fpu_registers), number_of_register_pairs_(number_of_register_pairs), @@ -649,7 +647,6 @@ class CodeGenerator : public DeletableArenaObject<kArenaAllocCodeGenerator> { // arrays. bool* const blocked_core_registers_; bool* const blocked_fpu_registers_; - bool* const blocked_register_pairs_; size_t number_of_core_registers_; size_t number_of_fpu_registers_; size_t number_of_register_pairs_; diff --git a/compiler/optimizing/code_generator_arm.cc b/compiler/optimizing/code_generator_arm.cc index 71aedec65a..9f92b20929 100644 --- a/compiler/optimizing/code_generator_arm.cc +++ b/compiler/optimizing/code_generator_arm.cc @@ -429,33 +429,49 @@ class LoadStringSlowPathARM : public SlowPathCodeARM { void EmitNativeCode(CodeGenerator* codegen) OVERRIDE { LocationSummary* locations = instruction_->GetLocations(); DCHECK(!locations->GetLiveRegisters()->ContainsCoreRegister(locations->Out().reg())); + HLoadString* load = instruction_->AsLoadString(); + const uint32_t string_index = load->GetStringIndex(); + Register out = locations->Out().AsRegister<Register>(); + Register temp = locations->GetTemp(0).AsRegister<Register>(); + constexpr bool call_saves_everything_except_r0 = (!kUseReadBarrier || kUseBakerReadBarrier); CodeGeneratorARM* arm_codegen = down_cast<CodeGeneratorARM*>(codegen); __ Bind(GetEntryLabel()); SaveLiveRegisters(codegen, locations); InvokeRuntimeCallingConvention calling_convention; - HLoadString* load = instruction_->AsLoadString(); - const uint32_t string_index = load->GetStringIndex(); + // In the unlucky case that the `temp` is R0, we preserve the address in `out` across + // the kSaveEverything call (or use `out` for the address after non-kSaveEverything call). + bool temp_is_r0 = (temp == calling_convention.GetRegisterAt(0)); + Register entry_address = temp_is_r0 ? out : temp; + DCHECK_NE(entry_address, calling_convention.GetRegisterAt(0)); + if (call_saves_everything_except_r0 && temp_is_r0) { + __ mov(entry_address, ShifterOperand(temp)); + } + __ LoadImmediate(calling_convention.GetRegisterAt(0), string_index); arm_codegen->InvokeRuntime(kQuickResolveString, instruction_, instruction_->GetDexPc(), this); CheckEntrypointTypes<kQuickResolveString, void*, uint32_t>(); - arm_codegen->Move32(locations->Out(), Location::RegisterLocation(R0)); - RestoreLiveRegisters(codegen, locations); + // Store the resolved String to the .bss entry. + if (call_saves_everything_except_r0) { + // The string entry address was preserved in `entry_address` thanks to kSaveEverything. + __ str(R0, Address(entry_address)); + } else { + // For non-Baker read barrier, we need to re-calculate the address of the string entry. + CodeGeneratorARM::PcRelativePatchInfo* labels = + arm_codegen->NewPcRelativeStringPatch(load->GetDexFile(), string_index); + __ BindTrackedLabel(&labels->movw_label); + __ movw(entry_address, /* placeholder */ 0u); + __ BindTrackedLabel(&labels->movt_label); + __ movt(entry_address, /* placeholder */ 0u); + __ BindTrackedLabel(&labels->add_pc_label); + __ add(entry_address, entry_address, ShifterOperand(PC)); + __ str(R0, Address(entry_address)); + } - // Store the resolved String to the BSS entry. - // TODO: Change art_quick_resolve_string to kSaveEverything and use a temporary for the - // .bss entry address in the fast path, so that we can avoid another calculation here. - CodeGeneratorARM::PcRelativePatchInfo* labels = - arm_codegen->NewPcRelativeStringPatch(load->GetDexFile(), string_index); - __ BindTrackedLabel(&labels->movw_label); - __ movw(IP, /* placeholder */ 0u); - __ BindTrackedLabel(&labels->movt_label); - __ movt(IP, /* placeholder */ 0u); - __ BindTrackedLabel(&labels->add_pc_label); - __ add(IP, IP, ShifterOperand(PC)); - __ str(locations->Out().AsRegister<Register>(), Address(IP)); + arm_codegen->Move32(locations->Out(), Location::RegisterLocation(R0)); + RestoreLiveRegisters(codegen, locations); __ b(GetExitLabel()); } @@ -1031,9 +1047,6 @@ void CodeGeneratorARM::Finalize(CodeAllocator* allocator) { } void CodeGeneratorARM::SetupBlockedRegisters() const { - // Don't allocate the dalvik style register pair passing. - blocked_register_pairs_[R1_R2] = true; - // Stack register, LR and PC are always reserved. blocked_core_registers_[SP] = true; blocked_core_registers_[LR] = true; @@ -1053,19 +1066,6 @@ void CodeGeneratorARM::SetupBlockedRegisters() const { blocked_fpu_registers_[kFpuCalleeSaves[i]] = true; } } - - UpdateBlockedPairRegisters(); -} - -void CodeGeneratorARM::UpdateBlockedPairRegisters() const { - for (int i = 0; i < kNumberOfRegisterPairs; i++) { - ArmManagedRegister current = - ArmManagedRegister::FromRegisterPair(static_cast<RegisterPair>(i)); - if (blocked_core_registers_[current.AsRegisterPairLow()] - || blocked_core_registers_[current.AsRegisterPairHigh()]) { - blocked_register_pairs_[i] = true; - } - } } InstructionCodeGeneratorARM::InstructionCodeGeneratorARM(HGraph* graph, CodeGeneratorARM* codegen) @@ -5710,10 +5710,25 @@ void LocationsBuilderARM::VisitLoadString(HLoadString* load) { HLoadString::LoadKind load_kind = load->GetLoadKind(); if (load_kind == HLoadString::LoadKind::kDexCacheViaMethod) { - locations->SetInAt(0, Location::RequiresRegister()); locations->SetOut(Location::RegisterLocation(R0)); } else { locations->SetOut(Location::RequiresRegister()); + if (load_kind == HLoadString::LoadKind::kBssEntry) { + if (!kUseReadBarrier || kUseBakerReadBarrier) { + // Rely on the pResolveString and/or marking to save everything, including temps. + // Note that IP may theoretically be clobbered by saving/restoring the live register + // (only one thanks to the custom calling convention), so we request a different temp. + locations->AddTemp(Location::RequiresRegister()); + RegisterSet caller_saves = RegisterSet::Empty(); + InvokeRuntimeCallingConvention calling_convention; + caller_saves.Add(Location::RegisterLocation(calling_convention.GetRegisterAt(0))); + // TODO: Add GetReturnLocation() to the calling convention so that we can DCHECK() + // that the the kPrimNot result register is the same as the first argument register. + locations->SetCustomSlowPathCallerSaves(caller_saves); + } else { + // For non-Baker read barrier we have a temp-clobbering call. + } + } } } @@ -5749,15 +5764,16 @@ void InstructionCodeGeneratorARM::VisitLoadString(HLoadString* load) { } case HLoadString::LoadKind::kBssEntry: { DCHECK(!codegen_->GetCompilerOptions().IsBootImage()); + Register temp = locations->GetTemp(0).AsRegister<Register>(); CodeGeneratorARM::PcRelativePatchInfo* labels = codegen_->NewPcRelativeStringPatch(load->GetDexFile(), load->GetStringIndex()); __ BindTrackedLabel(&labels->movw_label); - __ movw(out, /* placeholder */ 0u); + __ movw(temp, /* placeholder */ 0u); __ BindTrackedLabel(&labels->movt_label); - __ movt(out, /* placeholder */ 0u); + __ movt(temp, /* placeholder */ 0u); __ BindTrackedLabel(&labels->add_pc_label); - __ add(out, out, ShifterOperand(PC)); - GenerateGcRootFieldLoad(load, out_loc, out, 0); + __ add(temp, temp, ShifterOperand(PC)); + GenerateGcRootFieldLoad(load, out_loc, temp, 0); SlowPathCode* slow_path = new (GetGraph()->GetArena()) LoadStringSlowPathARM(load); codegen_->AddSlowPath(slow_path); __ CompareAndBranchIfZero(out, slow_path->GetEntryLabel()); @@ -5771,6 +5787,7 @@ void InstructionCodeGeneratorARM::VisitLoadString(HLoadString* load) { // TODO: Consider re-adding the compiler code to do string dex cache lookup again. DCHECK(load_kind == HLoadString::LoadKind::kDexCacheViaMethod); InvokeRuntimeCallingConvention calling_convention; + DCHECK_EQ(calling_convention.GetRegisterAt(0), out); __ LoadImmediate(calling_convention.GetRegisterAt(0), load->GetStringIndex()); codegen_->InvokeRuntime(kQuickResolveString, load, load->GetDexPc()); CheckEntrypointTypes<kQuickResolveString, void*, uint32_t>(); diff --git a/compiler/optimizing/code_generator_arm.h b/compiler/optimizing/code_generator_arm.h index ef2e23f258..4d59b47861 100644 --- a/compiler/optimizing/code_generator_arm.h +++ b/compiler/optimizing/code_generator_arm.h @@ -365,9 +365,6 @@ class CodeGeneratorARM : public CodeGenerator { void DumpCoreRegister(std::ostream& stream, int reg) const OVERRIDE; void DumpFloatingPointRegister(std::ostream& stream, int reg) const OVERRIDE; - // Blocks all register pairs made out of blocked core registers. - void UpdateBlockedPairRegisters() const; - ParallelMoveResolverARM* GetMoveResolver() OVERRIDE { return &move_resolver_; } diff --git a/compiler/optimizing/code_generator_arm64.cc b/compiler/optimizing/code_generator_arm64.cc index f02b028541..9e59d8cc38 100644 --- a/compiler/optimizing/code_generator_arm64.cc +++ b/compiler/optimizing/code_generator_arm64.cc @@ -331,13 +331,20 @@ class LoadClassSlowPathARM64 : public SlowPathCodeARM64 { class LoadStringSlowPathARM64 : public SlowPathCodeARM64 { public: - explicit LoadStringSlowPathARM64(HLoadString* instruction) : SlowPathCodeARM64(instruction) {} + LoadStringSlowPathARM64(HLoadString* instruction, Register temp, vixl::aarch64::Label* adrp_label) + : SlowPathCodeARM64(instruction), + temp_(temp), + adrp_label_(adrp_label) {} void EmitNativeCode(CodeGenerator* codegen) OVERRIDE { LocationSummary* locations = instruction_->GetLocations(); DCHECK(!locations->GetLiveRegisters()->ContainsCoreRegister(locations->Out().reg())); CodeGeneratorARM64* arm64_codegen = down_cast<CodeGeneratorARM64*>(codegen); + // temp_ is a scratch register. Make sure it's not used for saving/restoring registers. + UseScratchRegisterScope temps(arm64_codegen->GetVIXLAssembler()); + temps.Exclude(temp_); + __ Bind(GetEntryLabel()); SaveLiveRegisters(codegen, locations); @@ -352,21 +359,21 @@ class LoadStringSlowPathARM64 : public SlowPathCodeARM64 { RestoreLiveRegisters(codegen, locations); // Store the resolved String to the BSS entry. - UseScratchRegisterScope temps(arm64_codegen->GetVIXLAssembler()); - Register temp = temps.AcquireX(); const DexFile& dex_file = instruction_->AsLoadString()->GetDexFile(); - // TODO: Change art_quick_resolve_string to kSaveEverything and use a temporary - // for the ADRP in the fast path, so that we can avoid the ADRP here. - vixl::aarch64::Label* adrp_label = - arm64_codegen->NewPcRelativeStringPatch(dex_file, string_index); - arm64_codegen->EmitAdrpPlaceholder(adrp_label, temp); + if (!kUseReadBarrier || kUseBakerReadBarrier) { + // The string entry page address was preserved in temp_ thanks to kSaveEverything. + } else { + // For non-Baker read barrier, we need to re-calculate the address of the string entry page. + adrp_label_ = arm64_codegen->NewPcRelativeStringPatch(dex_file, string_index); + arm64_codegen->EmitAdrpPlaceholder(adrp_label_, temp_); + } vixl::aarch64::Label* strp_label = - arm64_codegen->NewPcRelativeStringPatch(dex_file, string_index, adrp_label); + arm64_codegen->NewPcRelativeStringPatch(dex_file, string_index, adrp_label_); { SingleEmissionCheckScope guard(arm64_codegen->GetVIXLAssembler()); __ Bind(strp_label); __ str(RegisterFrom(locations->Out(), Primitive::kPrimNot), - MemOperand(temp, /* offset placeholder */ 0)); + MemOperand(temp_, /* offset placeholder */ 0)); } __ B(GetExitLabel()); @@ -375,6 +382,9 @@ class LoadStringSlowPathARM64 : public SlowPathCodeARM64 { const char* GetDescription() const OVERRIDE { return "LoadStringSlowPathARM64"; } private: + const Register temp_; + vixl::aarch64::Label* adrp_label_; + DISALLOW_COPY_AND_ASSIGN(LoadStringSlowPathARM64); }; @@ -4246,11 +4256,24 @@ void LocationsBuilderARM64::VisitLoadString(HLoadString* load) { : LocationSummary::kNoCall; LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(load, call_kind); if (load->GetLoadKind() == HLoadString::LoadKind::kDexCacheViaMethod) { - locations->SetInAt(0, Location::RequiresRegister()); InvokeRuntimeCallingConvention calling_convention; locations->SetOut(calling_convention.GetReturnLocation(load->GetType())); } else { locations->SetOut(Location::RequiresRegister()); + if (load->GetLoadKind() == HLoadString::LoadKind::kBssEntry) { + if (!kUseReadBarrier || kUseBakerReadBarrier) { + // Rely on the pResolveString and/or marking to save everything, including temps. + RegisterSet caller_saves = RegisterSet::Empty(); + InvokeRuntimeCallingConvention calling_convention; + caller_saves.Add(Location::RegisterLocation(calling_convention.GetRegisterAt(0).GetCode())); + DCHECK_EQ(calling_convention.GetRegisterAt(0).GetCode(), + RegisterFrom(calling_convention.GetReturnLocation(Primitive::kPrimNot), + Primitive::kPrimNot).GetCode()); + locations->SetCustomSlowPathCallerSaves(caller_saves); + } else { + // For non-Baker read barrier we have a temp-clobbering call. + } + } } } @@ -4285,18 +4308,21 @@ void InstructionCodeGeneratorARM64::VisitLoadString(HLoadString* load) { const DexFile& dex_file = load->GetDexFile(); uint32_t string_index = load->GetStringIndex(); DCHECK(!codegen_->GetCompilerOptions().IsBootImage()); + UseScratchRegisterScope temps(codegen_->GetVIXLAssembler()); + Register temp = temps.AcquireX(); vixl::aarch64::Label* adrp_label = codegen_->NewPcRelativeStringPatch(dex_file, string_index); - codegen_->EmitAdrpPlaceholder(adrp_label, out.X()); + codegen_->EmitAdrpPlaceholder(adrp_label, temp); // Add LDR with its PC-relative String patch. vixl::aarch64::Label* ldr_label = codegen_->NewPcRelativeStringPatch(dex_file, string_index, adrp_label); // /* GcRoot<mirror::Class> */ out = *(base_address + offset) /* PC-relative */ GenerateGcRootFieldLoad(load, load->GetLocations()->Out(), - out.X(), + temp, /* placeholder */ 0u, ldr_label); - SlowPathCodeARM64* slow_path = new (GetGraph()->GetArena()) LoadStringSlowPathARM64(load); + SlowPathCodeARM64* slow_path = + new (GetGraph()->GetArena()) LoadStringSlowPathARM64(load, temp, adrp_label); codegen_->AddSlowPath(slow_path); __ Cbz(out.X(), slow_path->GetEntryLabel()); __ Bind(slow_path->GetExitLabel()); @@ -4308,6 +4334,7 @@ void InstructionCodeGeneratorARM64::VisitLoadString(HLoadString* load) { // TODO: Re-add the compiler code to do string dex cache lookup again. InvokeRuntimeCallingConvention calling_convention; + DCHECK_EQ(calling_convention.GetRegisterAt(0).GetCode(), out.GetCode()); __ Mov(calling_convention.GetRegisterAt(0).W(), load->GetStringIndex()); codegen_->InvokeRuntime(kQuickResolveString, load, load->GetDexPc()); CheckEntrypointTypes<kQuickResolveString, void*, uint32_t>(); diff --git a/compiler/optimizing/code_generator_arm_vixl.cc b/compiler/optimizing/code_generator_arm_vixl.cc index b1a941d12a..32287a0f2a 100644 --- a/compiler/optimizing/code_generator_arm_vixl.cc +++ b/compiler/optimizing/code_generator_arm_vixl.cc @@ -498,9 +498,6 @@ void CodeGeneratorARMVIXL::Finalize(CodeAllocator* allocator) { } void CodeGeneratorARMVIXL::SetupBlockedRegisters() const { - // Don't allocate the dalvik style register pair passing. - blocked_register_pairs_[R1_R2] = true; - // Stack register, LR and PC are always reserved. blocked_core_registers_[SP] = true; blocked_core_registers_[LR] = true; @@ -522,20 +519,6 @@ void CodeGeneratorARMVIXL::SetupBlockedRegisters() const { blocked_fpu_registers_[i] = true; } } - - UpdateBlockedPairRegisters(); -} - -// Blocks all register pairs containing blocked core registers. -void CodeGeneratorARMVIXL::UpdateBlockedPairRegisters() const { - for (int i = 0; i < kNumberOfRegisterPairs; i++) { - ArmManagedRegister current = - ArmManagedRegister::FromRegisterPair(static_cast<RegisterPair>(i)); - if (blocked_core_registers_[current.AsRegisterPairLow()] - || blocked_core_registers_[current.AsRegisterPairHigh()]) { - blocked_register_pairs_[i] = true; - } - } } InstructionCodeGeneratorARMVIXL::InstructionCodeGeneratorARMVIXL(HGraph* graph, diff --git a/compiler/optimizing/code_generator_arm_vixl.h b/compiler/optimizing/code_generator_arm_vixl.h index 3c8d027339..c749f8620a 100644 --- a/compiler/optimizing/code_generator_arm_vixl.h +++ b/compiler/optimizing/code_generator_arm_vixl.h @@ -414,9 +414,6 @@ class CodeGeneratorARMVIXL : public CodeGenerator { void Finalize(CodeAllocator* allocator) OVERRIDE; void SetupBlockedRegisters() const OVERRIDE; - // Blocks all register pairs made out of blocked core registers. - void UpdateBlockedPairRegisters() const; - void DumpCoreRegister(std::ostream& stream, int reg) const OVERRIDE; void DumpFloatingPointRegister(std::ostream& stream, int reg) const OVERRIDE; diff --git a/compiler/optimizing/code_generator_mips.cc b/compiler/optimizing/code_generator_mips.cc index e336df8c6c..bab702a949 100644 --- a/compiler/optimizing/code_generator_mips.cc +++ b/compiler/optimizing/code_generator_mips.cc @@ -1168,9 +1168,6 @@ void CodeGeneratorMIPS::MarkGCCard(Register object, Register value) { } void CodeGeneratorMIPS::SetupBlockedRegisters() const { - // Don't allocate the dalvik style register pair passing. - blocked_register_pairs_[A1_A2] = true; - // ZERO, K0, K1, GP, SP, RA are always reserved and can't be allocated. blocked_core_registers_[ZERO] = true; blocked_core_registers_[K0] = true; @@ -1205,19 +1202,6 @@ void CodeGeneratorMIPS::SetupBlockedRegisters() const { blocked_fpu_registers_[kFpuCalleeSaves[i]] = true; } } - - UpdateBlockedPairRegisters(); -} - -void CodeGeneratorMIPS::UpdateBlockedPairRegisters() const { - for (int i = 0; i < kNumberOfRegisterPairs; i++) { - MipsManagedRegister current = - MipsManagedRegister::FromRegisterPair(static_cast<RegisterPair>(i)); - if (blocked_core_registers_[current.AsRegisterPairLow()] - || blocked_core_registers_[current.AsRegisterPairHigh()]) { - blocked_register_pairs_[i] = true; - } - } } size_t CodeGeneratorMIPS::SaveCoreRegister(size_t stack_index, uint32_t reg_id) { diff --git a/compiler/optimizing/code_generator_mips.h b/compiler/optimizing/code_generator_mips.h index 0e8d8d40cf..b8bd96a545 100644 --- a/compiler/optimizing/code_generator_mips.h +++ b/compiler/optimizing/code_generator_mips.h @@ -342,9 +342,6 @@ class CodeGeneratorMIPS : public CodeGenerator { void DumpCoreRegister(std::ostream& stream, int reg) const OVERRIDE; void DumpFloatingPointRegister(std::ostream& stream, int reg) const OVERRIDE; - // Blocks all register pairs made out of blocked core registers. - void UpdateBlockedPairRegisters() const; - InstructionSet GetInstructionSet() const OVERRIDE { return InstructionSet::kMips; } const MipsInstructionSetFeatures& GetInstructionSetFeatures() const { diff --git a/compiler/optimizing/code_generator_x86.cc b/compiler/optimizing/code_generator_x86.cc index 960f01ce9d..02c1c3b69f 100644 --- a/compiler/optimizing/code_generator_x86.cc +++ b/compiler/optimizing/code_generator_x86.cc @@ -841,24 +841,8 @@ CodeGeneratorX86::CodeGeneratorX86(HGraph* graph, } void CodeGeneratorX86::SetupBlockedRegisters() const { - // Don't allocate the dalvik style register pair passing. - blocked_register_pairs_[ECX_EDX] = true; - // Stack register is always reserved. blocked_core_registers_[ESP] = true; - - UpdateBlockedPairRegisters(); -} - -void CodeGeneratorX86::UpdateBlockedPairRegisters() const { - for (int i = 0; i < kNumberOfRegisterPairs; i++) { - X86ManagedRegister current = - X86ManagedRegister::FromRegisterPair(static_cast<RegisterPair>(i)); - if (blocked_core_registers_[current.AsRegisterPairLow()] - || blocked_core_registers_[current.AsRegisterPairHigh()]) { - blocked_register_pairs_[i] = true; - } - } } InstructionCodeGeneratorX86::InstructionCodeGeneratorX86(HGraph* graph, CodeGeneratorX86* codegen) @@ -6064,8 +6048,7 @@ void LocationsBuilderX86::VisitLoadString(HLoadString* load) { : LocationSummary::kNoCall; LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(load, call_kind); HLoadString::LoadKind load_kind = load->GetLoadKind(); - if (load_kind == HLoadString::LoadKind::kDexCacheViaMethod || - load_kind == HLoadString::LoadKind::kBootImageLinkTimePcRelative || + if (load_kind == HLoadString::LoadKind::kBootImageLinkTimePcRelative || load_kind == HLoadString::LoadKind::kBssEntry) { locations->SetInAt(0, Location::RequiresRegister()); } @@ -6073,6 +6056,17 @@ void LocationsBuilderX86::VisitLoadString(HLoadString* load) { locations->SetOut(Location::RegisterLocation(EAX)); } else { locations->SetOut(Location::RequiresRegister()); + if (load_kind == HLoadString::LoadKind::kBssEntry) { + if (!kUseReadBarrier || kUseBakerReadBarrier) { + // Rely on the pResolveString and/or marking to save everything. + RegisterSet caller_saves = RegisterSet::Empty(); + InvokeRuntimeCallingConvention calling_convention; + caller_saves.Add(Location::RegisterLocation(calling_convention.GetRegisterAt(0))); + locations->SetCustomSlowPathCallerSaves(caller_saves); + } else { + // For non-Baker read barrier we have a temp-clobbering call. + } + } } } @@ -6119,6 +6113,7 @@ void InstructionCodeGeneratorX86::VisitLoadString(HLoadString* load) { // TODO: Re-add the compiler code to do string dex cache lookup again. InvokeRuntimeCallingConvention calling_convention; + DCHECK_EQ(calling_convention.GetRegisterAt(0), out); __ movl(calling_convention.GetRegisterAt(0), Immediate(load->GetStringIndex())); codegen_->InvokeRuntime(kQuickResolveString, load, load->GetDexPc()); CheckEntrypointTypes<kQuickResolveString, void*, uint32_t>(); diff --git a/compiler/optimizing/code_generator_x86.h b/compiler/optimizing/code_generator_x86.h index 25f5c2a58f..e7d9a43f58 100644 --- a/compiler/optimizing/code_generator_x86.h +++ b/compiler/optimizing/code_generator_x86.h @@ -372,9 +372,6 @@ class CodeGeneratorX86 : public CodeGenerator { void DumpCoreRegister(std::ostream& stream, int reg) const OVERRIDE; void DumpFloatingPointRegister(std::ostream& stream, int reg) const OVERRIDE; - // Blocks all register pairs made out of blocked core registers. - void UpdateBlockedPairRegisters() const; - ParallelMoveResolverX86* GetMoveResolver() OVERRIDE { return &move_resolver_; } diff --git a/compiler/optimizing/code_generator_x86_64.cc b/compiler/optimizing/code_generator_x86_64.cc index 665d028338..4b64c1b6ff 100644 --- a/compiler/optimizing/code_generator_x86_64.cc +++ b/compiler/optimizing/code_generator_x86_64.cc @@ -299,9 +299,9 @@ class LoadStringSlowPathX86_64 : public SlowPathCode { __ Bind(GetEntryLabel()); SaveLiveRegisters(codegen, locations); - InvokeRuntimeCallingConvention calling_convention; const uint32_t string_index = instruction_->AsLoadString()->GetStringIndex(); - __ movl(CpuRegister(calling_convention.GetRegisterAt(0)), Immediate(string_index)); + // Custom calling convention: RAX serves as both input and output. + __ movl(CpuRegister(RAX), Immediate(string_index)); x86_64_codegen->InvokeRuntime(kQuickResolveString, instruction_, instruction_->GetDexPc(), @@ -457,7 +457,8 @@ class ReadBarrierMarkSlowPathX86_64 : public SlowPathCode { void EmitNativeCode(CodeGenerator* codegen) OVERRIDE { LocationSummary* locations = instruction_->GetLocations(); - Register reg = obj_.AsRegister<Register>(); + CpuRegister cpu_reg = obj_.AsRegister<CpuRegister>(); + Register reg = cpu_reg.AsRegister(); DCHECK(locations->CanCall()); DCHECK(!locations->GetLiveRegisters()->ContainsCoreRegister(reg)); DCHECK(instruction_->IsInstanceFieldGet() || @@ -476,7 +477,7 @@ class ReadBarrierMarkSlowPathX86_64 : public SlowPathCode { __ Bind(GetEntryLabel()); if (unpoison_) { // Object* ref = ref_addr->AsMirrorPtr() - __ MaybeUnpoisonHeapReference(obj_.AsRegister<CpuRegister>()); + __ MaybeUnpoisonHeapReference(cpu_reg); } // No need to save live registers; it's taken care of by the // entrypoint. Also, there is no need to update the stack mask, @@ -5455,10 +5456,20 @@ void LocationsBuilderX86_64::VisitLoadString(HLoadString* load) { : LocationSummary::kNoCall; LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(load, call_kind); if (load->GetLoadKind() == HLoadString::LoadKind::kDexCacheViaMethod) { - locations->SetInAt(0, Location::RequiresRegister()); locations->SetOut(Location::RegisterLocation(RAX)); } else { locations->SetOut(Location::RequiresRegister()); + if (load->GetLoadKind() == HLoadString::LoadKind::kBssEntry) { + if (!kUseReadBarrier || kUseBakerReadBarrier) { + // Rely on the pResolveString and/or marking to save everything. + // Custom calling convention: RAX serves as both input and output. + RegisterSet caller_saves = RegisterSet::Empty(); + caller_saves.Add(Location::RegisterLocation(RAX)); + locations->SetCustomSlowPathCallerSaves(caller_saves); + } else { + // For non-Baker read barrier we have a temp-clobbering call. + } + } } } @@ -5498,9 +5509,8 @@ void InstructionCodeGeneratorX86_64::VisitLoadString(HLoadString* load) { } // TODO: Re-add the compiler code to do string dex cache lookup again. - InvokeRuntimeCallingConvention calling_convention; - __ movl(CpuRegister(calling_convention.GetRegisterAt(0)), - Immediate(load->GetStringIndex())); + // Custom calling convention: RAX serves as both input and output. + __ movl(CpuRegister(RAX), Immediate(load->GetStringIndex())); codegen_->InvokeRuntime(kQuickResolveString, load, load->GetDexPc()); diff --git a/compiler/optimizing/codegen_test.cc b/compiler/optimizing/codegen_test.cc index f19faa324c..9ec32df578 100644 --- a/compiler/optimizing/codegen_test.cc +++ b/compiler/optimizing/codegen_test.cc @@ -115,8 +115,6 @@ class TestCodeGeneratorARM : public arm::CodeGeneratorARM { blocked_core_registers_[arm::R4] = true; blocked_core_registers_[arm::R6] = false; blocked_core_registers_[arm::R7] = false; - // Makes pair R6-R7 available. - blocked_register_pairs_[arm::R6_R7] = false; } }; @@ -137,8 +135,6 @@ class TestCodeGeneratorARMVIXL : public arm::CodeGeneratorARMVIXL { blocked_core_registers_[arm::R4] = true; blocked_core_registers_[arm::R6] = false; blocked_core_registers_[arm::R7] = false; - // Makes pair R6-R7 available. - blocked_register_pairs_[arm::R6_R7] = false; } }; #endif @@ -158,14 +154,9 @@ class TestCodeGeneratorX86 : public x86::CodeGeneratorX86 { x86::CodeGeneratorX86::SetupBlockedRegisters(); // ebx is a callee-save register in C, but caller-save for ART. blocked_core_registers_[x86::EBX] = true; - blocked_register_pairs_[x86::EAX_EBX] = true; - blocked_register_pairs_[x86::EDX_EBX] = true; - blocked_register_pairs_[x86::ECX_EBX] = true; - blocked_register_pairs_[x86::EBX_EDI] = true; // Make edi available. blocked_core_registers_[x86::EDI] = false; - blocked_register_pairs_[x86::ECX_EDI] = false; } }; #endif diff --git a/compiler/optimizing/graph_visualizer.cc b/compiler/optimizing/graph_visualizer.cc index 912ee29cdb..09dcefa02c 100644 --- a/compiler/optimizing/graph_visualizer.cc +++ b/compiler/optimizing/graph_visualizer.cc @@ -441,8 +441,8 @@ class HGraphVisualizerPrinter : public HGraphDelegateVisitor { void VisitInvoke(HInvoke* invoke) OVERRIDE { StartAttributeStream("dex_file_index") << invoke->GetDexMethodIndex(); - StartAttributeStream("method_name") << PrettyMethod( - invoke->GetDexMethodIndex(), GetGraph()->GetDexFile(), /* with_signature */ false); + StartAttributeStream("method_name") << GetGraph()->GetDexFile().PrettyMethod( + invoke->GetDexMethodIndex(), /* with_signature */ false); } void VisitInvokeUnresolved(HInvokeUnresolved* invoke) OVERRIDE { @@ -465,15 +465,15 @@ class HGraphVisualizerPrinter : public HGraphDelegateVisitor { } void VisitInstanceFieldGet(HInstanceFieldGet* iget) OVERRIDE { - StartAttributeStream("field_name") << PrettyField(iget->GetFieldInfo().GetFieldIndex(), - iget->GetFieldInfo().GetDexFile(), + StartAttributeStream("field_name") << + iget->GetFieldInfo().GetDexFile().PrettyField(iget->GetFieldInfo().GetFieldIndex(), /* with type */ false); StartAttributeStream("field_type") << iget->GetFieldType(); } void VisitInstanceFieldSet(HInstanceFieldSet* iset) OVERRIDE { - StartAttributeStream("field_name") << PrettyField(iset->GetFieldInfo().GetFieldIndex(), - iset->GetFieldInfo().GetDexFile(), + StartAttributeStream("field_name") << + iset->GetFieldInfo().GetDexFile().PrettyField(iset->GetFieldInfo().GetFieldIndex(), /* with type */ false); StartAttributeStream("field_type") << iset->GetFieldType(); } @@ -604,7 +604,8 @@ class HGraphVisualizerPrinter : public HGraphDelegateVisitor { : instruction->GetReferenceTypeInfo(); ScopedObjectAccess soa(Thread::Current()); if (info.IsValid()) { - StartAttributeStream("klass") << PrettyDescriptor(info.GetTypeHandle().Get()); + StartAttributeStream("klass") + << mirror::Class::PrettyDescriptor(info.GetTypeHandle().Get()); StartAttributeStream("can_be_null") << std::boolalpha << instruction->CanBeNull() << std::noboolalpha; StartAttributeStream("exact") << std::boolalpha << info.IsExact() << std::noboolalpha; diff --git a/compiler/optimizing/induction_var_range.cc b/compiler/optimizing/induction_var_range.cc index 140c7f0c40..663cbaf2de 100644 --- a/compiler/optimizing/induction_var_range.cc +++ b/compiler/optimizing/induction_var_range.cc @@ -162,17 +162,17 @@ bool InductionVarRange::CanGenerateRange(HInstruction* context, /*out*/bool* needs_taken_test) { bool is_last_value = false; int64_t stride_value = 0; - return GenerateCode(context, - instruction, - is_last_value, - nullptr, - nullptr, - nullptr, - nullptr, - nullptr, // nothing generated yet - &stride_value, - needs_finite_test, - needs_taken_test) + return GenerateRangeOrLastValue(context, + instruction, + is_last_value, + nullptr, + nullptr, + nullptr, + nullptr, + nullptr, // nothing generated yet + &stride_value, + needs_finite_test, + needs_taken_test) && (stride_value == -1 || stride_value == 0 || stride_value == 1); // avoid wrap-around anomalies. @@ -187,17 +187,17 @@ void InductionVarRange::GenerateRange(HInstruction* context, bool is_last_value = false; int64_t stride_value = 0; bool b1, b2; // unused - if (!GenerateCode(context, - instruction, - is_last_value, - graph, - block, - lower, - upper, - nullptr, - &stride_value, - &b1, - &b2)) { + if (!GenerateRangeOrLastValue(context, + instruction, + is_last_value, + graph, + block, + lower, + upper, + nullptr, + &stride_value, + &b1, + &b2)) { LOG(FATAL) << "Failed precondition: CanGenerateRange()"; } } @@ -209,17 +209,17 @@ HInstruction* InductionVarRange::GenerateTakenTest(HInstruction* context, bool is_last_value = false; int64_t stride_value = 0; bool b1, b2; // unused - if (!GenerateCode(context, - context, - is_last_value, - graph, - block, - nullptr, - nullptr, - &taken_test, - &stride_value, - &b1, - &b2)) { + if (!GenerateRangeOrLastValue(context, + context, + is_last_value, + graph, + block, + nullptr, + nullptr, + &taken_test, + &stride_value, + &b1, + &b2)) { LOG(FATAL) << "Failed precondition: CanGenerateRange()"; } return taken_test; @@ -230,17 +230,17 @@ bool InductionVarRange::CanGenerateLastValue(HInstruction* instruction) { int64_t stride_value = 0; bool needs_finite_test = false; bool needs_taken_test = false; - return GenerateCode(instruction, - instruction, - is_last_value, - nullptr, - nullptr, - nullptr, - nullptr, - nullptr, // nothing generated yet - &stride_value, - &needs_finite_test, - &needs_taken_test) + return GenerateRangeOrLastValue(instruction, + instruction, + is_last_value, + nullptr, + nullptr, + nullptr, + nullptr, + nullptr, // nothing generated yet + &stride_value, + &needs_finite_test, + &needs_taken_test) && !needs_finite_test && !needs_taken_test; } @@ -251,17 +251,17 @@ HInstruction* InductionVarRange::GenerateLastValue(HInstruction* instruction, bool is_last_value = true; int64_t stride_value = 0; bool b1, b2; // unused - if (!GenerateCode(instruction, - instruction, - is_last_value, - graph, - block, - &last_value, - &last_value, - nullptr, - &stride_value, - &b1, - &b2)) { + if (!GenerateRangeOrLastValue(instruction, + instruction, + is_last_value, + graph, + block, + &last_value, + &last_value, + nullptr, + &stride_value, + &b1, + &b2)) { LOG(FATAL) << "Failed precondition: CanGenerateLastValue()"; } return last_value; @@ -280,6 +280,12 @@ void InductionVarRange::Replace(HInstruction* instruction, } } +bool InductionVarRange::IsFinite(HLoopInformation* loop) const { + HInductionVarAnalysis::InductionInfo *trip = + induction_analysis_->LookupInfo(loop, GetLoopControl(loop)); + return trip != nullptr && !IsUnsafeTripCount(trip); +} + // // Private class methods. // @@ -732,17 +738,17 @@ InductionVarRange::Value InductionVarRange::MergeVal(Value v1, Value v2, bool is return Value(); } -bool InductionVarRange::GenerateCode(HInstruction* context, - HInstruction* instruction, - bool is_last_value, - HGraph* graph, - HBasicBlock* block, - /*out*/HInstruction** lower, - /*out*/HInstruction** upper, - /*out*/HInstruction** taken_test, - /*out*/int64_t* stride_value, - /*out*/bool* needs_finite_test, - /*out*/bool* needs_taken_test) const { +bool InductionVarRange::GenerateRangeOrLastValue(HInstruction* context, + HInstruction* instruction, + bool is_last_value, + HGraph* graph, + HBasicBlock* block, + /*out*/HInstruction** lower, + /*out*/HInstruction** upper, + /*out*/HInstruction** taken_test, + /*out*/int64_t* stride_value, + /*out*/bool* needs_finite_test, + /*out*/bool* needs_taken_test) const { HLoopInformation* loop = nullptr; HInductionVarAnalysis::InductionInfo* info = nullptr; HInductionVarAnalysis::InductionInfo* trip = nullptr; @@ -760,12 +766,17 @@ bool InductionVarRange::GenerateCode(HInstruction* context, *needs_taken_test = IsBodyTripCount(trip); // Handle last value request. if (is_last_value) { - if (info->induction_class != HInductionVarAnalysis::kLinear) { - return false; - } else if (*stride_value > 0) { - lower = nullptr; + if (info->induction_class == HInductionVarAnalysis::kLinear) { + if (*stride_value > 0) { + lower = nullptr; + } else { + upper = nullptr; + } + } else if (info->induction_class == HInductionVarAnalysis::kPeriodic) { + DCHECK(!in_body); + return GenerateLastValuePeriodic(info, trip, graph, block, lower, needs_taken_test); } else { - upper = nullptr; + return false; } } // Code generation for taken test: generate the code when requested or otherwise analyze @@ -787,6 +798,56 @@ bool InductionVarRange::GenerateCode(HInstruction* context, GenerateCode(info, trip, graph, block, upper, in_body, /* is_min */ false); } +bool InductionVarRange::GenerateLastValuePeriodic(HInductionVarAnalysis::InductionInfo* info, + HInductionVarAnalysis::InductionInfo* trip, + HGraph* graph, + HBasicBlock* block, + /*out*/HInstruction** result, + /*out*/bool* needs_taken_test) const { + DCHECK(info->induction_class == HInductionVarAnalysis::kPeriodic); + // Count period. + int32_t period = 1; + for (HInductionVarAnalysis::InductionInfo* p = info; + p->induction_class == HInductionVarAnalysis::kPeriodic; + p = p->op_b, ++period) {} + // Handle periodic(x, y) case for restricted types. + if (period != 2 || + trip->op_a->type != Primitive::kPrimInt || + (info->type != Primitive::kPrimInt && info->type != Primitive::kPrimBoolean)) { + return false; // TODO: easy to generalize + } + HInstruction* x_instr = nullptr; + HInstruction* y_instr = nullptr; + HInstruction* trip_expr = nullptr; + if (GenerateCode(info->op_a, nullptr, graph, block, graph ? &x_instr : nullptr, false, false) && + GenerateCode(info->op_b, nullptr, graph, block, graph ? &y_instr : nullptr, false, false) && + GenerateCode(trip->op_a, nullptr, graph, block, graph ? &trip_expr : nullptr, false, false)) { + // During actual code generation (graph != nullptr), + // generate is_even ? x : y select instruction. + if (graph != nullptr) { + HInstruction* is_even = Insert(block, new (graph->GetArena()) HEqual( + Insert(block, new (graph->GetArena()) HAnd( + Primitive::kPrimInt, trip_expr, graph->GetIntConstant(1))), + graph->GetIntConstant(0), kNoDexPc)); + *result = Insert(block, new (graph->GetArena()) HSelect(is_even, x_instr, y_instr, kNoDexPc)); + } + // Guard select with taken test if needed. + if (*needs_taken_test) { + HInstruction* taken_test = nullptr; + if (!GenerateCode( + trip->op_b, nullptr, graph, block, graph ? &taken_test : nullptr, false, false)) { + return false; + } else if (graph != nullptr) { + *result = Insert(block, + new (graph->GetArena()) HSelect(taken_test, *result, x_instr, kNoDexPc)); + } + *needs_taken_test = false; // taken care of + } + return true; + } + return false; +} + bool InductionVarRange::GenerateCode(HInductionVarAnalysis::InductionInfo* info, HInductionVarAnalysis::InductionInfo* trip, HGraph* graph, // when set, code is generated @@ -812,6 +873,7 @@ bool InductionVarRange::GenerateCode(HInductionVarAnalysis::InductionInfo* info, // Invariants. switch (info->operation) { case HInductionVarAnalysis::kAdd: + case HInductionVarAnalysis::kXor: case HInductionVarAnalysis::kLT: case HInductionVarAnalysis::kLE: case HInductionVarAnalysis::kGT: @@ -823,6 +885,8 @@ bool InductionVarRange::GenerateCode(HInductionVarAnalysis::InductionInfo* info, switch (info->operation) { case HInductionVarAnalysis::kAdd: operation = new (graph->GetArena()) HAdd(type, opa, opb); break; + case HInductionVarAnalysis::kXor: + operation = new (graph->GetArena()) HXor(type, opa, opb); break; case HInductionVarAnalysis::kLT: operation = new (graph->GetArena()) HLessThan(opa, opb); break; case HInductionVarAnalysis::kLE: diff --git a/compiler/optimizing/induction_var_range.h b/compiler/optimizing/induction_var_range.h index 895130064a..2f70046a27 100644 --- a/compiler/optimizing/induction_var_range.h +++ b/compiler/optimizing/induction_var_range.h @@ -139,6 +139,11 @@ class InductionVarRange { induction_analysis_->VisitLoop(loop); } + /** + * Checks if header logic of a loop terminates. + */ + bool IsFinite(HLoopInformation* loop) const; + private: /* * Enum used in IsConstant() request. @@ -218,17 +223,24 @@ class InductionVarRange { * success. With values nullptr, the method can be used to determine if code generation * would be successful without generating actual code yet. */ - bool GenerateCode(HInstruction* context, - HInstruction* instruction, - bool is_last_val, - HGraph* graph, - HBasicBlock* block, - /*out*/ HInstruction** lower, - /*out*/ HInstruction** upper, - /*out*/ HInstruction** taken_test, - /*out*/ int64_t* stride_value, - /*out*/ bool* needs_finite_test, - /*out*/ bool* needs_taken_test) const; + bool GenerateRangeOrLastValue(HInstruction* context, + HInstruction* instruction, + bool is_last_val, + HGraph* graph, + HBasicBlock* block, + /*out*/ HInstruction** lower, + /*out*/ HInstruction** upper, + /*out*/ HInstruction** taken_test, + /*out*/ int64_t* stride_value, + /*out*/ bool* needs_finite_test, + /*out*/ bool* needs_taken_test) const; + + bool GenerateLastValuePeriodic(HInductionVarAnalysis::InductionInfo* info, + HInductionVarAnalysis::InductionInfo* trip, + HGraph* graph, + HBasicBlock* block, + /*out*/HInstruction** result, + /*out*/ bool* needs_taken_test) const; bool GenerateCode(HInductionVarAnalysis::InductionInfo* info, HInductionVarAnalysis::InductionInfo* trip, diff --git a/compiler/optimizing/inliner.cc b/compiler/optimizing/inliner.cc index 6080551900..9faa98a388 100644 --- a/compiler/optimizing/inliner.cc +++ b/compiler/optimizing/inliner.cc @@ -90,14 +90,14 @@ void HInliner::Run() { if (!TryInline(call)) { if (kIsDebugBuild && IsCompilingWithCoreImage()) { std::string callee_name = - PrettyMethod(call->GetDexMethodIndex(), *outer_compilation_unit_.GetDexFile()); + outer_compilation_unit_.GetDexFile()->PrettyMethod(call->GetDexMethodIndex()); bool should_inline = callee_name.find("$inline$") != std::string::npos; CHECK(!should_inline) << "Could not inline " << callee_name; } } else { if (kIsDebugBuild && IsCompilingWithCoreImage()) { std::string callee_name = - PrettyMethod(call->GetDexMethodIndex(), *outer_compilation_unit_.GetDexFile()); + outer_compilation_unit_.GetDexFile()->PrettyMethod(call->GetDexMethodIndex()); bool must_not_inline = callee_name.find("$noinline$") != std::string::npos; CHECK(!must_not_inline) << "Should not have inlined " << callee_name; } @@ -203,10 +203,10 @@ static uint32_t FindClassIndexIn(mirror::Class* cls, REQUIRES_SHARED(Locks::mutator_lock_) { uint32_t index = DexFile::kDexNoIndex; if (cls->GetDexCache() == nullptr) { - DCHECK(cls->IsArrayClass()) << PrettyClass(cls); + DCHECK(cls->IsArrayClass()) << cls->PrettyClass(); index = cls->FindTypeIndexInOtherDexFile(dex_file); } else if (cls->GetDexTypeIndex() == DexFile::kDexNoIndex16) { - DCHECK(cls->IsProxyClass()) << PrettyClass(cls); + DCHECK(cls->IsProxyClass()) << cls->PrettyClass(); // TODO: deal with proxy classes. } else if (IsSameDexFile(cls->GetDexFile(), dex_file)) { DCHECK_EQ(cls->GetDexCache(), dex_cache.Get()); @@ -266,7 +266,7 @@ bool HInliner::TryInline(HInvoke* invoke_instruction) { ScopedObjectAccess soa(Thread::Current()); uint32_t method_index = invoke_instruction->GetDexMethodIndex(); const DexFile& caller_dex_file = *caller_compilation_unit_.GetDexFile(); - VLOG(compiler) << "Try inlining " << PrettyMethod(method_index, caller_dex_file); + VLOG(compiler) << "Try inlining " << caller_dex_file.PrettyMethod(method_index); // We can query the dex cache directly. The verifier has populated it already. ArtMethod* resolved_method = invoke_instruction->GetResolvedMethod(); @@ -304,7 +304,7 @@ bool HInliner::TryInline(HInvoke* invoke_instruction) { const InlineCache& ic = *profiling_info->GetInlineCache(invoke_instruction->GetDexPc()); if (ic.IsUninitialized()) { VLOG(compiler) << "Interface or virtual call to " - << PrettyMethod(method_index, caller_dex_file) + << caller_dex_file.PrettyMethod(method_index) << " is not hit and not inlined"; return false; } else if (ic.IsMonomorphic()) { @@ -322,7 +322,7 @@ bool HInliner::TryInline(HInvoke* invoke_instruction) { } else { DCHECK(ic.IsMegamorphic()); VLOG(compiler) << "Interface or virtual call to " - << PrettyMethod(method_index, caller_dex_file) + << caller_dex_file.PrettyMethod(method_index) << " is megamorphic and not inlined"; MaybeRecordStat(kMegamorphicCall); return false; @@ -331,7 +331,7 @@ bool HInliner::TryInline(HInvoke* invoke_instruction) { } VLOG(compiler) << "Interface or virtual call to " - << PrettyMethod(method_index, caller_dex_file) + << caller_dex_file.PrettyMethod(method_index) << " could not be statically determined"; return false; } @@ -366,7 +366,7 @@ bool HInliner::TryInlineMonomorphicCall(HInvoke* invoke_instruction, uint32_t class_index = FindClassIndexIn( ic.GetMonomorphicType(), caller_dex_file, caller_compilation_unit_.GetDexCache()); if (class_index == DexFile::kDexNoIndex) { - VLOG(compiler) << "Call to " << PrettyMethod(resolved_method) + VLOG(compiler) << "Call to " << ArtMethod::PrettyMethod(resolved_method) << " from inline cache is not inlined because its class is not" << " accessible to the caller"; return false; @@ -526,7 +526,7 @@ bool HInliner::TryInlinePolymorphicCall(HInvoke* invoke_instruction, } if (!one_target_inlined) { - VLOG(compiler) << "Call to " << PrettyMethod(resolved_method) + VLOG(compiler) << "Call to " << ArtMethod::PrettyMethod(resolved_method) << " from inline cache is not inlined because none" << " of its targets could be inlined"; return false; @@ -660,7 +660,7 @@ bool HInliner::TryInlinePolymorphicCallToSameTarget(HInvoke* invoke_instruction, actual_method = new_method; } else if (actual_method != new_method) { // Different methods, bailout. - VLOG(compiler) << "Call to " << PrettyMethod(resolved_method) + VLOG(compiler) << "Call to " << ArtMethod::PrettyMethod(resolved_method) << " from inline cache is not inlined because it resolves" << " to different methods"; return false; @@ -794,7 +794,7 @@ bool HInliner::TryBuildAndInline(HInvoke* invoke_instruction, ArtMethod* method, HInstruction** return_replacement) { if (method->IsProxyMethod()) { - VLOG(compiler) << "Method " << PrettyMethod(method) + VLOG(compiler) << "Method " << method->PrettyMethod() << " is not inlined because of unimplemented inline support for proxy methods."; return false; } @@ -804,11 +804,12 @@ bool HInliner::TryBuildAndInline(HInvoke* invoke_instruction, if (!compiler_driver_->MayInline(method->GetDexFile(), outer_compilation_unit_.GetDexFile())) { if (TryPatternSubstitution(invoke_instruction, method, return_replacement)) { - VLOG(compiler) << "Successfully replaced pattern of invoke " << PrettyMethod(method); + VLOG(compiler) << "Successfully replaced pattern of invoke " + << method->PrettyMethod(); MaybeRecordStat(kReplacedInvokeWithSimplePattern); return true; } - VLOG(compiler) << "Won't inline " << PrettyMethod(method) << " in " + VLOG(compiler) << "Won't inline " << method->PrettyMethod() << " in " << outer_compilation_unit_.GetDexFile()->GetLocation() << " (" << caller_compilation_unit_.GetDexFile()->GetLocation() << ") from " << method->GetDexFile()->GetLocation(); @@ -820,14 +821,14 @@ bool HInliner::TryBuildAndInline(HInvoke* invoke_instruction, const DexFile::CodeItem* code_item = method->GetCodeItem(); if (code_item == nullptr) { - VLOG(compiler) << "Method " << PrettyMethod(method) + VLOG(compiler) << "Method " << method->PrettyMethod() << " is not inlined because it is native"; return false; } size_t inline_max_code_units = compiler_driver_->GetCompilerOptions().GetInlineMaxCodeUnits(); if (code_item->insns_size_in_code_units_ > inline_max_code_units) { - VLOG(compiler) << "Method " << PrettyMethod(method) + VLOG(compiler) << "Method " << method->PrettyMethod() << " is too big to inline: " << code_item->insns_size_in_code_units_ << " > " @@ -836,13 +837,13 @@ bool HInliner::TryBuildAndInline(HInvoke* invoke_instruction, } if (code_item->tries_size_ != 0) { - VLOG(compiler) << "Method " << PrettyMethod(method) + VLOG(compiler) << "Method " << method->PrettyMethod() << " is not inlined because of try block"; return false; } if (!method->IsCompilable()) { - VLOG(compiler) << "Method " << PrettyMethod(method) + VLOG(compiler) << "Method " << method->PrettyMethod() << " has soft failures un-handled by the compiler, so it cannot be inlined"; } @@ -851,7 +852,7 @@ bool HInliner::TryBuildAndInline(HInvoke* invoke_instruction, if (Runtime::Current()->UseJitCompilation() || !compiler_driver_->IsMethodVerifiedWithoutFailures( method->GetDexMethodIndex(), class_def_idx, *method->GetDexFile())) { - VLOG(compiler) << "Method " << PrettyMethod(method) + VLOG(compiler) << "Method " << method->PrettyMethod() << " couldn't be verified, so it cannot be inlined"; return false; } @@ -861,7 +862,7 @@ bool HInliner::TryBuildAndInline(HInvoke* invoke_instruction, invoke_instruction->AsInvokeStaticOrDirect()->IsStaticWithImplicitClinitCheck()) { // Case of a static method that cannot be inlined because it implicitly // requires an initialization check of its declaring class. - VLOG(compiler) << "Method " << PrettyMethod(method) + VLOG(compiler) << "Method " << method->PrettyMethod() << " is not inlined because it is static and requires a clinit" << " check that cannot be emitted due to Dex cache limitations"; return false; @@ -871,7 +872,7 @@ bool HInliner::TryBuildAndInline(HInvoke* invoke_instruction, return false; } - VLOG(compiler) << "Successfully inlined " << PrettyMethod(method); + VLOG(compiler) << "Successfully inlined " << method->PrettyMethod(); MaybeRecordStat(kInlinedInvoke); return true; } @@ -1143,14 +1144,14 @@ bool HInliner::TryBuildAndInlineHelper(HInvoke* invoke_instruction, handles_); if (builder.BuildGraph() != kAnalysisSuccess) { - VLOG(compiler) << "Method " << PrettyMethod(method_index, callee_dex_file) + VLOG(compiler) << "Method " << callee_dex_file.PrettyMethod(method_index) << " could not be built, so cannot be inlined"; return false; } if (!RegisterAllocator::CanAllocateRegistersFor(*callee_graph, compiler_driver_->GetInstructionSet())) { - VLOG(compiler) << "Method " << PrettyMethod(method_index, callee_dex_file) + VLOG(compiler) << "Method " << callee_dex_file.PrettyMethod(method_index) << " cannot be inlined because of the register allocator"; return false; } @@ -1200,7 +1201,7 @@ bool HInliner::TryBuildAndInlineHelper(HInvoke* invoke_instruction, // a throw predecessor. HBasicBlock* exit_block = callee_graph->GetExitBlock(); if (exit_block == nullptr) { - VLOG(compiler) << "Method " << PrettyMethod(method_index, callee_dex_file) + VLOG(compiler) << "Method " << callee_dex_file.PrettyMethod(method_index) << " could not be inlined because it has an infinite loop"; return false; } @@ -1213,7 +1214,7 @@ bool HInliner::TryBuildAndInlineHelper(HInvoke* invoke_instruction, } } if (has_throw_predecessor) { - VLOG(compiler) << "Method " << PrettyMethod(method_index, callee_dex_file) + VLOG(compiler) << "Method " << callee_dex_file.PrettyMethod(method_index) << " could not be inlined because one branch always throws"; return false; } @@ -1231,7 +1232,7 @@ bool HInliner::TryBuildAndInlineHelper(HInvoke* invoke_instruction, if (block->IsLoopHeader() && block->GetLoopInformation()->IsIrreducible()) { // Don't inline methods with irreducible loops, they could prevent some // optimizations to run. - VLOG(compiler) << "Method " << PrettyMethod(method_index, callee_dex_file) + VLOG(compiler) << "Method " << callee_dex_file.PrettyMethod(method_index) << " could not be inlined because it contains an irreducible loop"; return false; } @@ -1240,28 +1241,28 @@ bool HInliner::TryBuildAndInlineHelper(HInvoke* invoke_instruction, !instr_it.Done(); instr_it.Advance()) { if (number_of_instructions++ == number_of_instructions_budget) { - VLOG(compiler) << "Method " << PrettyMethod(method_index, callee_dex_file) + VLOG(compiler) << "Method " << callee_dex_file.PrettyMethod(method_index) << " is not inlined because its caller has reached" << " its instruction budget limit."; return false; } HInstruction* current = instr_it.Current(); if (!can_inline_environment && current->NeedsEnvironment()) { - VLOG(compiler) << "Method " << PrettyMethod(method_index, callee_dex_file) + VLOG(compiler) << "Method " << callee_dex_file.PrettyMethod(method_index) << " is not inlined because its caller has reached" << " its environment budget limit."; return false; } if (!same_dex_file && current->NeedsEnvironment()) { - VLOG(compiler) << "Method " << PrettyMethod(method_index, callee_dex_file) + VLOG(compiler) << "Method " << callee_dex_file.PrettyMethod(method_index) << " could not be inlined because " << current->DebugName() << " needs an environment and is in a different dex file"; return false; } if (!same_dex_file && current->NeedsDexCacheOfDeclaringClass()) { - VLOG(compiler) << "Method " << PrettyMethod(method_index, callee_dex_file) + VLOG(compiler) << "Method " << callee_dex_file.PrettyMethod(method_index) << " could not be inlined because " << current->DebugName() << " it is in a different dex file and requires access to the dex cache"; return false; @@ -1269,7 +1270,7 @@ bool HInliner::TryBuildAndInlineHelper(HInvoke* invoke_instruction, if (current->IsNewInstance() && (current->AsNewInstance()->GetEntrypoint() == kQuickAllocObjectWithAccessCheck)) { - VLOG(compiler) << "Method " << PrettyMethod(method_index, callee_dex_file) + VLOG(compiler) << "Method " << callee_dex_file.PrettyMethod(method_index) << " could not be inlined because it is using an entrypoint" << " with access checks"; // Allocation entrypoint does not handle inlined frames. @@ -1278,7 +1279,7 @@ bool HInliner::TryBuildAndInlineHelper(HInvoke* invoke_instruction, if (current->IsNewArray() && (current->AsNewArray()->GetEntrypoint() == kQuickAllocArrayWithAccessCheck)) { - VLOG(compiler) << "Method " << PrettyMethod(method_index, callee_dex_file) + VLOG(compiler) << "Method " << callee_dex_file.PrettyMethod(method_index) << " could not be inlined because it is using an entrypoint" << " with access checks"; // Allocation entrypoint does not handle inlined frames. @@ -1290,7 +1291,7 @@ bool HInliner::TryBuildAndInlineHelper(HInvoke* invoke_instruction, current->IsUnresolvedStaticFieldSet() || current->IsUnresolvedInstanceFieldSet()) { // Entrypoint for unresolved fields does not handle inlined frames. - VLOG(compiler) << "Method " << PrettyMethod(method_index, callee_dex_file) + VLOG(compiler) << "Method " << callee_dex_file.PrettyMethod(method_index) << " could not be inlined because it is using an unresolved" << " entrypoint"; return false; diff --git a/compiler/optimizing/instruction_builder.cc b/compiler/optimizing/instruction_builder.cc index f7d67db5b2..613e00843f 100644 --- a/compiler/optimizing/instruction_builder.cc +++ b/compiler/optimizing/instruction_builder.cc @@ -1065,7 +1065,7 @@ bool HInstructionBuilder::SetupInvokeArguments(HInvoke* invoke, // reject any class where this is violated. However, the verifier only does these checks // on non trivially dead instructions, so we just bailout the compilation. VLOG(compiler) << "Did not compile " - << PrettyMethod(dex_compilation_unit_->GetDexMethodIndex(), *dex_file_) + << dex_file_->PrettyMethod(dex_compilation_unit_->GetDexMethodIndex()) << " because of non-sequential dex register pair in wide argument"; MaybeRecordStat(MethodCompilationStat::kNotCompiledMalformedOpcode); return false; @@ -1079,7 +1079,7 @@ bool HInstructionBuilder::SetupInvokeArguments(HInvoke* invoke, if (*argument_index != invoke->GetNumberOfArguments()) { VLOG(compiler) << "Did not compile " - << PrettyMethod(dex_compilation_unit_->GetDexMethodIndex(), *dex_file_) + << dex_file_->PrettyMethod(dex_compilation_unit_->GetDexMethodIndex()) << " because of wrong number of arguments in invoke instruction"; MaybeRecordStat(MethodCompilationStat::kNotCompiledMalformedOpcode); return false; @@ -2716,7 +2716,7 @@ bool HInstructionBuilder::ProcessDexInstruction(const Instruction& instruction, default: VLOG(compiler) << "Did not compile " - << PrettyMethod(dex_compilation_unit_->GetDexMethodIndex(), *dex_file_) + << dex_file_->PrettyMethod(dex_compilation_unit_->GetDexMethodIndex()) << " because of unhandled instruction " << instruction.Name(); MaybeRecordStat(MethodCompilationStat::kNotCompiledUnhandledInstruction); diff --git a/compiler/optimizing/intrinsics.cc b/compiler/optimizing/intrinsics.cc index 412ccfcf4f..8327a4c244 100644 --- a/compiler/optimizing/intrinsics.cc +++ b/compiler/optimizing/intrinsics.cc @@ -146,7 +146,7 @@ void IntrinsicsRecognizer::Run() { if (!CheckInvokeType(intrinsic, invoke)) { LOG(WARNING) << "Found an intrinsic with unexpected invoke type: " << intrinsic << " for " - << PrettyMethod(invoke->GetDexMethodIndex(), invoke->GetDexFile()) + << invoke->GetDexFile().PrettyMethod(invoke->GetDexMethodIndex()) << invoke->DebugName(); } else { invoke->SetIntrinsic(intrinsic, diff --git a/compiler/optimizing/load_store_elimination.cc b/compiler/optimizing/load_store_elimination.cc index 7347686830..820fa29597 100644 --- a/compiler/optimizing/load_store_elimination.cc +++ b/compiler/optimizing/load_store_elimination.cc @@ -168,7 +168,9 @@ class HeapLocation : public ArenaObject<kArenaAllocMisc> { const int16_t declaring_class_def_index_; // declaring class's def's dex index. bool value_killed_by_loop_side_effects_; // value of this location may be killed by loop // side effects because this location is stored - // into inside a loop. + // into inside a loop. This gives + // better info on whether a singleton's location + // value may be killed by loop side effects. DISALLOW_COPY_AND_ASSIGN(HeapLocation); }; @@ -420,8 +422,26 @@ class HeapLocationCollector : public HGraphVisitor { void VisitInstanceFieldSet(HInstanceFieldSet* instruction) OVERRIDE { HeapLocation* location = VisitFieldAccess(instruction->InputAt(0), instruction->GetFieldInfo()); has_heap_stores_ = true; - if (instruction->GetBlock()->GetLoopInformation() != nullptr) { - location->SetValueKilledByLoopSideEffects(true); + if (location->GetReferenceInfo()->IsSingleton()) { + // A singleton's location value may be killed by loop side effects if it's + // defined before that loop, and it's stored into inside that loop. + HLoopInformation* loop_info = instruction->GetBlock()->GetLoopInformation(); + if (loop_info != nullptr) { + HInstruction* ref = location->GetReferenceInfo()->GetReference(); + DCHECK(ref->IsNewInstance()); + if (loop_info->IsDefinedOutOfTheLoop(ref)) { + // ref's location value may be killed by this loop's side effects. + location->SetValueKilledByLoopSideEffects(true); + } else { + // ref is defined inside this loop so this loop's side effects cannot + // kill its location value at the loop header since ref/its location doesn't + // exist yet at the loop header. + } + } + } else { + // For non-singletons, value_killed_by_loop_side_effects_ is inited to + // true. + DCHECK_EQ(location->IsValueKilledByLoopSideEffects(), true); } } @@ -810,9 +830,6 @@ class LSEVisitor : public HGraphVisitor { if (loop_info != nullptr) { // instruction is a store in the loop so the loop must does write. DCHECK(side_effects_.GetLoopEffects(loop_info->GetHeader()).DoesAnyWrite()); - // If it's a singleton, IsValueKilledByLoopSideEffects() must be true. - DCHECK(!ref_info->IsSingleton() || - heap_location_collector_.GetHeapLocation(idx)->IsValueKilledByLoopSideEffects()); if (loop_info->IsDefinedOutOfTheLoop(original_ref)) { DCHECK(original_ref->GetBlock()->Dominates(loop_info->GetPreHeader())); diff --git a/compiler/optimizing/loop_optimization.cc b/compiler/optimizing/loop_optimization.cc index 33fa87d568..703a10402d 100644 --- a/compiler/optimizing/loop_optimization.cc +++ b/compiler/optimizing/loop_optimization.cc @@ -20,17 +20,37 @@ namespace art { -// TODO: Generalize to cycles, as found by induction analysis? +// Detects a potential induction cycle. Note that the actual induction +// information is queried later if its last value is really needed. static bool IsPhiInduction(HPhi* phi, ArenaSet<HInstruction*>* iset) { DCHECK(iset->empty()); HInputsRef inputs = phi->GetInputs(); - if (inputs.size() == 2 && (inputs[1]->IsAdd() || inputs[1]->IsSub())) { - HInstruction* addsub = inputs[1]; - if (addsub->InputAt(0) == phi || addsub->InputAt(1) == phi) { - if (addsub->GetUses().HasExactlyOneElement()) { - iset->insert(phi); - iset->insert(addsub); - return true; + if (inputs.size() == 2) { + HLoopInformation* loop_info = phi->GetBlock()->GetLoopInformation(); + HInstruction* op = inputs[1]; + if (op->GetBlock()->GetLoopInformation() == loop_info) { + // Chase a simple chain back to phi. + while (!op->IsPhi()) { + // Binary operation with single use in same loop. + if (!op->IsBinaryOperation() || !op->GetUses().HasExactlyOneElement()) { + return false; + } + // Chase back either through left or right operand. + iset->insert(op); + HInstruction* a = op->InputAt(0); + HInstruction* b = op->InputAt(1); + if (a->GetBlock()->GetLoopInformation() == loop_info && b != phi) { + op = a; + } else if (b->GetBlock()->GetLoopInformation() == loop_info) { + op = b; + } else { + return false; + } + } + // Closed the cycle? + if (op == phi) { + iset->insert(phi); + return true; } } } @@ -62,16 +82,23 @@ static bool IsEmptyHeader(HBasicBlock* block, ArenaSet<HInstruction*>* iset) { return false; } +// Does the loop-body consist of induction cycle and direct control flow only? static bool IsEmptyBody(HBasicBlock* block, ArenaSet<HInstruction*>* iset) { - HInstruction* phi = block->GetFirstPhi(); - HInstruction* i = block->GetFirstInstruction(); - return phi == nullptr && iset->find(i) != iset->end() && - i->GetNext() != nullptr && i->GetNext()->IsGoto(); + if (block->GetFirstPhi() == nullptr) { + for (HInstructionIterator it(block->GetInstructions()); !it.Done(); it.Advance()) { + HInstruction* instruction = it.Current(); + if (!instruction->IsGoto() && iset->find(instruction) == iset->end()) { + return false; + } + } + return true; + } + return false; } +// Remove the instruction from the graph. A bit more elaborate than the usual +// instruction removal, since there may be a cycle in the use structure. static void RemoveFromCycle(HInstruction* instruction) { - // A bit more elaborate than the usual instruction removal, - // since there may be a cycle in the use structure. instruction->RemoveAsUserOfAllInputs(); instruction->RemoveEnvironmentUsers(); instruction->GetBlock()->RemoveInstructionOrPhi(instruction, /*ensure_safety=*/ false); @@ -196,7 +223,9 @@ void HLoopOptimization::TraverseLoopsInnerToOuter(LoopNode* node) { } SimplifyInduction(node); SimplifyBlocks(node); - RemoveIfEmptyLoop(node); + if (node->inner == nullptr) { + RemoveIfEmptyInnerLoop(node); + } } } @@ -233,7 +262,7 @@ void HLoopOptimization::SimplifyBlocks(LoopNode* node) { block->RemoveInstruction(instruction); } } - // Remove trivial control flow blocks from the loop body, again usually resulting + // Remove trivial control flow blocks from the loop-body, again usually resulting // from eliminating induction cycles. if (block->GetPredecessors().size() == 1 && block->GetSuccessors().size() == 1 && @@ -252,9 +281,13 @@ void HLoopOptimization::SimplifyBlocks(LoopNode* node) { } } -void HLoopOptimization::RemoveIfEmptyLoop(LoopNode* node) { +void HLoopOptimization::RemoveIfEmptyInnerLoop(LoopNode* node) { HBasicBlock* header = node->loop_info->GetHeader(); HBasicBlock* preheader = node->loop_info->GetPreHeader(); + // Ensure loop header logic is finite. + if (!induction_range_.IsFinite(node->loop_info)) { + return; + } // Ensure there is only a single loop-body (besides the header). HBasicBlock* body = nullptr; for (HBlocksInLoopIterator it(*node->loop_info); !it.Done(); it.Advance()) { diff --git a/compiler/optimizing/loop_optimization.h b/compiler/optimizing/loop_optimization.h index 9c4b462a1f..4113357035 100644 --- a/compiler/optimizing/loop_optimization.h +++ b/compiler/optimizing/loop_optimization.h @@ -62,7 +62,7 @@ class HLoopOptimization : public HOptimization { void SimplifyInduction(LoopNode* node); void SimplifyBlocks(LoopNode* node); - void RemoveIfEmptyLoop(LoopNode* node); + void RemoveIfEmptyInnerLoop(LoopNode* node); bool IsOnlyUsedAfterLoop(HLoopInformation* loop_info, HInstruction* instruction, diff --git a/compiler/optimizing/nodes.cc b/compiler/optimizing/nodes.cc index 1e69966b98..59cc0091bf 100644 --- a/compiler/optimizing/nodes.cc +++ b/compiler/optimizing/nodes.cc @@ -2295,7 +2295,7 @@ std::ostream& operator<<(std::ostream& os, const ReferenceTypeInfo& rhs) { ScopedObjectAccess soa(Thread::Current()); os << "[" << " is_valid=" << rhs.IsValid() - << " type=" << (!rhs.IsValid() ? "?" : PrettyClass(rhs.GetTypeHandle().Get())) + << " type=" << (!rhs.IsValid() ? "?" : mirror::Class::PrettyClass(rhs.GetTypeHandle().Get())) << " is_exact=" << rhs.IsExact() << " ]"; return os; diff --git a/compiler/optimizing/optimizing_compiler.cc b/compiler/optimizing/optimizing_compiler.cc index b559a7a7ed..7972387536 100644 --- a/compiler/optimizing/optimizing_compiler.cc +++ b/compiler/optimizing/optimizing_compiler.cc @@ -173,7 +173,7 @@ class PassObserver : public ValueObject { const char* GetMethodName() { // PrettyMethod() is expensive, so we delay calling it until we actually have to. if (cached_method_name_.empty()) { - cached_method_name_ = PrettyMethod(graph_->GetMethodIdx(), graph_->GetDexFile()); + cached_method_name_ = graph_->GetDexFile().PrettyMethod(graph_->GetMethodIdx()); } return cached_method_name_.c_str(); } @@ -1049,7 +1049,7 @@ CompiledMethod* OptimizingCompiler::Compile(const DexFile::CodeItem* code_item, if (kArenaAllocatorCountAllocations) { if (arena.BytesAllocated() > kArenaAllocatorMemoryReportThreshold) { MemStats mem_stats(arena.GetMemStats()); - LOG(INFO) << PrettyMethod(method_idx, dex_file) << " " << Dumpable<MemStats>(mem_stats); + LOG(INFO) << dex_file.PrettyMethod(method_idx) << " " << Dumpable<MemStats>(mem_stats); } } } @@ -1071,7 +1071,7 @@ CompiledMethod* OptimizingCompiler::Compile(const DexFile::CodeItem* code_item, // instruction set is supported -- and has support for read // barriers, if they are enabled). This makes sure we're not // regressing. - std::string method_name = PrettyMethod(method_idx, dex_file); + std::string method_name = dex_file.PrettyMethod(method_idx); bool shouldCompile = method_name.find("$opt$") != std::string::npos; DCHECK((method != nullptr) || !shouldCompile) << "Didn't compile " << method_name; } @@ -1136,7 +1136,7 @@ bool OptimizingCompiler::JitCompile(Thread* self, if (kArenaAllocatorCountAllocations) { if (arena.BytesAllocated() > kArenaAllocatorMemoryReportThreshold) { MemStats mem_stats(arena.GetMemStats()); - LOG(INFO) << PrettyMethod(method_idx, *dex_file) << " " << Dumpable<MemStats>(mem_stats); + LOG(INFO) << dex_file->PrettyMethod(method_idx) << " " << Dumpable<MemStats>(mem_stats); } } } diff --git a/compiler/optimizing/prepare_for_register_allocation.cc b/compiler/optimizing/prepare_for_register_allocation.cc index 8fb539661f..a4df9e5503 100644 --- a/compiler/optimizing/prepare_for_register_allocation.cc +++ b/compiler/optimizing/prepare_for_register_allocation.cc @@ -44,7 +44,7 @@ void PrepareForRegisterAllocation::VisitBoundsCheck(HBoundsCheck* check) { // Add a fake environment for String.charAt() inline info as we want // the exception to appear as being thrown from there. const DexFile& dex_file = check->GetEnvironment()->GetDexFile(); - DCHECK_STREQ(PrettyMethod(check->GetStringCharAtMethodIndex(), dex_file).c_str(), + DCHECK_STREQ(dex_file.PrettyMethod(check->GetStringCharAtMethodIndex()).c_str(), "char java.lang.String.charAt(int)"); ArenaAllocator* arena = GetGraph()->GetArena(); HEnvironment* environment = new (arena) HEnvironment(arena, diff --git a/compiler/optimizing/reference_type_propagation.cc b/compiler/optimizing/reference_type_propagation.cc index 83698adba4..d93c9ddc39 100644 --- a/compiler/optimizing/reference_type_propagation.cc +++ b/compiler/optimizing/reference_type_propagation.cc @@ -448,9 +448,9 @@ void ReferenceTypePropagation::RTPVisitor::SetClassAsTypeInfo(HInstruction* inst mirror::Class* declaring_class = method->GetDeclaringClass(); DCHECK(declaring_class != nullptr); DCHECK(declaring_class->IsStringClass()) - << "Expected String class: " << PrettyDescriptor(declaring_class); + << "Expected String class: " << declaring_class->PrettyDescriptor(); DCHECK(method->IsConstructor()) - << "Expected String.<init>: " << PrettyMethod(method); + << "Expected String.<init>: " << method->PrettyMethod(); } instr->SetReferenceTypeInfo( ReferenceTypeInfo::Create(handle_cache_->GetStringClassHandle(), /* is_exact */ true)); @@ -517,7 +517,8 @@ void ReferenceTypePropagation::RTPVisitor::UpdateFieldAccessTypeInfo(HInstructio // The field index is unknown only during tests. if (info.GetFieldIndex() != kUnknownFieldIndex) { ClassLinker* cl = Runtime::Current()->GetClassLinker(); - ArtField* field = cl->GetResolvedField(info.GetFieldIndex(), info.GetDexCache().Get()); + ArtField* field = cl->GetResolvedField(info.GetFieldIndex(), + MakeObjPtr(info.GetDexCache().Get())); // TODO: There are certain cases where we can't resolve the field. // b/21914925 is open to keep track of a repro case for this issue. if (field != nullptr) { |