ART: Compiler support for const-method-handle
Implemented as a runtime call.
Bug: 66890674
Test: art/test.py --target -r -t 979
Test: art/test.py --target --64 -r -t 979
Test: art/test.py --host -r -t 979
Change-Id: I67f461c819a7d528d7455afda8b4a59e9aed381c
diff --git a/compiler/optimizing/code_generator.cc b/compiler/optimizing/code_generator.cc
index 1e44311..f573337 100644
--- a/compiler/optimizing/code_generator.cc
+++ b/compiler/optimizing/code_generator.cc
@@ -736,6 +736,26 @@
}
}
+void CodeGenerator::CreateLoadMethodHandleRuntimeCallLocationSummary(
+ HLoadMethodHandle* method_handle,
+ Location runtime_proto_index_location,
+ Location runtime_return_location) {
+ DCHECK_EQ(method_handle->InputCount(), 1u);
+ LocationSummary* locations =
+ new (method_handle->GetBlock()->GetGraph()->GetAllocator()) LocationSummary(
+ method_handle, LocationSummary::kCallOnMainOnly);
+ locations->SetInAt(0, Location::NoLocation());
+ locations->AddTemp(runtime_proto_index_location);
+ locations->SetOut(runtime_return_location);
+}
+
+void CodeGenerator::GenerateLoadMethodHandleRuntimeCall(HLoadMethodHandle* method_handle) {
+ LocationSummary* locations = method_handle->GetLocations();
+ MoveConstant(locations->GetTemp(0), method_handle->GetMethodHandleIndex());
+ CheckEntrypointTypes<kQuickResolveMethodHandle, void*, uint32_t>();
+ InvokeRuntime(kQuickResolveMethodHandle, method_handle, method_handle->GetDexPc());
+}
+
void CodeGenerator::CreateLoadMethodTypeRuntimeCallLocationSummary(
HLoadMethodType* method_type,
Location runtime_proto_index_location,
diff --git a/compiler/optimizing/code_generator.h b/compiler/optimizing/code_generator.h
index 7e84a44..bcb2599 100644
--- a/compiler/optimizing/code_generator.h
+++ b/compiler/optimizing/code_generator.h
@@ -564,6 +564,11 @@
Location runtime_return_location);
void GenerateLoadClassRuntimeCall(HLoadClass* cls);
+ static void CreateLoadMethodHandleRuntimeCallLocationSummary(HLoadMethodHandle* method_handle,
+ Location runtime_handle_index_location,
+ Location runtime_return_location);
+ void GenerateLoadMethodHandleRuntimeCall(HLoadMethodHandle* method_handle);
+
static void CreateLoadMethodTypeRuntimeCallLocationSummary(HLoadMethodType* method_type,
Location runtime_type_index_location,
Location runtime_return_location);
diff --git a/compiler/optimizing/code_generator_arm64.cc b/compiler/optimizing/code_generator_arm64.cc
index 0601d2d..6f173e1 100644
--- a/compiler/optimizing/code_generator_arm64.cc
+++ b/compiler/optimizing/code_generator_arm64.cc
@@ -5144,6 +5144,16 @@
}
}
+void LocationsBuilderARM64::VisitLoadMethodHandle(HLoadMethodHandle* load) {
+ InvokeRuntimeCallingConvention calling_convention;
+ Location location = LocationFrom(calling_convention.GetRegisterAt(0));
+ CodeGenerator::CreateLoadMethodHandleRuntimeCallLocationSummary(load, location, location);
+}
+
+void InstructionCodeGeneratorARM64::VisitLoadMethodHandle(HLoadMethodHandle* load) {
+ codegen_->GenerateLoadMethodHandleRuntimeCall(load);
+}
+
void LocationsBuilderARM64::VisitLoadMethodType(HLoadMethodType* load) {
InvokeRuntimeCallingConvention calling_convention;
Location location = LocationFrom(calling_convention.GetRegisterAt(0));
diff --git a/compiler/optimizing/code_generator_arm_vixl.cc b/compiler/optimizing/code_generator_arm_vixl.cc
index 33304c6..859e159 100644
--- a/compiler/optimizing/code_generator_arm_vixl.cc
+++ b/compiler/optimizing/code_generator_arm_vixl.cc
@@ -7527,6 +7527,16 @@
}
}
+void LocationsBuilderARMVIXL::VisitLoadMethodHandle(HLoadMethodHandle* load) {
+ InvokeRuntimeCallingConventionARMVIXL calling_convention;
+ Location location = LocationFrom(calling_convention.GetRegisterAt(0));
+ CodeGenerator::CreateLoadMethodHandleRuntimeCallLocationSummary(load, location, location);
+}
+
+void InstructionCodeGeneratorARMVIXL::VisitLoadMethodHandle(HLoadMethodHandle* load) {
+ codegen_->GenerateLoadMethodHandleRuntimeCall(load);
+}
+
void LocationsBuilderARMVIXL::VisitLoadMethodType(HLoadMethodType* load) {
InvokeRuntimeCallingConventionARMVIXL calling_convention;
Location location = LocationFrom(calling_convention.GetRegisterAt(0));
diff --git a/compiler/optimizing/code_generator_mips.cc b/compiler/optimizing/code_generator_mips.cc
index 3a3fcff..7f3441f 100644
--- a/compiler/optimizing/code_generator_mips.cc
+++ b/compiler/optimizing/code_generator_mips.cc
@@ -8226,6 +8226,16 @@
}
}
+void LocationsBuilderMIPS::VisitLoadMethodHandle(HLoadMethodHandle* load) {
+ InvokeRuntimeCallingConvention calling_convention;
+ Location loc = Location::RegisterLocation(calling_convention.GetRegisterAt(0));
+ CodeGenerator::CreateLoadMethodHandleRuntimeCallLocationSummary(load, loc, loc);
+}
+
+void InstructionCodeGeneratorMIPS::VisitLoadMethodHandle(HLoadMethodHandle* load) {
+ codegen_->GenerateLoadMethodHandleRuntimeCall(load);
+}
+
void LocationsBuilderMIPS::VisitLoadMethodType(HLoadMethodType* load) {
InvokeRuntimeCallingConvention calling_convention;
Location loc = Location::RegisterLocation(calling_convention.GetRegisterAt(0));
diff --git a/compiler/optimizing/code_generator_mips64.cc b/compiler/optimizing/code_generator_mips64.cc
index d6fc9a1..ee32b96 100644
--- a/compiler/optimizing/code_generator_mips64.cc
+++ b/compiler/optimizing/code_generator_mips64.cc
@@ -6262,6 +6262,16 @@
}
}
+void LocationsBuilderMIPS64::VisitLoadMethodHandle(HLoadMethodHandle* load) {
+ InvokeRuntimeCallingConvention calling_convention;
+ Location loc = Location::RegisterLocation(calling_convention.GetRegisterAt(0));
+ CodeGenerator::CreateLoadMethodHandleRuntimeCallLocationSummary(load, loc, loc);
+}
+
+void InstructionCodeGeneratorMIPS64::VisitLoadMethodHandle(HLoadMethodHandle* load) {
+ codegen_->GenerateLoadMethodHandleRuntimeCall(load);
+}
+
void LocationsBuilderMIPS64::VisitLoadMethodType(HLoadMethodType* load) {
InvokeRuntimeCallingConvention calling_convention;
Location loc = Location::RegisterLocation(calling_convention.GetRegisterAt(0));
diff --git a/compiler/optimizing/code_generator_x86.cc b/compiler/optimizing/code_generator_x86.cc
index d18a750..9e31538 100644
--- a/compiler/optimizing/code_generator_x86.cc
+++ b/compiler/optimizing/code_generator_x86.cc
@@ -6539,6 +6539,16 @@
}
}
+void LocationsBuilderX86::VisitLoadMethodHandle(HLoadMethodHandle* load) {
+ InvokeRuntimeCallingConvention calling_convention;
+ Location location = Location::RegisterLocation(calling_convention.GetRegisterAt(0));
+ CodeGenerator::CreateLoadMethodHandleRuntimeCallLocationSummary(load, location, location);
+}
+
+void InstructionCodeGeneratorX86::VisitLoadMethodHandle(HLoadMethodHandle* load) {
+ codegen_->GenerateLoadMethodHandleRuntimeCall(load);
+}
+
void LocationsBuilderX86::VisitLoadMethodType(HLoadMethodType* load) {
InvokeRuntimeCallingConvention calling_convention;
Location location = Location::RegisterLocation(calling_convention.GetRegisterAt(0));
diff --git a/compiler/optimizing/code_generator_x86_64.cc b/compiler/optimizing/code_generator_x86_64.cc
index 450c857..f739704 100644
--- a/compiler/optimizing/code_generator_x86_64.cc
+++ b/compiler/optimizing/code_generator_x86_64.cc
@@ -5908,6 +5908,16 @@
}
}
+void LocationsBuilderX86_64::VisitLoadMethodHandle(HLoadMethodHandle* load) {
+ // Custom calling convention: RAX serves as both input and output.
+ Location location = Location::RegisterLocation(RAX);
+ CodeGenerator::CreateLoadMethodHandleRuntimeCallLocationSummary(load, location, location);
+}
+
+void InstructionCodeGeneratorX86_64::VisitLoadMethodHandle(HLoadMethodHandle* load) {
+ codegen_->GenerateLoadMethodHandleRuntimeCall(load);
+}
+
void LocationsBuilderX86_64::VisitLoadMethodType(HLoadMethodType* load) {
// Custom calling convention: RAX serves as both input and output.
Location location = Location::RegisterLocation(RAX);
diff --git a/compiler/optimizing/graph_visualizer.cc b/compiler/optimizing/graph_visualizer.cc
index 87ce1f0..d65ad40 100644
--- a/compiler/optimizing/graph_visualizer.cc
+++ b/compiler/optimizing/graph_visualizer.cc
@@ -386,6 +386,11 @@
<< load_class->NeedsAccessCheck() << std::noboolalpha;
}
+ void VisitLoadMethodHandle(HLoadMethodHandle* load_method_handle) OVERRIDE {
+ StartAttributeStream("load_kind") << "RuntimeCall";
+ StartAttributeStream("method_handle_index") << load_method_handle->GetMethodHandleIndex();
+ }
+
void VisitLoadMethodType(HLoadMethodType* load_method_type) OVERRIDE {
StartAttributeStream("load_kind") << "RuntimeCall";
const DexFile& dex_file = load_method_type->GetDexFile();
diff --git a/compiler/optimizing/instruction_builder.cc b/compiler/optimizing/instruction_builder.cc
index 61730a8..35a3945 100644
--- a/compiler/optimizing/instruction_builder.cc
+++ b/compiler/optimizing/instruction_builder.cc
@@ -1896,6 +1896,13 @@
}
}
+void HInstructionBuilder::BuildLoadMethodHandle(uint16_t proto_idx, uint32_t dex_pc) {
+ const DexFile& dex_file = *dex_compilation_unit_->GetDexFile();
+ HLoadMethodHandle* load_method_handle =
+ new (allocator_) HLoadMethodHandle(graph_->GetCurrentMethod(), proto_idx, dex_file, dex_pc);
+ AppendInstruction(load_method_handle);
+}
+
void HInstructionBuilder::BuildLoadMethodType(uint16_t proto_idx, uint32_t dex_pc) {
const DexFile& dex_file = *dex_compilation_unit_->GetDexFile();
HLoadMethodType* load_method_type =
@@ -2934,6 +2941,13 @@
break;
}
+ case Instruction::CONST_METHOD_HANDLE: {
+ uint16_t method_handle_idx = instruction.VRegB_21c();
+ BuildLoadMethodHandle(method_handle_idx, dex_pc);
+ UpdateLocal(instruction.VRegA_21c(), current_block_->GetLastInstruction());
+ break;
+ }
+
case Instruction::CONST_METHOD_TYPE: {
uint16_t proto_idx = instruction.VRegB_21c();
BuildLoadMethodType(proto_idx, dex_pc);
diff --git a/compiler/optimizing/instruction_builder.h b/compiler/optimizing/instruction_builder.h
index 3fde54c..95ffa6b 100644
--- a/compiler/optimizing/instruction_builder.h
+++ b/compiler/optimizing/instruction_builder.h
@@ -240,7 +240,10 @@
bool LoadClassNeedsAccessCheck(Handle<mirror::Class> klass)
REQUIRES_SHARED(Locks::mutator_lock_);
- // Builds a `HLoadMethodType` loading the given `proto_index`.
+ // Builds a `HLoadMethodHandle` loading the given `method_handle_idx`.
+ void BuildLoadMethodHandle(uint16_t method_handle_idx, uint32_t dex_pc);
+
+ // Builds a `HLoadMethodType` loading the given `proto_idx`.
void BuildLoadMethodType(uint16_t proto_idx, uint32_t dex_pc);
// Returns the outer-most compiling method's class.
diff --git a/compiler/optimizing/nodes.h b/compiler/optimizing/nodes.h
index 54882ff..a7c2d0b 100644
--- a/compiler/optimizing/nodes.h
+++ b/compiler/optimizing/nodes.h
@@ -1383,6 +1383,7 @@
M(LessThanOrEqual, Condition) \
M(LoadClass, Instruction) \
M(LoadException, Instruction) \
+ M(LoadMethodHandle, Instruction) \
M(LoadMethodType, Instruction) \
M(LoadString, Instruction) \
M(LongConstant, Constant) \
@@ -6500,6 +6501,50 @@
special_input->AddUseAt(this, 0);
}
+class HLoadMethodHandle FINAL : public HInstruction {
+ public:
+ HLoadMethodHandle(HCurrentMethod* current_method,
+ uint16_t method_handle_idx,
+ const DexFile& dex_file,
+ uint32_t dex_pc)
+ : HInstruction(kLoadMethodHandle,
+ DataType::Type::kReference,
+ SideEffectsForArchRuntimeCalls(),
+ dex_pc),
+ special_input_(HUserRecord<HInstruction*>(current_method)),
+ method_handle_idx_(method_handle_idx),
+ dex_file_(dex_file) {
+ }
+
+ using HInstruction::GetInputRecords; // Keep the const version visible.
+ ArrayRef<HUserRecord<HInstruction*>> GetInputRecords() OVERRIDE FINAL {
+ return ArrayRef<HUserRecord<HInstruction*>>(
+ &special_input_, (special_input_.GetInstruction() != nullptr) ? 1u : 0u);
+ }
+
+ bool IsClonable() const OVERRIDE { return true; }
+
+ uint16_t GetMethodHandleIndex() const { return method_handle_idx_; }
+
+ const DexFile& GetDexFile() const { return dex_file_; }
+
+ static SideEffects SideEffectsForArchRuntimeCalls() {
+ return SideEffects::CanTriggerGC();
+ }
+
+ DECLARE_INSTRUCTION(LoadMethodHandle);
+
+ protected:
+ DEFAULT_COPY_CONSTRUCTOR(LoadMethodHandle);
+
+ private:
+ // The special input is the HCurrentMethod for kRuntimeCall.
+ HUserRecord<HInstruction*> special_input_;
+
+ const uint16_t method_handle_idx_;
+ const DexFile& dex_file_;
+};
+
class HLoadMethodType FINAL : public HInstruction {
public:
HLoadMethodType(HCurrentMethod* current_method,
@@ -6540,7 +6585,7 @@
// The special input is the HCurrentMethod for kRuntimeCall.
HUserRecord<HInstruction*> special_input_;
- uint16_t proto_idx_;
+ const uint16_t proto_idx_;
const DexFile& dex_file_;
};
diff --git a/compiler/optimizing/reference_type_propagation.cc b/compiler/optimizing/reference_type_propagation.cc
index b15a0ea..ecfa790 100644
--- a/compiler/optimizing/reference_type_propagation.cc
+++ b/compiler/optimizing/reference_type_propagation.cc
@@ -59,6 +59,12 @@
return GetRootHandle(handles_, ClassLinker::kJavaLangClass, &class_class_handle_);
}
+ReferenceTypeInfo::TypeHandle ReferenceTypePropagation::HandleCache::GetMethodHandleClassHandle() {
+ return GetRootHandle(handles_,
+ ClassLinker::kJavaLangInvokeMethodHandleImpl,
+ &method_handle_class_handle_);
+}
+
ReferenceTypeInfo::TypeHandle ReferenceTypePropagation::HandleCache::GetMethodTypeClassHandle() {
return GetRootHandle(handles_,
ClassLinker::kJavaLangInvokeMethodType,
@@ -95,6 +101,7 @@
void VisitLoadClass(HLoadClass* load_class) OVERRIDE;
void VisitInstanceOf(HInstanceOf* load_class) OVERRIDE;
void VisitClinitCheck(HClinitCheck* clinit_check) OVERRIDE;
+ void VisitLoadMethodHandle(HLoadMethodHandle* instr) OVERRIDE;
void VisitLoadMethodType(HLoadMethodType* instr) OVERRIDE;
void VisitLoadString(HLoadString* instr) OVERRIDE;
void VisitLoadException(HLoadException* instr) OVERRIDE;
@@ -675,6 +682,12 @@
instr->SetReferenceTypeInfo(instr->InputAt(0)->GetReferenceTypeInfo());
}
+void ReferenceTypePropagation::RTPVisitor::VisitLoadMethodHandle(HLoadMethodHandle* instr) {
+ instr->SetReferenceTypeInfo(ReferenceTypeInfo::Create(
+ handle_cache_->GetMethodHandleClassHandle(),
+ /* is_exact */ true));
+}
+
void ReferenceTypePropagation::RTPVisitor::VisitLoadMethodType(HLoadMethodType* instr) {
instr->SetReferenceTypeInfo(
ReferenceTypeInfo::Create(handle_cache_->GetMethodTypeClassHandle(), /* is_exact */ true));
diff --git a/compiler/optimizing/reference_type_propagation.h b/compiler/optimizing/reference_type_propagation.h
index da2193d..d36d592 100644
--- a/compiler/optimizing/reference_type_propagation.h
+++ b/compiler/optimizing/reference_type_propagation.h
@@ -75,6 +75,7 @@
ReferenceTypeInfo::TypeHandle GetObjectClassHandle();
ReferenceTypeInfo::TypeHandle GetClassClassHandle();
+ ReferenceTypeInfo::TypeHandle GetMethodHandleClassHandle();
ReferenceTypeInfo::TypeHandle GetMethodTypeClassHandle();
ReferenceTypeInfo::TypeHandle GetStringClassHandle();
ReferenceTypeInfo::TypeHandle GetThrowableClassHandle();
@@ -84,6 +85,7 @@
ReferenceTypeInfo::TypeHandle object_class_handle_;
ReferenceTypeInfo::TypeHandle class_class_handle_;
+ ReferenceTypeInfo::TypeHandle method_handle_class_handle_;
ReferenceTypeInfo::TypeHandle method_type_class_handle_;
ReferenceTypeInfo::TypeHandle string_class_handle_;
ReferenceTypeInfo::TypeHandle throwable_class_handle_;
diff --git a/compiler/utils/assembler_thumb_test_expected.cc.inc b/compiler/utils/assembler_thumb_test_expected.cc.inc
index ff3e1ba..19c405e 100644
--- a/compiler/utils/assembler_thumb_test_expected.cc.inc
+++ b/compiler/utils/assembler_thumb_test_expected.cc.inc
@@ -153,7 +153,7 @@
" 21c: f8d9 8034 ldr.w r8, [r9, #52] ; 0x34\n",
" 220: 4770 bx lr\n",
" 222: 4660 mov r0, ip\n",
- " 224: f8d9 c2c8 ldr.w ip, [r9, #712] ; 0x2c8\n",
+ " 224: f8d9 c2cc ldr.w ip, [r9, #716] ; 0x2cc\n",
" 228: 47e0 blx ip\n",
nullptr
};