diff options
| author | 2015-09-17 12:29:02 +0000 | |
|---|---|---|
| committer | 2015-09-17 12:29:02 +0000 | |
| commit | 9d567824e101428adfde58976a1307fbd6c0e247 (patch) | |
| tree | 9ea1b98840ee6108408d6f11e0c670e39eb28136 /compiler/optimizing | |
| parent | b4b543d79b427fa96f0dd635014bd8754a798cc9 (diff) | |
| parent | 175dc732c80e6f2afd83209348124df349290ba8 (diff) | |
Merge "Support unresolved methods in Optimizing"
Diffstat (limited to 'compiler/optimizing')
| -rw-r--r-- | compiler/optimizing/builder.cc | 19 | ||||
| -rw-r--r-- | compiler/optimizing/code_generator.cc | 25 | ||||
| -rw-r--r-- | compiler/optimizing/code_generator.h | 8 | ||||
| -rw-r--r-- | compiler/optimizing/code_generator_arm.cc | 31 | ||||
| -rw-r--r-- | compiler/optimizing/code_generator_arm.h | 12 | ||||
| -rw-r--r-- | compiler/optimizing/code_generator_arm64.cc | 44 | ||||
| -rw-r--r-- | compiler/optimizing/code_generator_arm64.h | 6 | ||||
| -rw-r--r-- | compiler/optimizing/code_generator_mips64.cc | 44 | ||||
| -rw-r--r-- | compiler/optimizing/code_generator_mips64.h | 7 | ||||
| -rw-r--r-- | compiler/optimizing/code_generator_x86.cc | 50 | ||||
| -rw-r--r-- | compiler/optimizing/code_generator_x86.h | 8 | ||||
| -rw-r--r-- | compiler/optimizing/code_generator_x86_64.cc | 50 | ||||
| -rw-r--r-- | compiler/optimizing/code_generator_x86_64.h | 8 | ||||
| -rw-r--r-- | compiler/optimizing/graph_visualizer.cc | 5 | ||||
| -rw-r--r-- | compiler/optimizing/inliner.cc | 5 | ||||
| -rw-r--r-- | compiler/optimizing/nodes.h | 24 | ||||
| -rw-r--r-- | compiler/optimizing/optimizing_compiler.cc | 12 | ||||
| -rw-r--r-- | compiler/optimizing/optimizing_compiler_stats.h | 4 |
18 files changed, 301 insertions, 61 deletions
diff --git a/compiler/optimizing/builder.cc b/compiler/optimizing/builder.cc index a2a0696cd4..3663448f64 100644 --- a/compiler/optimizing/builder.cc +++ b/compiler/optimizing/builder.cc @@ -839,11 +839,20 @@ bool HGraphBuilder::BuildInvoke(const Instruction& instruction, &table_index, &direct_code, &direct_method)) { - VLOG(compiler) << "Did not compile " - << PrettyMethod(dex_compilation_unit_->GetDexMethodIndex(), *dex_file_) - << " because a method call could not be resolved"; - MaybeRecordStat(MethodCompilationStat::kNotCompiledUnresolvedMethod); - return false; + MaybeRecordStat(MethodCompilationStat::kUnresolvedMethod); + HInvoke* invoke = new (arena_) HInvokeUnresolved(arena_, + number_of_arguments, + return_type, + dex_pc, + method_idx, + original_invoke_type); + return HandleInvoke(invoke, + number_of_vreg_arguments, + args, + register_index, + is_range, + descriptor, + nullptr /* clinit_check */); } // Handle resolved methods (non string init). diff --git a/compiler/optimizing/code_generator.cc b/compiler/optimizing/code_generator.cc index 50108a7275..3c6a41df34 100644 --- a/compiler/optimizing/code_generator.cc +++ b/compiler/optimizing/code_generator.cc @@ -388,6 +388,31 @@ void CodeGenerator::CreateCommonInvokeLocationSummary( } } +void CodeGenerator::GenerateInvokeUnresolvedRuntimeCall(HInvokeUnresolved* invoke) { + MoveConstant(invoke->GetLocations()->GetTemp(0), invoke->GetDexMethodIndex()); + + // Initialize to anything to silent compiler warnings. + QuickEntrypointEnum entrypoint = kQuickInvokeStaticTrampolineWithAccessCheck; + switch (invoke->GetOriginalInvokeType()) { + case kStatic: + entrypoint = kQuickInvokeStaticTrampolineWithAccessCheck; + break; + case kDirect: + entrypoint = kQuickInvokeDirectTrampolineWithAccessCheck; + break; + case kVirtual: + entrypoint = kQuickInvokeVirtualTrampolineWithAccessCheck; + break; + case kSuper: + entrypoint = kQuickInvokeSuperTrampolineWithAccessCheck; + break; + case kInterface: + entrypoint = kQuickInvokeInterfaceTrampolineWithAccessCheck; + break; + } + InvokeRuntime(entrypoint, invoke, invoke->GetDexPc(), nullptr); +} + void CodeGenerator::BlockIfInRegister(Location location, bool is_out) const { // The DCHECKS below check that a register is not specified twice in // the summary. The out location can overlap with an input, so we need diff --git a/compiler/optimizing/code_generator.h b/compiler/optimizing/code_generator.h index d2af56a33a..a54dbf1506 100644 --- a/compiler/optimizing/code_generator.h +++ b/compiler/optimizing/code_generator.h @@ -169,6 +169,7 @@ class CodeGenerator { virtual void GenerateFrameExit() = 0; virtual void Bind(HBasicBlock* block) = 0; virtual void Move(HInstruction* instruction, Location location, HInstruction* move_for) = 0; + virtual void MoveConstant(Location destination, int32_t value) = 0; virtual Assembler* GetAssembler() = 0; virtual const Assembler& GetAssembler() const = 0; virtual size_t GetWordSize() const = 0; @@ -375,9 +376,16 @@ class CodeGenerator { static void CreateCommonInvokeLocationSummary( HInvoke* invoke, InvokeDexCallingConventionVisitor* visitor); + void GenerateInvokeUnresolvedRuntimeCall(HInvokeUnresolved* invoke); + void SetDisassemblyInformation(DisassemblyInformation* info) { disasm_info_ = info; } DisassemblyInformation* GetDisassemblyInformation() const { return disasm_info_; } + virtual void InvokeRuntime(QuickEntrypointEnum entrypoint, + HInstruction* instruction, + uint32_t dex_pc, + SlowPathCode* slow_path) = 0; + protected: // Method patch info used for recording locations of required linker patches and // target methods. The target method can be used for various purposes, whether for diff --git a/compiler/optimizing/code_generator_arm.cc b/compiler/optimizing/code_generator_arm.cc index c3d63b9952..6f89293018 100644 --- a/compiler/optimizing/code_generator_arm.cc +++ b/compiler/optimizing/code_generator_arm.cc @@ -710,6 +710,7 @@ Location InvokeDexCallingConventionVisitorARM::GetNextLocation(Primitive::Type t if (index + 1 < calling_convention.GetNumberOfRegisters()) { DCHECK_EQ(calling_convention.GetRegisterAt(index) + 1, calling_convention.GetRegisterAt(index + 1)); + return Location::RegisterPairLocation(calling_convention.GetRegisterAt(index), calling_convention.GetRegisterAt(index + 1)); } else { @@ -963,6 +964,21 @@ void CodeGeneratorARM::Move(HInstruction* instruction, Location location, HInstr } } +void CodeGeneratorARM::MoveConstant(Location location, int32_t value) { + DCHECK(location.IsRegister()); + __ LoadImmediate(location.AsRegister<Register>(), value); +} + +void CodeGeneratorARM::InvokeRuntime(QuickEntrypointEnum entrypoint, + HInstruction* instruction, + uint32_t dex_pc, + SlowPathCode* slow_path) { + InvokeRuntime(GetThreadOffset<kArmWordSize>(entrypoint).Int32Value(), + instruction, + dex_pc, + slow_path); +} + void CodeGeneratorARM::InvokeRuntime(int32_t entry_point_offset, HInstruction* instruction, uint32_t dex_pc, @@ -1515,6 +1531,17 @@ void InstructionCodeGeneratorARM::VisitReturn(HReturn* ret) { codegen_->GenerateFrameExit(); } +void LocationsBuilderARM::VisitInvokeUnresolved(HInvokeUnresolved* invoke) { + // The trampoline uses the same calling convention as dex calling conventions, + // except instead of loading arg0/r0 with the target Method*, arg0/r0 will contain + // the method_idx. + HandleInvoke(invoke); +} + +void InstructionCodeGeneratorARM::VisitInvokeUnresolved(HInvokeUnresolved* invoke) { + codegen_->GenerateInvokeUnresolvedRuntimeCall(invoke); +} + void LocationsBuilderARM::VisitInvokeStaticOrDirect(HInvokeStaticOrDirect* invoke) { // When we do not run baseline, explicit clinit checks triggered by static // invokes must have been pruned by art::PrepareForRegisterAllocation. @@ -2967,7 +2994,7 @@ void InstructionCodeGeneratorARM::VisitNewInstance(HNewInstance* instruction) { __ LoadImmediate(calling_convention.GetRegisterAt(0), instruction->GetTypeIndex()); // Note: if heap poisoning is enabled, the entry point takes cares // of poisoning the reference. - codegen_->InvokeRuntime(GetThreadOffset<kArmWordSize>(instruction->GetEntrypoint()).Int32Value(), + codegen_->InvokeRuntime(instruction->GetEntrypoint(), instruction, instruction->GetDexPc(), nullptr); @@ -2988,7 +3015,7 @@ void InstructionCodeGeneratorARM::VisitNewArray(HNewArray* instruction) { __ LoadImmediate(calling_convention.GetRegisterAt(0), instruction->GetTypeIndex()); // Note: if heap poisoning is enabled, the entry point takes cares // of poisoning the reference. - codegen_->InvokeRuntime(GetThreadOffset<kArmWordSize>(instruction->GetEntrypoint()).Int32Value(), + codegen_->InvokeRuntime(instruction->GetEntrypoint(), instruction, instruction->GetDexPc(), nullptr); diff --git a/compiler/optimizing/code_generator_arm.h b/compiler/optimizing/code_generator_arm.h index e44209d41b..91cfd00b47 100644 --- a/compiler/optimizing/code_generator_arm.h +++ b/compiler/optimizing/code_generator_arm.h @@ -239,6 +239,7 @@ class CodeGeneratorARM : public CodeGenerator { void GenerateFrameExit() OVERRIDE; void Bind(HBasicBlock* block) OVERRIDE; void Move(HInstruction* instruction, Location location, HInstruction* move_for) OVERRIDE; + void MoveConstant(Location destination, int32_t value) OVERRIDE; size_t SaveCoreRegister(size_t stack_index, uint32_t reg_id) OVERRIDE; size_t RestoreCoreRegister(size_t stack_index, uint32_t reg_id) OVERRIDE; size_t SaveFloatingPointRegister(size_t stack_index, uint32_t reg_id) OVERRIDE; @@ -299,8 +300,15 @@ class CodeGeneratorARM : public CodeGenerator { void Move64(Location destination, Location source); // Generate code to invoke a runtime entry point. - void InvokeRuntime( - int32_t offset, HInstruction* instruction, uint32_t dex_pc, SlowPathCode* slow_path); + void InvokeRuntime(QuickEntrypointEnum entrypoint, + HInstruction* instruction, + uint32_t dex_pc, + SlowPathCode* slow_path) OVERRIDE; + + void InvokeRuntime(int32_t offset, + HInstruction* instruction, + uint32_t dex_pc, + SlowPathCode* slow_path); // Emit a write barrier. void MarkGCCard(Register temp, Register card, Register object, Register value, bool can_be_null); diff --git a/compiler/optimizing/code_generator_arm64.cc b/compiler/optimizing/code_generator_arm64.cc index 377eaf6c40..531b66927b 100644 --- a/compiler/optimizing/code_generator_arm64.cc +++ b/compiler/optimizing/code_generator_arm64.cc @@ -716,6 +716,11 @@ void CodeGeneratorARM64::Move(HInstruction* instruction, } } +void CodeGeneratorARM64::MoveConstant(Location location, int32_t value) { + DCHECK(location.IsRegister()); + __ Mov(RegisterFrom(location, Primitive::kPrimInt), value); +} + Location CodeGeneratorARM64::GetStackLocation(HLoadLocal* load) const { Primitive::Type type = load->GetType(); @@ -1107,6 +1112,16 @@ void CodeGeneratorARM64::StoreRelease(Primitive::Type type, } } +void CodeGeneratorARM64::InvokeRuntime(QuickEntrypointEnum entrypoint, + HInstruction* instruction, + uint32_t dex_pc, + SlowPathCode* slow_path) { + InvokeRuntime(GetThreadOffset<kArm64WordSize>(entrypoint).Int32Value(), + instruction, + dex_pc, + slow_path); +} + void CodeGeneratorARM64::InvokeRuntime(int32_t entry_point_offset, HInstruction* instruction, uint32_t dex_pc, @@ -2305,6 +2320,17 @@ void InstructionCodeGeneratorARM64::VisitNullConstant(HNullConstant* constant) { UNUSED(constant); } +void LocationsBuilderARM64::VisitInvokeUnresolved(HInvokeUnresolved* invoke) { + // The trampoline uses the same calling convention as dex calling conventions, + // except instead of loading arg0/r0 with the target Method*, arg0/r0 will contain + // the method_idx. + HandleInvoke(invoke); +} + +void InstructionCodeGeneratorARM64::VisitInvokeUnresolved(HInvokeUnresolved* invoke) { + codegen_->GenerateInvokeUnresolvedRuntimeCall(invoke); +} + void LocationsBuilderARM64::HandleInvoke(HInvoke* invoke) { InvokeDexCallingConventionVisitorARM64 calling_convention_visitor; CodeGenerator::CreateCommonInvokeLocationSummary(invoke, &calling_convention_visitor); @@ -2831,11 +2857,10 @@ void InstructionCodeGeneratorARM64::VisitNewArray(HNewArray* instruction) { __ Mov(type_index, instruction->GetTypeIndex()); // Note: if heap poisoning is enabled, the entry point takes cares // of poisoning the reference. - codegen_->InvokeRuntime( - GetThreadOffset<kArm64WordSize>(instruction->GetEntrypoint()).Int32Value(), - instruction, - instruction->GetDexPc(), - nullptr); + codegen_->InvokeRuntime(instruction->GetEntrypoint(), + instruction, + instruction->GetDexPc(), + nullptr); CheckEntrypointTypes<kQuickAllocArrayWithAccessCheck, void*, uint32_t, int32_t, ArtMethod*>(); } @@ -2856,11 +2881,10 @@ void InstructionCodeGeneratorARM64::VisitNewInstance(HNewInstance* instruction) __ Mov(type_index, instruction->GetTypeIndex()); // Note: if heap poisoning is enabled, the entry point takes cares // of poisoning the reference. - codegen_->InvokeRuntime( - GetThreadOffset<kArm64WordSize>(instruction->GetEntrypoint()).Int32Value(), - instruction, - instruction->GetDexPc(), - nullptr); + codegen_->InvokeRuntime(instruction->GetEntrypoint(), + instruction, + instruction->GetDexPc(), + nullptr); CheckEntrypointTypes<kQuickAllocObjectWithAccessCheck, void*, uint32_t, ArtMethod*>(); } diff --git a/compiler/optimizing/code_generator_arm64.h b/compiler/optimizing/code_generator_arm64.h index 3211a831f6..576406e0fd 100644 --- a/compiler/optimizing/code_generator_arm64.h +++ b/compiler/optimizing/code_generator_arm64.h @@ -338,6 +338,7 @@ class CodeGeneratorARM64 : public CodeGenerator { // Code generation helpers. void MoveConstant(vixl::CPURegister destination, HConstant* constant); + void MoveConstant(Location destination, int32_t value) OVERRIDE; // The type is optional. When specified it must be coherent with the // locations, and is used for optimisation and debugging. void MoveLocation(Location destination, Location source, @@ -348,6 +349,11 @@ class CodeGeneratorARM64 : public CodeGenerator { void StoreRelease(Primitive::Type type, vixl::CPURegister rt, const vixl::MemOperand& dst); // Generate code to invoke a runtime entry point. + void InvokeRuntime(QuickEntrypointEnum entrypoint, + HInstruction* instruction, + uint32_t dex_pc, + SlowPathCode* slow_path) OVERRIDE; + void InvokeRuntime(int32_t offset, HInstruction* instruction, uint32_t dex_pc, diff --git a/compiler/optimizing/code_generator_mips64.cc b/compiler/optimizing/code_generator_mips64.cc index 0787e49dda..bf0d2e2a11 100644 --- a/compiler/optimizing/code_generator_mips64.cc +++ b/compiler/optimizing/code_generator_mips64.cc @@ -856,6 +856,11 @@ void CodeGeneratorMIPS64::Move(HInstruction* instruction, } } +void CodeGeneratorMIPS64::MoveConstant(Location location, int32_t value) { + DCHECK(location.IsRegister()); + __ LoadConst32(location.AsRegister<GpuRegister>(), value); +} + Location CodeGeneratorMIPS64::GetStackLocation(HLoadLocal* load) const { Primitive::Type type = load->GetType(); @@ -973,6 +978,16 @@ void CodeGeneratorMIPS64::DumpFloatingPointRegister(std::ostream& stream, int re stream << Mips64ManagedRegister::FromFpuRegister(FpuRegister(reg)); } +void CodeGeneratorMIPS64::InvokeRuntime(QuickEntrypointEnum entrypoint, + HInstruction* instruction, + uint32_t dex_pc, + SlowPathCode* slow_path) { + InvokeRuntime(GetThreadOffset<kMips64WordSize>(entrypoint).Int32Value(), + instruction, + dex_pc, + slow_path); +} + void CodeGeneratorMIPS64::InvokeRuntime(int32_t entry_point_offset, HInstruction* instruction, uint32_t dex_pc, @@ -2326,6 +2341,17 @@ void InstructionCodeGeneratorMIPS64::VisitNullConstant(HNullConstant* constant A // Will be generated at use site. } +void LocationsBuilderMIPS64::VisitInvokeUnresolved(HInvokeUnresolved* invoke) { + // The trampoline uses the same calling convention as dex calling conventions, + // except instead of loading arg0/r0 with the target Method*, arg0/r0 will contain + // the method_idx. + HandleInvoke(invoke); +} + +void InstructionCodeGeneratorMIPS64::VisitInvokeUnresolved(HInvokeUnresolved* invoke) { + codegen_->GenerateInvokeUnresolvedRuntimeCall(invoke); +} + void LocationsBuilderMIPS64::HandleInvoke(HInvoke* invoke) { InvokeDexCallingConventionVisitorMIPS64 calling_convention_visitor; CodeGenerator::CreateCommonInvokeLocationSummary(invoke, &calling_convention_visitor); @@ -2775,11 +2801,10 @@ void InstructionCodeGeneratorMIPS64::VisitNewArray(HNewArray* instruction) { LocationSummary* locations = instruction->GetLocations(); // Move an uint16_t value to a register. __ LoadConst32(locations->GetTemp(0).AsRegister<GpuRegister>(), instruction->GetTypeIndex()); - codegen_->InvokeRuntime( - GetThreadOffset<kMips64WordSize>(instruction->GetEntrypoint()).Int32Value(), - instruction, - instruction->GetDexPc(), - nullptr); + codegen_->InvokeRuntime(instruction->GetEntrypoint(), + instruction, + instruction->GetDexPc(), + nullptr); CheckEntrypointTypes<kQuickAllocArrayWithAccessCheck, void*, uint32_t, int32_t, ArtMethod*>(); } @@ -2796,11 +2821,10 @@ void InstructionCodeGeneratorMIPS64::VisitNewInstance(HNewInstance* instruction) LocationSummary* locations = instruction->GetLocations(); // Move an uint16_t value to a register. __ LoadConst32(locations->GetTemp(0).AsRegister<GpuRegister>(), instruction->GetTypeIndex()); - codegen_->InvokeRuntime( - GetThreadOffset<kMips64WordSize>(instruction->GetEntrypoint()).Int32Value(), - instruction, - instruction->GetDexPc(), - nullptr); + codegen_->InvokeRuntime(instruction->GetEntrypoint(), + instruction, + instruction->GetDexPc(), + nullptr); CheckEntrypointTypes<kQuickAllocObjectWithAccessCheck, void*, uint32_t, ArtMethod*>(); } diff --git a/compiler/optimizing/code_generator_mips64.h b/compiler/optimizing/code_generator_mips64.h index c7548388d1..8511eb6fe5 100644 --- a/compiler/optimizing/code_generator_mips64.h +++ b/compiler/optimizing/code_generator_mips64.h @@ -283,9 +283,16 @@ class CodeGeneratorMIPS64 : public CodeGenerator { void MoveLocation(Location destination, Location source, Primitive::Type type); + void MoveConstant(Location destination, int32_t value) OVERRIDE; + void SwapLocations(Location loc1, Location loc2, Primitive::Type type); // Generate code to invoke a runtime entry point. + void InvokeRuntime(QuickEntrypointEnum entrypoint, + HInstruction* instruction, + uint32_t dex_pc, + SlowPathCode* slow_path) OVERRIDE; + void InvokeRuntime(int32_t offset, HInstruction* instruction, uint32_t dex_pc, diff --git a/compiler/optimizing/code_generator_x86.cc b/compiler/optimizing/code_generator_x86.cc index c7ddabb5fb..9c5ecc3544 100644 --- a/compiler/optimizing/code_generator_x86.cc +++ b/compiler/optimizing/code_generator_x86.cc @@ -47,7 +47,7 @@ static constexpr int kC2ConditionMask = 0x400; static constexpr int kFakeReturnRegister = Register(8); #define __ down_cast<X86Assembler*>(codegen->GetAssembler())-> -#define QUICK_ENTRY_POINT(x) Address::Absolute(QUICK_ENTRYPOINT_OFFSET(kX86WordSize, x)) +#define QUICK_ENTRY_POINT(x) QUICK_ENTRYPOINT_OFFSET(kX86WordSize, x).Int32Value() class NullCheckSlowPathX86 : public SlowPathCodeX86 { public: @@ -420,12 +420,22 @@ size_t CodeGeneratorX86::RestoreFloatingPointRegister(size_t stack_index, uint32 return GetFloatingPointSpillSlotSize(); } -void CodeGeneratorX86::InvokeRuntime(Address entry_point, +void CodeGeneratorX86::InvokeRuntime(QuickEntrypointEnum entrypoint, + HInstruction* instruction, + uint32_t dex_pc, + SlowPathCode* slow_path) { + InvokeRuntime(GetThreadOffset<kX86WordSize>(entrypoint).Int32Value(), + instruction, + dex_pc, + slow_path); +} + +void CodeGeneratorX86::InvokeRuntime(int32_t entry_point_offset, HInstruction* instruction, uint32_t dex_pc, SlowPathCode* slow_path) { ValidateInvokeRuntime(instruction, slow_path); - __ fs()->call(entry_point); + __ fs()->call(Address::Absolute(entry_point_offset)); RecordPcInfo(instruction, dex_pc, slow_path); } @@ -889,6 +899,11 @@ void CodeGeneratorX86::Move(HInstruction* instruction, Location location, HInstr } } +void CodeGeneratorX86::MoveConstant(Location location, int32_t value) { + DCHECK(location.IsRegister()); + __ movl(location.AsRegister<Register>(), Immediate(value)); +} + void InstructionCodeGeneratorX86::HandleGoto(HInstruction* got, HBasicBlock* successor) { DCHECK(!successor->IsExitBlock()); @@ -1505,6 +1520,17 @@ void InstructionCodeGeneratorX86::VisitReturn(HReturn* ret) { codegen_->GenerateFrameExit(); } +void LocationsBuilderX86::VisitInvokeUnresolved(HInvokeUnresolved* invoke) { + // The trampoline uses the same calling convention as dex calling conventions, + // except instead of loading arg0/r0 with the target Method*, arg0/r0 will contain + // the method_idx. + HandleInvoke(invoke); +} + +void InstructionCodeGeneratorX86::VisitInvokeUnresolved(HInvokeUnresolved* invoke) { + codegen_->GenerateInvokeUnresolvedRuntimeCall(invoke); +} + void LocationsBuilderX86::VisitInvokeStaticOrDirect(HInvokeStaticOrDirect* invoke) { // When we do not run baseline, explicit clinit checks triggered by static // invokes must have been pruned by art::PrepareForRegisterAllocation. @@ -3360,11 +3386,10 @@ void InstructionCodeGeneratorX86::VisitNewInstance(HNewInstance* instruction) { __ movl(calling_convention.GetRegisterAt(0), Immediate(instruction->GetTypeIndex())); // Note: if heap poisoning is enabled, the entry point takes cares // of poisoning the reference. - codegen_->InvokeRuntime( - Address::Absolute(GetThreadOffset<kX86WordSize>(instruction->GetEntrypoint())), - instruction, - instruction->GetDexPc(), - nullptr); + codegen_->InvokeRuntime(instruction->GetEntrypoint(), + instruction, + instruction->GetDexPc(), + nullptr); DCHECK(!codegen_->IsLeafMethod()); } @@ -3384,11 +3409,10 @@ void InstructionCodeGeneratorX86::VisitNewArray(HNewArray* instruction) { // Note: if heap poisoning is enabled, the entry point takes cares // of poisoning the reference. - codegen_->InvokeRuntime( - Address::Absolute(GetThreadOffset<kX86WordSize>(instruction->GetEntrypoint())), - instruction, - instruction->GetDexPc(), - nullptr); + codegen_->InvokeRuntime(instruction->GetEntrypoint(), + instruction, + instruction->GetDexPc(), + nullptr); DCHECK(!codegen_->IsLeafMethod()); } diff --git a/compiler/optimizing/code_generator_x86.h b/compiler/optimizing/code_generator_x86.h index c63634dbeb..f3307cf96c 100644 --- a/compiler/optimizing/code_generator_x86.h +++ b/compiler/optimizing/code_generator_x86.h @@ -228,13 +228,19 @@ class CodeGeneratorX86 : public CodeGenerator { void GenerateFrameExit() OVERRIDE; void Bind(HBasicBlock* block) OVERRIDE; void Move(HInstruction* instruction, Location location, HInstruction* move_for) OVERRIDE; + void MoveConstant(Location destination, int32_t value) OVERRIDE; size_t SaveCoreRegister(size_t stack_index, uint32_t reg_id) OVERRIDE; size_t RestoreCoreRegister(size_t stack_index, uint32_t reg_id) OVERRIDE; size_t SaveFloatingPointRegister(size_t stack_index, uint32_t reg_id) OVERRIDE; size_t RestoreFloatingPointRegister(size_t stack_index, uint32_t reg_id) OVERRIDE; // Generate code to invoke a runtime entry point. - void InvokeRuntime(Address entry_point, + void InvokeRuntime(QuickEntrypointEnum entrypoint, + HInstruction* instruction, + uint32_t dex_pc, + SlowPathCode* slow_path) OVERRIDE; + + void InvokeRuntime(int32_t entry_point_offset, HInstruction* instruction, uint32_t dex_pc, SlowPathCode* slow_path); diff --git a/compiler/optimizing/code_generator_x86_64.cc b/compiler/optimizing/code_generator_x86_64.cc index 82c037a07b..134bfedb15 100644 --- a/compiler/optimizing/code_generator_x86_64.cc +++ b/compiler/optimizing/code_generator_x86_64.cc @@ -48,7 +48,7 @@ static constexpr FloatRegister kFpuCalleeSaves[] = { XMM12, XMM13, XMM14, XMM15 static constexpr int kC2ConditionMask = 0x400; #define __ down_cast<X86_64Assembler*>(codegen->GetAssembler())-> -#define QUICK_ENTRY_POINT(x) Address::Absolute(QUICK_ENTRYPOINT_OFFSET(kX86_64WordSize, x), true) +#define QUICK_ENTRY_POINT(x) QUICK_ENTRYPOINT_OFFSET(kX86_64WordSize, x).Int32Value() class NullCheckSlowPathX86_64 : public SlowPathCodeX86_64 { public: @@ -566,12 +566,22 @@ size_t CodeGeneratorX86_64::RestoreFloatingPointRegister(size_t stack_index, uin return kX86_64WordSize; } -void CodeGeneratorX86_64::InvokeRuntime(Address entry_point, +void CodeGeneratorX86_64::InvokeRuntime(QuickEntrypointEnum entrypoint, + HInstruction* instruction, + uint32_t dex_pc, + SlowPathCode* slow_path) { + InvokeRuntime(GetThreadOffset<kX86_64WordSize>(entrypoint).Int32Value(), + instruction, + dex_pc, + slow_path); +} + +void CodeGeneratorX86_64::InvokeRuntime(int32_t entry_point_offset, HInstruction* instruction, uint32_t dex_pc, SlowPathCode* slow_path) { ValidateInvokeRuntime(instruction, slow_path); - __ gs()->call(entry_point); + __ gs()->call(Address::Absolute(entry_point_offset, true)); RecordPcInfo(instruction, dex_pc, slow_path); } @@ -913,6 +923,11 @@ void CodeGeneratorX86_64::Move(HInstruction* instruction, } } +void CodeGeneratorX86_64::MoveConstant(Location location, int32_t value) { + DCHECK(location.IsRegister()); + Load64BitValue(location.AsRegister<CpuRegister>(), static_cast<int64_t>(value)); +} + void InstructionCodeGeneratorX86_64::HandleGoto(HInstruction* got, HBasicBlock* successor) { DCHECK(!successor->IsExitBlock()); @@ -1686,6 +1701,17 @@ Location InvokeDexCallingConventionVisitorX86_64::GetNextLocation(Primitive::Typ return Location(); } +void LocationsBuilderX86_64::VisitInvokeUnresolved(HInvokeUnresolved* invoke) { + // The trampoline uses the same calling convention as dex calling conventions, + // except instead of loading arg0/r0 with the target Method*, arg0/r0 will contain + // the method_idx. + HandleInvoke(invoke); +} + +void InstructionCodeGeneratorX86_64::VisitInvokeUnresolved(HInvokeUnresolved* invoke) { + codegen_->GenerateInvokeUnresolvedRuntimeCall(invoke); +} + void LocationsBuilderX86_64::VisitInvokeStaticOrDirect(HInvokeStaticOrDirect* invoke) { // When we do not run baseline, explicit clinit checks triggered by static // invokes must have been pruned by art::PrepareForRegisterAllocation. @@ -3382,11 +3408,10 @@ void InstructionCodeGeneratorX86_64::VisitNewInstance(HNewInstance* instruction) // Note: if heap poisoning is enabled, the entry point takes cares // of poisoning the reference. - codegen_->InvokeRuntime( - Address::Absolute(GetThreadOffset<kX86_64WordSize>(instruction->GetEntrypoint()), true), - instruction, - instruction->GetDexPc(), - nullptr); + codegen_->InvokeRuntime(instruction->GetEntrypoint(), + instruction, + instruction->GetDexPc(), + nullptr); DCHECK(!codegen_->IsLeafMethod()); } @@ -3408,11 +3433,10 @@ void InstructionCodeGeneratorX86_64::VisitNewArray(HNewArray* instruction) { // Note: if heap poisoning is enabled, the entry point takes cares // of poisoning the reference. - codegen_->InvokeRuntime( - Address::Absolute(GetThreadOffset<kX86_64WordSize>(instruction->GetEntrypoint()), true), - instruction, - instruction->GetDexPc(), - nullptr); + codegen_->InvokeRuntime(instruction->GetEntrypoint(), + instruction, + instruction->GetDexPc(), + nullptr); DCHECK(!codegen_->IsLeafMethod()); } diff --git a/compiler/optimizing/code_generator_x86_64.h b/compiler/optimizing/code_generator_x86_64.h index 522f03649d..9b2423f8be 100644 --- a/compiler/optimizing/code_generator_x86_64.h +++ b/compiler/optimizing/code_generator_x86_64.h @@ -228,13 +228,19 @@ class CodeGeneratorX86_64 : public CodeGenerator { void GenerateFrameExit() OVERRIDE; void Bind(HBasicBlock* block) OVERRIDE; void Move(HInstruction* instruction, Location location, HInstruction* move_for) OVERRIDE; + void MoveConstant(Location destination, int32_t value) OVERRIDE; size_t SaveCoreRegister(size_t stack_index, uint32_t reg_id) OVERRIDE; size_t RestoreCoreRegister(size_t stack_index, uint32_t reg_id) OVERRIDE; size_t SaveFloatingPointRegister(size_t stack_index, uint32_t reg_id) OVERRIDE; size_t RestoreFloatingPointRegister(size_t stack_index, uint32_t reg_id) OVERRIDE; // Generate code to invoke a runtime entry point. - void InvokeRuntime(Address entry_point, + void InvokeRuntime(QuickEntrypointEnum entrypoint, + HInstruction* instruction, + uint32_t dex_pc, + SlowPathCode* slow_path) OVERRIDE; + + void InvokeRuntime(int32_t entry_point_offset, HInstruction* instruction, uint32_t dex_pc, SlowPathCode* slow_path); diff --git a/compiler/optimizing/graph_visualizer.cc b/compiler/optimizing/graph_visualizer.cc index 60a5955801..d05c514912 100644 --- a/compiler/optimizing/graph_visualizer.cc +++ b/compiler/optimizing/graph_visualizer.cc @@ -380,6 +380,11 @@ class HGraphVisualizerPrinter : public HGraphDelegateVisitor { invoke->GetDexMethodIndex(), GetGraph()->GetDexFile(), /* with_signature */ false); } + void VisitInvokeUnresolved(HInvokeUnresolved* invoke) OVERRIDE { + VisitInvoke(invoke); + StartAttributeStream("invoke_type") << invoke->GetOriginalInvokeType(); + } + void VisitInvokeStaticOrDirect(HInvokeStaticOrDirect* invoke) OVERRIDE { VisitInvoke(invoke); StartAttributeStream("recursive") << std::boolalpha diff --git a/compiler/optimizing/inliner.cc b/compiler/optimizing/inliner.cc index 12fd1c37d7..039029aa52 100644 --- a/compiler/optimizing/inliner.cc +++ b/compiler/optimizing/inliner.cc @@ -173,6 +173,10 @@ static uint32_t FindMethodIndexIn(ArtMethod* method, } bool HInliner::TryInline(HInvoke* invoke_instruction) { + if (invoke_instruction->IsInvokeUnresolved()) { + return false; // Don't bother to move further if we know the method is unresolved. + } + uint32_t method_index = invoke_instruction->GetDexMethodIndex(); ScopedObjectAccess soa(Thread::Current()); const DexFile& caller_dex_file = *caller_compilation_unit_.GetDexFile(); @@ -194,6 +198,7 @@ bool HInliner::TryInline(HInvoke* invoke_instruction) { } if (resolved_method == nullptr) { + // TODO: Can this still happen? // Method cannot be resolved if it is in another dex file we do not have access to. VLOG(compiler) << "Method cannot be resolved " << PrettyMethod(method_index, caller_dex_file); return false; diff --git a/compiler/optimizing/nodes.h b/compiler/optimizing/nodes.h index 70002addea..90ff20cf4c 100644 --- a/compiler/optimizing/nodes.h +++ b/compiler/optimizing/nodes.h @@ -1033,6 +1033,7 @@ class HLoopInformationOutwardIterator : public ValueObject { M(InstanceFieldSet, Instruction) \ M(InstanceOf, Instruction) \ M(IntConstant, Constant) \ + M(InvokeUnresolved, Invoke) \ M(InvokeInterface, Invoke) \ M(InvokeStaticOrDirect, Invoke) \ M(InvokeVirtual, Invoke) \ @@ -3057,6 +3058,29 @@ class HInvoke : public HInstruction { DISALLOW_COPY_AND_ASSIGN(HInvoke); }; +class HInvokeUnresolved : public HInvoke { + public: + HInvokeUnresolved(ArenaAllocator* arena, + uint32_t number_of_arguments, + Primitive::Type return_type, + uint32_t dex_pc, + uint32_t dex_method_index, + InvokeType invoke_type) + : HInvoke(arena, + number_of_arguments, + 0u /* number_of_other_inputs */, + return_type, + dex_pc, + dex_method_index, + invoke_type) { + } + + DECLARE_INSTRUCTION(InvokeUnresolved); + + private: + DISALLOW_COPY_AND_ASSIGN(HInvokeUnresolved); +}; + class HInvokeStaticOrDirect : public HInvoke { public: // Requirements of this method call regarding the class diff --git a/compiler/optimizing/optimizing_compiler.cc b/compiler/optimizing/optimizing_compiler.cc index 092e3c2876..a2b613194f 100644 --- a/compiler/optimizing/optimizing_compiler.cc +++ b/compiler/optimizing/optimizing_compiler.cc @@ -66,6 +66,7 @@ #include "ssa_phi_elimination.h" #include "ssa_liveness_analysis.h" #include "utils/assembler.h" +#include "verifier/method_verifier.h" namespace art { @@ -835,6 +836,11 @@ CompiledMethod* OptimizingCompiler::TryCompile(const DexFile::CodeItem* code_ite return compiled_method; } +static bool HasOnlyUnresolvedFailures(const VerifiedMethod* verified_method) { + uint32_t unresolved_mask = verifier::VerifyError::VERIFY_ERROR_NO_CLASS; + return (verified_method->GetEncounteredVerificationFailures() & (~unresolved_mask)) == 0; +} + CompiledMethod* OptimizingCompiler::Compile(const DexFile::CodeItem* code_item, uint32_t access_flags, InvokeType invoke_type, @@ -845,8 +851,10 @@ CompiledMethod* OptimizingCompiler::Compile(const DexFile::CodeItem* code_item, Handle<mirror::DexCache> dex_cache) const { CompilerDriver* compiler_driver = GetCompilerDriver(); CompiledMethod* method = nullptr; - DCHECK(!compiler_driver->GetVerifiedMethod(&dex_file, method_idx)->HasRuntimeThrow()); - if (compiler_driver->IsMethodVerifiedWithoutFailures(method_idx, class_def_idx, dex_file)) { + const VerifiedMethod* verified_method = compiler_driver->GetVerifiedMethod(&dex_file, method_idx); + DCHECK(!verified_method->HasRuntimeThrow()); + if (compiler_driver->IsMethodVerifiedWithoutFailures(method_idx, class_def_idx, dex_file) + || HasOnlyUnresolvedFailures(verified_method)) { method = TryCompile(code_item, access_flags, invoke_type, class_def_idx, method_idx, jclass_loader, dex_file, dex_cache); } else { diff --git a/compiler/optimizing/optimizing_compiler_stats.h b/compiler/optimizing/optimizing_compiler_stats.h index da5cb578b8..c7701b70ad 100644 --- a/compiler/optimizing/optimizing_compiler_stats.h +++ b/compiler/optimizing/optimizing_compiler_stats.h @@ -33,6 +33,7 @@ enum MethodCompilationStat { kInlinedInvoke, kInstructionSimplifications, kInstructionSimplificationsArch, + kUnresolvedMethod, kNotCompiledBranchOutsideMethodCode, kNotCompiledCannotBuildSSA, kNotCompiledCantAccesType, @@ -45,7 +46,6 @@ enum MethodCompilationStat { kNotCompiledSpaceFilter, kNotCompiledUnhandledInstruction, kNotCompiledUnresolvedField, - kNotCompiledUnresolvedMethod, kNotCompiledUnsupportedIsa, kNotCompiledVerifyAtRuntime, kNotOptimizedDisabled, @@ -103,6 +103,7 @@ class OptimizingCompilerStats { case kInlinedInvoke : return "kInlinedInvoke"; case kInstructionSimplifications: return "kInstructionSimplifications"; case kInstructionSimplificationsArch: return "kInstructionSimplificationsArch"; + case kUnresolvedMethod : return "kUnresolvedMethod"; case kNotCompiledBranchOutsideMethodCode: return "kNotCompiledBranchOutsideMethodCode"; case kNotCompiledCannotBuildSSA : return "kNotCompiledCannotBuildSSA"; case kNotCompiledCantAccesType : return "kNotCompiledCantAccesType"; @@ -115,7 +116,6 @@ class OptimizingCompilerStats { case kNotCompiledSpaceFilter : return "kNotCompiledSpaceFilter"; case kNotCompiledUnhandledInstruction : return "kNotCompiledUnhandledInstruction"; case kNotCompiledUnresolvedField : return "kNotCompiledUnresolvedField"; - case kNotCompiledUnresolvedMethod : return "kNotCompiledUnresolvedMethod"; case kNotCompiledUnsupportedIsa : return "kNotCompiledUnsupportedIsa"; case kNotCompiledVerifyAtRuntime : return "kNotCompiledVerifyAtRuntime"; case kNotOptimizedDisabled : return "kNotOptimizedDisabled"; |