diff options
| -rw-r--r-- | compiler/optimizing/builder.cc | 15 | ||||
| -rw-r--r-- | compiler/optimizing/code_generator_arm.cc | 45 | ||||
| -rw-r--r-- | compiler/optimizing/code_generator_arm64.cc | 37 | ||||
| -rw-r--r-- | compiler/optimizing/code_generator_x86.cc | 38 | ||||
| -rw-r--r-- | compiler/optimizing/code_generator_x86_64.cc | 42 | ||||
| -rw-r--r-- | compiler/optimizing/nodes.cc | 15 | ||||
| -rw-r--r-- | compiler/optimizing/nodes.h | 31 | ||||
| -rw-r--r-- | compiler/optimizing/register_allocator.cc | 18 | ||||
| -rw-r--r-- | test/482-checker-loop-back-edge-use/src/Main.java | 44 |
9 files changed, 198 insertions, 87 deletions
diff --git a/compiler/optimizing/builder.cc b/compiler/optimizing/builder.cc index 49a0444f94..c142e4ddb5 100644 --- a/compiler/optimizing/builder.cc +++ b/compiler/optimizing/builder.cc @@ -712,7 +712,11 @@ bool HGraphBuilder::BuildInvoke(const Instruction& instruction, } else { clinit_check_requirement = HInvokeStaticOrDirect::ClinitCheckRequirement::kExplicit; HLoadClass* load_class = new (arena_) HLoadClass( - storage_index, *dex_compilation_unit_->GetDexFile(), is_referrer_class, dex_pc); + graph_->GetCurrentMethod(), + storage_index, + *dex_compilation_unit_->GetDexFile(), + is_referrer_class, + dex_pc); current_block_->AddInstruction(load_class); clinit_check = new (arena_) HClinitCheck(load_class, dex_pc); current_block_->AddInstruction(clinit_check); @@ -915,8 +919,11 @@ bool HGraphBuilder::BuildStaticFieldAccess(const Instruction& instruction, *outer_compilation_unit_->GetDexFile(), storage_index); bool is_initialized = resolved_field->GetDeclaringClass()->IsInitialized() && is_in_dex_cache; - HLoadClass* constant = new (arena_) HLoadClass( - storage_index, *dex_compilation_unit_->GetDexFile(), is_referrer_class, dex_pc); + HLoadClass* constant = new (arena_) HLoadClass(graph_->GetCurrentMethod(), + storage_index, + *dex_compilation_unit_->GetDexFile(), + is_referrer_class, + dex_pc); current_block_->AddInstruction(constant); HInstruction* cls = constant; @@ -1152,6 +1159,7 @@ bool HGraphBuilder::BuildTypeCheck(const Instruction& instruction, } HInstruction* object = LoadLocal(reference, Primitive::kPrimNot); HLoadClass* cls = new (arena_) HLoadClass( + graph_->GetCurrentMethod(), type_index, *dex_compilation_unit_->GetDexFile(), IsOutermostCompilingClass(type_index), @@ -2167,6 +2175,7 @@ bool HGraphBuilder::AnalyzeDexInstruction(const Instruction& instruction, uint32 return false; } current_block_->AddInstruction(new (arena_) HLoadClass( + graph_->GetCurrentMethod(), type_index, *dex_compilation_unit_->GetDexFile(), IsOutermostCompilingClass(type_index), diff --git a/compiler/optimizing/code_generator_arm.cc b/compiler/optimizing/code_generator_arm.cc index 7d26a3c9ae..1cca52270e 100644 --- a/compiler/optimizing/code_generator_arm.cc +++ b/compiler/optimizing/code_generator_arm.cc @@ -41,6 +41,7 @@ static bool ExpectedPairLayout(Location location) { } static constexpr int kCurrentMethodStackOffset = 0; +static constexpr Register kMethodRegisterArgument = R0; // We unconditionally allocate R5 to ensure we can do long operations // with baseline. @@ -544,7 +545,7 @@ void CodeGeneratorARM::GenerateFrameEntry() { uint32_t push_mask = (core_spill_mask_ & (~(1 << PC))) | 1 << LR; __ PushList(push_mask); __ cfi().AdjustCFAOffset(kArmWordSize * POPCOUNT(push_mask)); - __ cfi().RelOffsetForMany(DWARFReg(R0), 0, push_mask, kArmWordSize); + __ cfi().RelOffsetForMany(DWARFReg(kMethodRegisterArgument), 0, push_mask, kArmWordSize); if (fpu_spill_mask_ != 0) { SRegister start_register = SRegister(LeastSignificantBit(fpu_spill_mask_)); __ vpushs(start_register, POPCOUNT(fpu_spill_mask_)); @@ -554,7 +555,7 @@ void CodeGeneratorARM::GenerateFrameEntry() { int adjust = GetFrameSize() - FrameEntrySpillSize(); __ AddConstant(SP, -adjust); __ cfi().AdjustCFAOffset(adjust); - __ StoreToOffset(kStoreWord, R0, SP, 0); + __ StoreToOffset(kStoreWord, kMethodRegisterArgument, SP, 0); } void CodeGeneratorARM::GenerateFrameExit() { @@ -803,11 +804,11 @@ void CodeGeneratorARM::Move64(Location destination, Location source) { void CodeGeneratorARM::Move(HInstruction* instruction, Location location, HInstruction* move_for) { LocationSummary* locations = instruction->GetLocations(); - if (locations != nullptr && locations->Out().Equals(location)) { + if (instruction->IsCurrentMethod()) { + Move32(location, Location::StackSlot(kCurrentMethodStackOffset)); + } else if (locations != nullptr && locations->Out().Equals(location)) { return; - } - - if (locations != nullptr && locations->Out().IsConstant()) { + } else if (locations != nullptr && locations->Out().IsConstant()) { HConstant* const_to_move = locations->Out().GetConstant(); if (const_to_move->IsIntConstant() || const_to_move->IsNullConstant()) { int32_t value = GetInt32ValueOf(const_to_move); @@ -1286,7 +1287,7 @@ void InstructionCodeGeneratorARM::VisitInvokeStaticOrDirect(HInvokeStaticOrDirec void LocationsBuilderARM::HandleInvoke(HInvoke* invoke) { LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(invoke, LocationSummary::kCall); - locations->AddTemp(Location::RegisterLocation(R0)); + locations->AddTemp(Location::RegisterLocation(kMethodRegisterArgument)); InvokeDexCallingConventionVisitorARM calling_convention_visitor; for (size_t i = 0; i < invoke->GetNumberOfArguments(); i++) { @@ -2802,9 +2803,19 @@ void LocationsBuilderARM::VisitParameterValue(HParameterValue* instruction) { locations->SetOut(location); } -void InstructionCodeGeneratorARM::VisitParameterValue(HParameterValue* instruction) { +void InstructionCodeGeneratorARM::VisitParameterValue( + HParameterValue* instruction ATTRIBUTE_UNUSED) { // Nothing to do, the parameter is already at its location. - UNUSED(instruction); +} + +void LocationsBuilderARM::VisitCurrentMethod(HCurrentMethod* instruction) { + LocationSummary* locations = + new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kNoCall); + locations->SetOut(Location::RegisterLocation(kMethodRegisterArgument)); +} + +void InstructionCodeGeneratorARM::VisitCurrentMethod(HCurrentMethod* instruction ATTRIBUTE_UNUSED) { + // Nothing to do, the method is already at its location. } void LocationsBuilderARM::VisitNot(HNot* not_) { @@ -3954,21 +3965,25 @@ void LocationsBuilderARM::VisitLoadClass(HLoadClass* cls) { : LocationSummary::kNoCall; LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(cls, call_kind); + locations->SetInAt(0, Location::RequiresRegister()); locations->SetOut(Location::RequiresRegister()); } void InstructionCodeGeneratorARM::VisitLoadClass(HLoadClass* cls) { - Register out = cls->GetLocations()->Out().AsRegister<Register>(); + LocationSummary* locations = cls->GetLocations(); + Register out = locations->Out().AsRegister<Register>(); + Register current_method = locations->InAt(0).AsRegister<Register>(); if (cls->IsReferrersClass()) { DCHECK(!cls->CanCallRuntime()); DCHECK(!cls->MustGenerateClinitCheck()); - codegen_->LoadCurrentMethod(out); - __ LoadFromOffset(kLoadWord, out, out, mirror::ArtMethod::DeclaringClassOffset().Int32Value()); + __ LoadFromOffset( + kLoadWord, out, current_method, mirror::ArtMethod::DeclaringClassOffset().Int32Value()); } else { DCHECK(cls->CanCallRuntime()); - codegen_->LoadCurrentMethod(out); - __ LoadFromOffset( - kLoadWord, out, out, mirror::ArtMethod::DexCacheResolvedTypesOffset().Int32Value()); + __ LoadFromOffset(kLoadWord, + out, + current_method, + mirror::ArtMethod::DexCacheResolvedTypesOffset().Int32Value()); __ LoadFromOffset(kLoadWord, out, out, CodeGenerator::GetCacheOffset(cls->GetTypeIndex())); SlowPathCodeARM* slow_path = new (GetGraph()->GetArena()) LoadClassSlowPathARM( diff --git a/compiler/optimizing/code_generator_arm64.cc b/compiler/optimizing/code_generator_arm64.cc index ced60cd33f..04c38f6df2 100644 --- a/compiler/optimizing/code_generator_arm64.cc +++ b/compiler/optimizing/code_generator_arm64.cc @@ -634,16 +634,16 @@ void CodeGeneratorARM64::Move(HInstruction* instruction, Location location, HInstruction* move_for) { LocationSummary* locations = instruction->GetLocations(); - if (locations != nullptr && locations->Out().Equals(location)) { - return; - } - Primitive::Type type = instruction->GetType(); DCHECK_NE(type, Primitive::kPrimVoid); - if (instruction->IsIntConstant() - || instruction->IsLongConstant() - || instruction->IsNullConstant()) { + if (instruction->IsCurrentMethod()) { + MoveLocation(location, Location::StackSlot(kCurrentMethodStackOffset)); + } else if (locations != nullptr && locations->Out().Equals(location)) { + return; + } else if (instruction->IsIntConstant() + || instruction->IsLongConstant() + || instruction->IsNullConstant()) { int64_t value = GetInt64ValueOf(instruction->AsConstant()); if (location.IsRegister()) { Register dst = RegisterFrom(location, type); @@ -2345,20 +2345,20 @@ void LocationsBuilderARM64::VisitLoadClass(HLoadClass* cls) { LocationSummary::CallKind call_kind = cls->CanCallRuntime() ? LocationSummary::kCallOnSlowPath : LocationSummary::kNoCall; LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(cls, call_kind); + locations->SetInAt(0, Location::RequiresRegister()); locations->SetOut(Location::RequiresRegister()); } void InstructionCodeGeneratorARM64::VisitLoadClass(HLoadClass* cls) { Register out = OutputRegister(cls); + Register current_method = InputRegisterAt(cls, 0); if (cls->IsReferrersClass()) { DCHECK(!cls->CanCallRuntime()); DCHECK(!cls->MustGenerateClinitCheck()); - codegen_->LoadCurrentMethod(out); - __ Ldr(out, HeapOperand(out, mirror::ArtMethod::DeclaringClassOffset())); + __ Ldr(out, HeapOperand(current_method, mirror::ArtMethod::DeclaringClassOffset())); } else { DCHECK(cls->CanCallRuntime()); - codegen_->LoadCurrentMethod(out); - __ Ldr(out, HeapOperand(out, mirror::ArtMethod::DexCacheResolvedTypesOffset())); + __ Ldr(out, HeapOperand(current_method, mirror::ArtMethod::DexCacheResolvedTypesOffset())); __ Ldr(out, HeapOperand(out, CodeGenerator::GetCacheOffset(cls->GetTypeIndex()))); SlowPathCodeARM64* slow_path = new (GetGraph()->GetArena()) LoadClassSlowPathARM64( @@ -2674,9 +2674,20 @@ void LocationsBuilderARM64::VisitParameterValue(HParameterValue* instruction) { locations->SetOut(location); } -void InstructionCodeGeneratorARM64::VisitParameterValue(HParameterValue* instruction) { +void InstructionCodeGeneratorARM64::VisitParameterValue( + HParameterValue* instruction ATTRIBUTE_UNUSED) { // Nothing to do, the parameter is already at its location. - UNUSED(instruction); +} + +void LocationsBuilderARM64::VisitCurrentMethod(HCurrentMethod* instruction) { + LocationSummary* locations = + new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kNoCall); + locations->SetOut(LocationFrom(x0)); +} + +void InstructionCodeGeneratorARM64::VisitCurrentMethod( + HCurrentMethod* instruction ATTRIBUTE_UNUSED) { + // Nothing to do, the method is already at its location. } void LocationsBuilderARM64::VisitPhi(HPhi* instruction) { diff --git a/compiler/optimizing/code_generator_x86.cc b/compiler/optimizing/code_generator_x86.cc index a6f01dad38..3c5efa436f 100644 --- a/compiler/optimizing/code_generator_x86.cc +++ b/compiler/optimizing/code_generator_x86.cc @@ -36,6 +36,7 @@ namespace art { namespace x86 { static constexpr int kCurrentMethodStackOffset = 0; +static constexpr Register kMethodRegisterArgument = EAX; static constexpr Register kCoreCalleeSaves[] = { EBP, ESI, EDI }; @@ -498,7 +499,7 @@ void CodeGeneratorX86::GenerateFrameEntry() { int adjust = GetFrameSize() - FrameEntrySpillSize(); __ subl(ESP, Immediate(adjust)); __ cfi().AdjustCFAOffset(adjust); - __ movl(Address(ESP, kCurrentMethodStackOffset), EAX); + __ movl(Address(ESP, kCurrentMethodStackOffset), kMethodRegisterArgument); } void CodeGeneratorX86::GenerateFrameExit() { @@ -717,11 +718,11 @@ void CodeGeneratorX86::Move64(Location destination, Location source) { void CodeGeneratorX86::Move(HInstruction* instruction, Location location, HInstruction* move_for) { LocationSummary* locations = instruction->GetLocations(); - if (locations != nullptr && locations->Out().Equals(location)) { + if (instruction->IsCurrentMethod()) { + Move32(location, Location::StackSlot(kCurrentMethodStackOffset)); + } else if (locations != nullptr && locations->Out().Equals(location)) { return; - } - - if (locations != nullptr && locations->Out().IsConstant()) { + } else if (locations != nullptr && locations->Out().IsConstant()) { HConstant* const_to_move = locations->Out().GetConstant(); if (const_to_move->IsIntConstant() || const_to_move->IsNullConstant()) { Immediate imm(GetInt32ValueOf(const_to_move)); @@ -1239,7 +1240,7 @@ void LocationsBuilderX86::VisitInvokeVirtual(HInvokeVirtual* invoke) { void LocationsBuilderX86::HandleInvoke(HInvoke* invoke) { LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(invoke, LocationSummary::kCall); - locations->AddTemp(Location::RegisterLocation(EAX)); + locations->AddTemp(Location::RegisterLocation(kMethodRegisterArgument)); InvokeDexCallingConventionVisitorX86 calling_convention_visitor; for (size_t i = 0; i < invoke->GetNumberOfArguments(); i++) { @@ -3010,8 +3011,17 @@ void LocationsBuilderX86::VisitParameterValue(HParameterValue* instruction) { locations->SetOut(location); } -void InstructionCodeGeneratorX86::VisitParameterValue(HParameterValue* instruction) { - UNUSED(instruction); +void InstructionCodeGeneratorX86::VisitParameterValue( + HParameterValue* instruction ATTRIBUTE_UNUSED) { +} + +void LocationsBuilderX86::VisitCurrentMethod(HCurrentMethod* instruction) { + LocationSummary* locations = + new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kNoCall); + locations->SetOut(Location::RegisterLocation(kMethodRegisterArgument)); +} + +void InstructionCodeGeneratorX86::VisitCurrentMethod(HCurrentMethod* instruction ATTRIBUTE_UNUSED) { } void LocationsBuilderX86::VisitNot(HNot* not_) { @@ -4279,20 +4289,22 @@ void LocationsBuilderX86::VisitLoadClass(HLoadClass* cls) { : LocationSummary::kNoCall; LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(cls, call_kind); + locations->SetInAt(0, Location::RequiresRegister()); locations->SetOut(Location::RequiresRegister()); } void InstructionCodeGeneratorX86::VisitLoadClass(HLoadClass* cls) { - Register out = cls->GetLocations()->Out().AsRegister<Register>(); + LocationSummary* locations = cls->GetLocations(); + Register out = locations->Out().AsRegister<Register>(); + Register current_method = locations->InAt(0).AsRegister<Register>(); if (cls->IsReferrersClass()) { DCHECK(!cls->CanCallRuntime()); DCHECK(!cls->MustGenerateClinitCheck()); - codegen_->LoadCurrentMethod(out); - __ movl(out, Address(out, mirror::ArtMethod::DeclaringClassOffset().Int32Value())); + __ movl(out, Address(current_method, mirror::ArtMethod::DeclaringClassOffset().Int32Value())); } else { DCHECK(cls->CanCallRuntime()); - codegen_->LoadCurrentMethod(out); - __ movl(out, Address(out, mirror::ArtMethod::DexCacheResolvedTypesOffset().Int32Value())); + __ movl(out, Address( + current_method, mirror::ArtMethod::DexCacheResolvedTypesOffset().Int32Value())); __ movl(out, Address(out, CodeGenerator::GetCacheOffset(cls->GetTypeIndex()))); SlowPathCodeX86* slow_path = new (GetGraph()->GetArena()) LoadClassSlowPathX86( diff --git a/compiler/optimizing/code_generator_x86_64.cc b/compiler/optimizing/code_generator_x86_64.cc index f49c26db2b..7b08c89e41 100644 --- a/compiler/optimizing/code_generator_x86_64.cc +++ b/compiler/optimizing/code_generator_x86_64.cc @@ -39,13 +39,13 @@ namespace x86_64 { static constexpr Register TMP = R11; static constexpr int kCurrentMethodStackOffset = 0; +static constexpr Register kMethodRegisterArgument = RDI; static constexpr Register kCoreCalleeSaves[] = { RBX, RBP, R12, R13, R14, R15 }; static constexpr FloatRegister kFpuCalleeSaves[] = { XMM12, XMM13, XMM14, XMM15 }; static constexpr int kC2ConditionMask = 0x400; - #define __ reinterpret_cast<X86_64Assembler*>(codegen->GetAssembler())-> class NullCheckSlowPathX86_64 : public SlowPathCodeX86_64 { @@ -545,7 +545,8 @@ void CodeGeneratorX86_64::GenerateFrameEntry() { } } - __ movl(Address(CpuRegister(RSP), kCurrentMethodStackOffset), CpuRegister(RDI)); + __ movl(Address(CpuRegister(RSP), kCurrentMethodStackOffset), + CpuRegister(kMethodRegisterArgument)); } void CodeGeneratorX86_64::GenerateFrameExit() { @@ -689,11 +690,11 @@ void CodeGeneratorX86_64::Move(HInstruction* instruction, Location location, HInstruction* move_for) { LocationSummary* locations = instruction->GetLocations(); - if (locations != nullptr && locations->Out().Equals(location)) { + if (instruction->IsCurrentMethod()) { + Move(location, Location::StackSlot(kCurrentMethodStackOffset)); + } else if (locations != nullptr && locations->Out().Equals(location)) { return; - } - - if (locations != nullptr && locations->Out().IsConstant()) { + } else if (locations != nullptr && locations->Out().IsConstant()) { HConstant* const_to_move = locations->Out().GetConstant(); if (const_to_move->IsIntConstant() || const_to_move->IsNullConstant()) { Immediate imm(GetInt32ValueOf(const_to_move)); @@ -1339,7 +1340,7 @@ void InstructionCodeGeneratorX86_64::VisitInvokeStaticOrDirect(HInvokeStaticOrDi void LocationsBuilderX86_64::HandleInvoke(HInvoke* invoke) { LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(invoke, LocationSummary::kCall); - locations->AddTemp(Location::RegisterLocation(RDI)); + locations->AddTemp(Location::RegisterLocation(kMethodRegisterArgument)); InvokeDexCallingConventionVisitorX86_64 calling_convention_visitor; for (size_t i = 0; i < invoke->GetNumberOfArguments(); i++) { @@ -3066,9 +3067,20 @@ void LocationsBuilderX86_64::VisitParameterValue(HParameterValue* instruction) { locations->SetOut(location); } -void InstructionCodeGeneratorX86_64::VisitParameterValue(HParameterValue* instruction) { +void InstructionCodeGeneratorX86_64::VisitParameterValue( + HParameterValue* instruction ATTRIBUTE_UNUSED) { // Nothing to do, the parameter is already at its location. - UNUSED(instruction); +} + +void LocationsBuilderX86_64::VisitCurrentMethod(HCurrentMethod* instruction) { + LocationSummary* locations = + new (GetGraph()->GetArena()) LocationSummary(instruction, LocationSummary::kNoCall); + locations->SetOut(Location::RegisterLocation(kMethodRegisterArgument)); +} + +void InstructionCodeGeneratorX86_64::VisitCurrentMethod( + HCurrentMethod* instruction ATTRIBUTE_UNUSED) { + // Nothing to do, the method is already at its location. } void LocationsBuilderX86_64::VisitNot(HNot* not_) { @@ -4123,20 +4135,22 @@ void LocationsBuilderX86_64::VisitLoadClass(HLoadClass* cls) { : LocationSummary::kNoCall; LocationSummary* locations = new (GetGraph()->GetArena()) LocationSummary(cls, call_kind); + locations->SetInAt(0, Location::RequiresRegister()); locations->SetOut(Location::RequiresRegister()); } void InstructionCodeGeneratorX86_64::VisitLoadClass(HLoadClass* cls) { - CpuRegister out = cls->GetLocations()->Out().AsRegister<CpuRegister>(); + LocationSummary* locations = cls->GetLocations(); + CpuRegister out = locations->Out().AsRegister<CpuRegister>(); + CpuRegister current_method = locations->InAt(0).AsRegister<CpuRegister>(); if (cls->IsReferrersClass()) { DCHECK(!cls->CanCallRuntime()); DCHECK(!cls->MustGenerateClinitCheck()); - codegen_->LoadCurrentMethod(out); - __ movl(out, Address(out, mirror::ArtMethod::DeclaringClassOffset().Int32Value())); + __ movl(out, Address(current_method, mirror::ArtMethod::DeclaringClassOffset().Int32Value())); } else { DCHECK(cls->CanCallRuntime()); - codegen_->LoadCurrentMethod(out); - __ movl(out, Address(out, mirror::ArtMethod::DexCacheResolvedTypesOffset().Int32Value())); + __ movl(out, Address( + current_method, mirror::ArtMethod::DexCacheResolvedTypesOffset().Int32Value())); __ movl(out, Address(out, CodeGenerator::GetCacheOffset(cls->GetTypeIndex()))); SlowPathCodeX86_64* slow_path = new (GetGraph()->GetArena()) LoadClassSlowPathX86_64( cls, cls, cls->GetDexPc(), cls->MustGenerateClinitCheck()); diff --git a/compiler/optimizing/nodes.cc b/compiler/optimizing/nodes.cc index 483c09e5a9..80d4b4a863 100644 --- a/compiler/optimizing/nodes.cc +++ b/compiler/optimizing/nodes.cc @@ -295,6 +295,19 @@ HNullConstant* HGraph::GetNullConstant() { return cached_null_constant_; } +HCurrentMethod* HGraph::GetCurrentMethod() { + if (cached_current_method_ == nullptr) { + cached_current_method_ = new (arena_) HCurrentMethod(); + if (entry_block_->GetFirstInstruction() == nullptr) { + entry_block_->AddInstruction(cached_current_method_); + } else { + entry_block_->InsertInstructionBefore( + cached_current_method_, entry_block_->GetFirstInstruction()); + } + } + return cached_current_method_; +} + HConstant* HGraph::GetConstant(Primitive::Type type, int64_t value) { switch (type) { case Primitive::Type::kPrimBoolean: @@ -1461,6 +1474,8 @@ void HGraph::InlineInto(HGraph* outer_graph, HInvoke* invoke) { DCHECK(parameter_index != last_input_index); } current->ReplaceWith(invoke->InputAt(parameter_index++)); + } else if (current->IsCurrentMethod()) { + current->ReplaceWith(outer_graph->GetCurrentMethod()); } else { DCHECK(current->IsGoto() || current->IsSuspendCheck()); entry_block_->RemoveInstruction(current); diff --git a/compiler/optimizing/nodes.h b/compiler/optimizing/nodes.h index 01870c36fa..d542e59621 100644 --- a/compiler/optimizing/nodes.h +++ b/compiler/optimizing/nodes.h @@ -35,6 +35,7 @@ namespace art { class GraphChecker; class HBasicBlock; +class HCurrentMethod; class HDoubleConstant; class HEnvironment; class HFloatConstant; @@ -147,7 +148,8 @@ class HGraph : public ArenaObject<kArenaAllocMisc> { cached_int_constants_(std::less<int32_t>(), arena->Adapter()), cached_float_constants_(std::less<int32_t>(), arena->Adapter()), cached_long_constants_(std::less<int64_t>(), arena->Adapter()), - cached_double_constants_(std::less<int64_t>(), arena->Adapter()) {} + cached_double_constants_(std::less<int64_t>(), arena->Adapter()), + cached_current_method_(nullptr) {} ArenaAllocator* GetArena() const { return arena_; } const GrowableArray<HBasicBlock*>& GetBlocks() const { return blocks_; } @@ -278,6 +280,8 @@ class HGraph : public ArenaObject<kArenaAllocMisc> { return CreateConstant(bit_cast<int64_t, double>(value), &cached_double_constants_); } + HCurrentMethod* GetCurrentMethod(); + HBasicBlock* FindCommonDominator(HBasicBlock* first, HBasicBlock* second) const; const DexFile& GetDexFile() const { @@ -386,6 +390,8 @@ class HGraph : public ArenaObject<kArenaAllocMisc> { ArenaSafeMap<int64_t, HLongConstant*> cached_long_constants_; ArenaSafeMap<int64_t, HDoubleConstant*> cached_double_constants_; + HCurrentMethod* cached_current_method_; + friend class SsaBuilder; // For caching constants. friend class SsaLivenessAnalysis; // For the linear order. ART_FRIEND_TEST(GraphTest, IfSuccessorSimpleJoinBlock1); @@ -811,6 +817,7 @@ class HLoopInformationOutwardIterator : public ValueObject { M(ClinitCheck, Instruction) \ M(Compare, BinaryOperation) \ M(Condition, BinaryOperation) \ + M(CurrentMethod, Instruction) \ M(Deoptimize, Instruction) \ M(Div, BinaryOperation) \ M(DivZeroCheck, Instruction) \ @@ -1824,6 +1831,19 @@ class HDeoptimize : public HTemplateInstruction<1> { DISALLOW_COPY_AND_ASSIGN(HDeoptimize); }; +// Represents the ArtMethod that was passed as a first argument to +// the method. It is used by instructions that depend on it, like +// instructions that work with the dex cache. +class HCurrentMethod : public HExpression<0> { + public: + HCurrentMethod() : HExpression(Primitive::kPrimNot, SideEffects::None()) {} + + DECLARE_INSTRUCTION(CurrentMethod); + + private: + DISALLOW_COPY_AND_ASSIGN(HCurrentMethod); +}; + class HUnaryOperation : public HExpression<1> { public: HUnaryOperation(Primitive::Type result_type, HInstruction* input) @@ -3433,9 +3453,10 @@ class HSuspendCheck : public HTemplateInstruction<0> { /** * Instruction to load a Class object. */ -class HLoadClass : public HExpression<0> { +class HLoadClass : public HExpression<1> { public: - HLoadClass(uint16_t type_index, + HLoadClass(HCurrentMethod* current_method, + uint16_t type_index, const DexFile& dex_file, bool is_referrers_class, uint32_t dex_pc) @@ -3445,7 +3466,9 @@ class HLoadClass : public HExpression<0> { is_referrers_class_(is_referrers_class), dex_pc_(dex_pc), generate_clinit_check_(false), - loaded_class_rti_(ReferenceTypeInfo::CreateTop(/* is_exact */ false)) {} + loaded_class_rti_(ReferenceTypeInfo::CreateTop(/* is_exact */ false)) { + SetRawInputAt(0, current_method); + } bool CanBeMoved() const OVERRIDE { return true; } diff --git a/compiler/optimizing/register_allocator.cc b/compiler/optimizing/register_allocator.cc index 925099ade6..d4ff4d8dee 100644 --- a/compiler/optimizing/register_allocator.cc +++ b/compiler/optimizing/register_allocator.cc @@ -482,8 +482,9 @@ bool RegisterAllocator::ValidateIntervals(const GrowableArray<LiveInterval*>& in LiveInterval* current = it.CurrentInterval(); HInstruction* defined_by = current->GetParent()->GetDefinedBy(); if (current->GetParent()->HasSpillSlot() - // Parameters have their own stack slot. - && !(defined_by != nullptr && defined_by->IsParameterValue())) { + // Parameters and current method have their own stack slot. + && !(defined_by != nullptr && (defined_by->IsParameterValue() + || defined_by->IsCurrentMethod()))) { BitVector* liveness_of_spill_slot = liveness_of_values.Get(number_of_registers + current->GetParent()->GetSpillSlot() / kVRegSize - number_of_out_slots); @@ -1246,6 +1247,11 @@ void RegisterAllocator::AllocateSpillSlotFor(LiveInterval* interval) { return; } + if (defined_by->IsCurrentMethod()) { + parent->SetSpillSlot(0); + return; + } + if (defined_by->IsConstant()) { // Constants don't need a spill slot. return; @@ -1519,7 +1525,10 @@ void RegisterAllocator::InsertMoveAfter(HInstruction* instruction, void RegisterAllocator::ConnectSiblings(LiveInterval* interval) { LiveInterval* current = interval; - if (current->HasSpillSlot() && current->HasRegister()) { + if (current->HasSpillSlot() + && current->HasRegister() + // Currently, we spill unconditionnally the current method in the code generators. + && !interval->GetDefinedBy()->IsCurrentMethod()) { // We spill eagerly, so move must be at definition. InsertMoveAfter(interval->GetDefinedBy(), interval->ToLocation(), @@ -1715,6 +1724,9 @@ void RegisterAllocator::Resolve() { } else if (current->HasSpillSlot()) { current->SetSpillSlot(current->GetSpillSlot() + codegen_->GetFrameSize()); } + } else if (instruction->IsCurrentMethod()) { + // The current method is always at offset 0. + DCHECK(!current->HasSpillSlot() || (current->GetSpillSlot() == 0)); } else if (current->HasSpillSlot()) { // Adjust the stack slot, now that we know the number of them for each type. // The way this implementation lays out the stack is the following: diff --git a/test/482-checker-loop-back-edge-use/src/Main.java b/test/482-checker-loop-back-edge-use/src/Main.java index 0ed926703d..f5796927f5 100644 --- a/test/482-checker-loop-back-edge-use/src/Main.java +++ b/test/482-checker-loop-back-edge-use/src/Main.java @@ -25,9 +25,9 @@ public class Main { } // CHECK-START: void Main.loop2(boolean) liveness (after) - // CHECK: ParameterValue liveness:2 ranges:{[2,42)} uses:[33,38,42] - // CHECK: Goto liveness:36 - // CHECK: Goto liveness:40 + // CHECK: ParameterValue liveness:4 ranges:{[4,44)} uses:[35,40,44] + // CHECK: Goto liveness:38 + // CHECK: Goto liveness:42 public static void loop2(boolean incoming) { while (true) { System.out.println("foo"); @@ -36,11 +36,11 @@ public class Main { } // CHECK-START: void Main.loop3(boolean) liveness (after) - // CHECK: ParameterValue liveness:2 ranges:{[2,60)} uses:[56,60] - // CHECK: Goto liveness:58 + // CHECK: ParameterValue liveness:4 ranges:{[4,62)} uses:[58,62] + // CHECK: Goto liveness:60 // CHECK-START: void Main.loop3(boolean) liveness (after) - // CHECK-NOT: Goto liveness:54 + // CHECK-NOT: Goto liveness:56 public static void loop3(boolean incoming) { // 'incoming' only needs a use at the outer loop's back edge. while (System.currentTimeMillis() != 42) { @@ -50,10 +50,10 @@ public class Main { } // CHECK-START: void Main.loop4(boolean) liveness (after) - // CHECK: ParameterValue liveness:2 ranges:{[2,22)} uses:[22] + // CHECK: ParameterValue liveness:4 ranges:{[4,24)} uses:[24] // CHECK-START: void Main.loop4(boolean) liveness (after) - // CHECK-NOT: Goto liveness:20 + // CHECK-NOT: Goto liveness:22 public static void loop4(boolean incoming) { // 'incoming' has no loop use, so should not have back edge uses. System.out.println(incoming); @@ -63,9 +63,9 @@ public class Main { } // CHECK-START: void Main.loop5(boolean) liveness (after) - // CHECK: ParameterValue liveness:2 ranges:{[2,50)} uses:[33,42,46,50] - // CHECK: Goto liveness:44 - // CHECK: Goto liveness:48 + // CHECK: ParameterValue liveness:4 ranges:{[4,52)} uses:[35,44,48,52] + // CHECK: Goto liveness:46 + // CHECK: Goto liveness:50 public static void loop5(boolean incoming) { // 'incoming' must have a use at both back edges. while (Runtime.getRuntime() != null) { @@ -76,11 +76,11 @@ public class Main { } // CHECK-START: void Main.loop6(boolean) liveness (after) - // CHECK ParameterValue liveness:2 ranges:{[2,46)} uses:[24,46] - // CHECK: Goto liveness:44 + // CHECK: ParameterValue liveness:4 ranges:{[4,48)} uses:[26,48] + // CHECK: Goto liveness:46 // CHECK-START: void Main.loop6(boolean) liveness (after) - // CHECK-NOT: Goto liveness:22 + // CHECK-NOT: Goto liveness:24 public static void loop6(boolean incoming) { // 'incoming' must have a use only at the first loop's back edge. while (true) { @@ -90,9 +90,9 @@ public class Main { } // CHECK-START: void Main.loop7(boolean) liveness (after) - // CHECK: ParameterValue liveness:2 ranges:{[2,50)} uses:[32,41,46,50] - // CHECK: Goto liveness:44 - // CHECK: Goto liveness:48 + // CHECK: ParameterValue liveness:4 ranges:{[4,52)} uses:[34,43,48,52] + // CHECK: Goto liveness:46 + // CHECK: Goto liveness:50 public static void loop7(boolean incoming) { // 'incoming' must have a use at both back edges. while (Runtime.getRuntime() != null) { @@ -102,9 +102,9 @@ public class Main { } // CHECK-START: void Main.loop8() liveness (after) - // CHECK: StaticFieldGet liveness:12 ranges:{[12,44)} uses:[35,40,44] - // CHECK: Goto liveness:38 - // CHECK: Goto liveness:42 + // CHECK: StaticFieldGet liveness:14 ranges:{[14,46)} uses:[37,42,46] + // CHECK: Goto liveness:40 + // CHECK: Goto liveness:44 public static void loop8() { // 'incoming' must have a use at both back edges. boolean incoming = field; @@ -114,8 +114,8 @@ public class Main { } // CHECK-START: void Main.loop9() liveness (after) - // CHECK: StaticFieldGet liveness:22 ranges:{[22,36)} uses:[31,36] - // CHECK: Goto liveness:38 + // CHECK: StaticFieldGet liveness:24 ranges:{[24,38)} uses:[33,38] + // CHECK: Goto liveness:40 public static void loop9() { while (Runtime.getRuntime() != null) { // 'incoming' must only have a use in the inner loop. |