Support unresolved methods in Optimizing
Change-Id: If2da02b50d2fa668cd58f134a005f1752e7746b1
diff --git a/compiler/optimizing/builder.cc b/compiler/optimizing/builder.cc
index a2a0696..3663448 100644
--- a/compiler/optimizing/builder.cc
+++ b/compiler/optimizing/builder.cc
@@ -839,11 +839,20 @@
&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 50108a7..3c6a41d 100644
--- a/compiler/optimizing/code_generator.cc
+++ b/compiler/optimizing/code_generator.cc
@@ -388,6 +388,31 @@
}
}
+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 d2af56a..a54dbf1 100644
--- a/compiler/optimizing/code_generator.h
+++ b/compiler/optimizing/code_generator.h
@@ -169,6 +169,7 @@
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 @@
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 c3d63b9..6f89293 100644
--- a/compiler/optimizing/code_generator_arm.cc
+++ b/compiler/optimizing/code_generator_arm.cc
@@ -710,6 +710,7 @@
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::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 @@
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 @@
__ 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 @@
__ 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 e44209d..91cfd00 100644
--- a/compiler/optimizing/code_generator_arm.h
+++ b/compiler/optimizing/code_generator_arm.h
@@ -239,6 +239,7 @@
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 @@
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 377eaf6..531b669 100644
--- a/compiler/optimizing/code_generator_arm64.cc
+++ b/compiler/optimizing/code_generator_arm64.cc
@@ -716,6 +716,11 @@
}
}
+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::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 @@
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 @@
__ 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 @@
__ 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 3211a83..576406e 100644
--- a/compiler/optimizing/code_generator_arm64.h
+++ b/compiler/optimizing/code_generator_arm64.h
@@ -338,6 +338,7 @@
// 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 @@
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 0787e49..bf0d2e2 100644
--- a/compiler/optimizing/code_generator_mips64.cc
+++ b/compiler/optimizing/code_generator_mips64.cc
@@ -856,6 +856,11 @@
}
}
+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 @@
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 @@
// 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 @@
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 @@
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 c754838..8511eb6 100644
--- a/compiler/optimizing/code_generator_mips64.h
+++ b/compiler/optimizing/code_generator_mips64.h
@@ -283,9 +283,16 @@
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 c7ddabb..9c5ecc3 100644
--- a/compiler/optimizing/code_generator_x86.cc
+++ b/compiler/optimizing/code_generator_x86.cc
@@ -47,7 +47,7 @@
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 @@
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::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 @@
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 @@
__ 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 @@
// 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 c63634d..f3307cf 100644
--- a/compiler/optimizing/code_generator_x86.h
+++ b/compiler/optimizing/code_generator_x86.h
@@ -228,13 +228,19 @@
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 82c037a..134bfed 100644
--- a/compiler/optimizing/code_generator_x86_64.cc
+++ b/compiler/optimizing/code_generator_x86_64.cc
@@ -48,7 +48,7 @@
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 @@
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::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 @@
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 @@
// 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 @@
// 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 522f036..9b2423f 100644
--- a/compiler/optimizing/code_generator_x86_64.h
+++ b/compiler/optimizing/code_generator_x86_64.h
@@ -228,13 +228,19 @@
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 60a5955..d05c514 100644
--- a/compiler/optimizing/graph_visualizer.cc
+++ b/compiler/optimizing/graph_visualizer.cc
@@ -380,6 +380,11 @@
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 12fd1c3..039029a 100644
--- a/compiler/optimizing/inliner.cc
+++ b/compiler/optimizing/inliner.cc
@@ -173,6 +173,10 @@
}
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 @@
}
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 70002ad..90ff20c 100644
--- a/compiler/optimizing/nodes.h
+++ b/compiler/optimizing/nodes.h
@@ -1033,6 +1033,7 @@
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 @@
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 092e3c2..a2b6131 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 @@
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 @@
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 da5cb57..c7701b7 100644
--- a/compiler/optimizing/optimizing_compiler_stats.h
+++ b/compiler/optimizing/optimizing_compiler_stats.h
@@ -33,6 +33,7 @@
kInlinedInvoke,
kInstructionSimplifications,
kInstructionSimplificationsArch,
+ kUnresolvedMethod,
kNotCompiledBranchOutsideMethodCode,
kNotCompiledCannotBuildSSA,
kNotCompiledCantAccesType,
@@ -45,7 +46,6 @@
kNotCompiledSpaceFilter,
kNotCompiledUnhandledInstruction,
kNotCompiledUnresolvedField,
- kNotCompiledUnresolvedMethod,
kNotCompiledUnsupportedIsa,
kNotCompiledVerifyAtRuntime,
kNotOptimizedDisabled,
@@ -103,6 +103,7 @@
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 @@
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";