ART: Compiler support for const-method-type

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: I4b3d3969d455d0198cfe122eea8abd54e0ea20ee
diff --git a/compiler/optimizing/code_generator.cc b/compiler/optimizing/code_generator.cc
index 231017f..1e44311 100644
--- a/compiler/optimizing/code_generator.cc
+++ b/compiler/optimizing/code_generator.cc
@@ -736,6 +736,26 @@
   }
 }
 
+void CodeGenerator::CreateLoadMethodTypeRuntimeCallLocationSummary(
+    HLoadMethodType* method_type,
+    Location runtime_proto_index_location,
+    Location runtime_return_location) {
+  DCHECK_EQ(method_type->InputCount(), 1u);
+  LocationSummary* locations =
+      new (method_type->GetBlock()->GetGraph()->GetAllocator()) LocationSummary(
+          method_type, LocationSummary::kCallOnMainOnly);
+  locations->SetInAt(0, Location::NoLocation());
+  locations->AddTemp(runtime_proto_index_location);
+  locations->SetOut(runtime_return_location);
+}
+
+void CodeGenerator::GenerateLoadMethodTypeRuntimeCall(HLoadMethodType* method_type) {
+  LocationSummary* locations = method_type->GetLocations();
+  MoveConstant(locations->GetTemp(0), method_type->GetProtoIndex());
+  CheckEntrypointTypes<kQuickResolveMethodType, void*, uint32_t>();
+  InvokeRuntime(kQuickResolveMethodType, method_type, method_type->GetDexPc());
+}
+
 static uint32_t GetBootImageOffsetImpl(const void* object, ImageHeader::ImageSections section) {
   Runtime* runtime = Runtime::Current();
   DCHECK(runtime->IsAotCompiler());
diff --git a/compiler/optimizing/code_generator.h b/compiler/optimizing/code_generator.h
index f0c4ee0..7e84a44 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 CreateLoadMethodTypeRuntimeCallLocationSummary(HLoadMethodType* method_type,
+                                                             Location runtime_type_index_location,
+                                                             Location runtime_return_location);
+  void GenerateLoadMethodTypeRuntimeCall(HLoadMethodType* method_type);
+
   uint32_t GetBootImageOffset(HLoadClass* load_class);
   uint32_t GetBootImageOffset(HLoadString* load_string);
   uint32_t GetBootImageOffset(HInvokeStaticOrDirect* invoke);
diff --git a/compiler/optimizing/code_generator_arm64.cc b/compiler/optimizing/code_generator_arm64.cc
index d4cfab8..0601d2d 100644
--- a/compiler/optimizing/code_generator_arm64.cc
+++ b/compiler/optimizing/code_generator_arm64.cc
@@ -5144,6 +5144,16 @@
   }
 }
 
+void LocationsBuilderARM64::VisitLoadMethodType(HLoadMethodType* load) {
+  InvokeRuntimeCallingConvention calling_convention;
+  Location location = LocationFrom(calling_convention.GetRegisterAt(0));
+  CodeGenerator::CreateLoadMethodTypeRuntimeCallLocationSummary(load, location, location);
+}
+
+void InstructionCodeGeneratorARM64::VisitLoadMethodType(HLoadMethodType* load) {
+  codegen_->GenerateLoadMethodTypeRuntimeCall(load);
+}
+
 static MemOperand GetExceptionTlsAddress() {
   return MemOperand(tr, Thread::ExceptionOffset<kArm64PointerSize>().Int32Value());
 }
diff --git a/compiler/optimizing/code_generator_arm_vixl.cc b/compiler/optimizing/code_generator_arm_vixl.cc
index 58ce9aa..33304c6 100644
--- a/compiler/optimizing/code_generator_arm_vixl.cc
+++ b/compiler/optimizing/code_generator_arm_vixl.cc
@@ -7527,6 +7527,16 @@
   }
 }
 
+void LocationsBuilderARMVIXL::VisitLoadMethodType(HLoadMethodType* load) {
+  InvokeRuntimeCallingConventionARMVIXL calling_convention;
+  Location location = LocationFrom(calling_convention.GetRegisterAt(0));
+  CodeGenerator::CreateLoadMethodTypeRuntimeCallLocationSummary(load, location, location);
+}
+
+void InstructionCodeGeneratorARMVIXL::VisitLoadMethodType(HLoadMethodType* load) {
+  codegen_->GenerateLoadMethodTypeRuntimeCall(load);
+}
+
 void LocationsBuilderARMVIXL::VisitClinitCheck(HClinitCheck* check) {
   LocationSummary* locations =
       new (GetGraph()->GetAllocator()) LocationSummary(check, LocationSummary::kCallOnSlowPath);
diff --git a/compiler/optimizing/code_generator_mips.cc b/compiler/optimizing/code_generator_mips.cc
index 25e2edd..3a3fcff 100644
--- a/compiler/optimizing/code_generator_mips.cc
+++ b/compiler/optimizing/code_generator_mips.cc
@@ -8226,6 +8226,16 @@
   }
 }
 
+void LocationsBuilderMIPS::VisitLoadMethodType(HLoadMethodType* load) {
+  InvokeRuntimeCallingConvention calling_convention;
+  Location loc = Location::RegisterLocation(calling_convention.GetRegisterAt(0));
+  CodeGenerator::CreateLoadMethodTypeRuntimeCallLocationSummary(load, loc, loc);
+}
+
+void InstructionCodeGeneratorMIPS::VisitLoadMethodType(HLoadMethodType* load) {
+  codegen_->GenerateLoadMethodTypeRuntimeCall(load);
+}
+
 static int32_t GetExceptionTlsOffset() {
   return Thread::ExceptionOffset<kMipsPointerSize>().Int32Value();
 }
diff --git a/compiler/optimizing/code_generator_mips64.cc b/compiler/optimizing/code_generator_mips64.cc
index 5b07b55..d6fc9a1 100644
--- a/compiler/optimizing/code_generator_mips64.cc
+++ b/compiler/optimizing/code_generator_mips64.cc
@@ -6262,6 +6262,16 @@
   }
 }
 
+void LocationsBuilderMIPS64::VisitLoadMethodType(HLoadMethodType* load) {
+  InvokeRuntimeCallingConvention calling_convention;
+  Location loc = Location::RegisterLocation(calling_convention.GetRegisterAt(0));
+  CodeGenerator::CreateLoadMethodTypeRuntimeCallLocationSummary(load, loc, loc);
+}
+
+void InstructionCodeGeneratorMIPS64::VisitLoadMethodType(HLoadMethodType* load) {
+  codegen_->GenerateLoadMethodTypeRuntimeCall(load);
+}
+
 static int32_t GetExceptionTlsOffset() {
   return Thread::ExceptionOffset<kMips64PointerSize>().Int32Value();
 }
diff --git a/compiler/optimizing/code_generator_x86.cc b/compiler/optimizing/code_generator_x86.cc
index 82d1fda..d18a750 100644
--- a/compiler/optimizing/code_generator_x86.cc
+++ b/compiler/optimizing/code_generator_x86.cc
@@ -6539,6 +6539,16 @@
   }
 }
 
+void LocationsBuilderX86::VisitLoadMethodType(HLoadMethodType* load) {
+  InvokeRuntimeCallingConvention calling_convention;
+  Location location = Location::RegisterLocation(calling_convention.GetRegisterAt(0));
+  CodeGenerator::CreateLoadMethodTypeRuntimeCallLocationSummary(load, location, location);
+}
+
+void InstructionCodeGeneratorX86::VisitLoadMethodType(HLoadMethodType* load) {
+  codegen_->GenerateLoadMethodTypeRuntimeCall(load);
+}
+
 void LocationsBuilderX86::VisitClinitCheck(HClinitCheck* check) {
   LocationSummary* locations =
       new (GetGraph()->GetAllocator()) LocationSummary(check, LocationSummary::kCallOnSlowPath);
diff --git a/compiler/optimizing/code_generator_x86_64.cc b/compiler/optimizing/code_generator_x86_64.cc
index 322b0cf..450c857 100644
--- a/compiler/optimizing/code_generator_x86_64.cc
+++ b/compiler/optimizing/code_generator_x86_64.cc
@@ -5908,6 +5908,16 @@
   }
 }
 
+void LocationsBuilderX86_64::VisitLoadMethodType(HLoadMethodType* load) {
+  // Custom calling convention: RAX serves as both input and output.
+  Location location = Location::RegisterLocation(RAX);
+  CodeGenerator::CreateLoadMethodTypeRuntimeCallLocationSummary(load, location, location);
+}
+
+void InstructionCodeGeneratorX86_64::VisitLoadMethodType(HLoadMethodType* load) {
+  codegen_->GenerateLoadMethodTypeRuntimeCall(load);
+}
+
 void InstructionCodeGeneratorX86_64::VisitClinitCheck(HClinitCheck* check) {
   // We assume the class to not be null.
   SlowPathCode* slow_path = new (codegen_->GetScopedAllocator()) LoadClassSlowPathX86_64(
diff --git a/compiler/optimizing/graph_visualizer.cc b/compiler/optimizing/graph_visualizer.cc
index 54d4644..87ce1f0 100644
--- a/compiler/optimizing/graph_visualizer.cc
+++ b/compiler/optimizing/graph_visualizer.cc
@@ -386,6 +386,13 @@
         << load_class->NeedsAccessCheck() << std::noboolalpha;
   }
 
+  void VisitLoadMethodType(HLoadMethodType* load_method_type) OVERRIDE {
+    StartAttributeStream("load_kind") << "RuntimeCall";
+    const DexFile& dex_file = load_method_type->GetDexFile();
+    const DexFile::ProtoId& proto_id = dex_file.GetProtoId(load_method_type->GetProtoIndex());
+    StartAttributeStream("method_type") << dex_file.GetProtoSignature(proto_id);
+  }
+
   void VisitLoadString(HLoadString* load_string) OVERRIDE {
     StartAttributeStream("load_kind") << load_string->GetLoadKind();
   }
diff --git a/compiler/optimizing/instruction_builder.cc b/compiler/optimizing/instruction_builder.cc
index 9647dd5..61730a8 100644
--- a/compiler/optimizing/instruction_builder.cc
+++ b/compiler/optimizing/instruction_builder.cc
@@ -1896,6 +1896,13 @@
   }
 }
 
+void HInstructionBuilder::BuildLoadMethodType(uint16_t proto_idx, uint32_t dex_pc) {
+  const DexFile& dex_file = *dex_compilation_unit_->GetDexFile();
+  HLoadMethodType* load_method_type =
+      new (allocator_) HLoadMethodType(graph_->GetCurrentMethod(), proto_idx, dex_file, dex_pc);
+  AppendInstruction(load_method_type);
+}
+
 void HInstructionBuilder::BuildTypeCheck(const Instruction& instruction,
                                          uint8_t destination,
                                          uint8_t reference,
@@ -2927,6 +2934,13 @@
       break;
     }
 
+    case Instruction::CONST_METHOD_TYPE: {
+      uint16_t proto_idx = instruction.VRegB_21c();
+      BuildLoadMethodType(proto_idx, dex_pc);
+      UpdateLocal(instruction.VRegA_21c(), current_block_->GetLastInstruction());
+      break;
+    }
+
     case Instruction::MOVE_EXCEPTION: {
       AppendInstruction(new (allocator_) HLoadException(dex_pc));
       UpdateLocal(instruction.VRegA_11x(), current_block_->GetLastInstruction());
diff --git a/compiler/optimizing/instruction_builder.h b/compiler/optimizing/instruction_builder.h
index f788292..3fde54c 100644
--- a/compiler/optimizing/instruction_builder.h
+++ b/compiler/optimizing/instruction_builder.h
@@ -45,6 +45,7 @@
 
 namespace mirror {
 class Class;
+class MethodType;
 }  // namespace mirror
 
 class HInstructionBuilder : public ValueObject {
@@ -239,6 +240,9 @@
   bool LoadClassNeedsAccessCheck(Handle<mirror::Class> klass)
       REQUIRES_SHARED(Locks::mutator_lock_);
 
+  // Builds a `HLoadMethodType` loading the given `proto_index`.
+  void BuildLoadMethodType(uint16_t proto_idx, uint32_t dex_pc);
+
   // Returns the outer-most compiling method's class.
   ObjPtr<mirror::Class> GetOutermostCompilingClass() const;
 
diff --git a/compiler/optimizing/nodes.h b/compiler/optimizing/nodes.h
index 9dcd741..54882ff 100644
--- a/compiler/optimizing/nodes.h
+++ b/compiler/optimizing/nodes.h
@@ -41,6 +41,7 @@
 #include "intrinsics_enum.h"
 #include "locations.h"
 #include "mirror/class.h"
+#include "mirror/method_type.h"
 #include "offsets.h"
 #include "utils/intrusive_forward_list.h"
 
@@ -1382,6 +1383,7 @@
   M(LessThanOrEqual, Condition)                                         \
   M(LoadClass, Instruction)                                             \
   M(LoadException, Instruction)                                         \
+  M(LoadMethodType, Instruction)                                        \
   M(LoadString, Instruction)                                            \
   M(LongConstant, Constant)                                             \
   M(Max, Instruction)                                                   \
@@ -6498,6 +6500,50 @@
   special_input->AddUseAt(this, 0);
 }
 
+class HLoadMethodType FINAL : public HInstruction {
+ public:
+  HLoadMethodType(HCurrentMethod* current_method,
+                  uint16_t proto_idx,
+                  const DexFile& dex_file,
+                  uint32_t dex_pc)
+      : HInstruction(kLoadMethodType,
+                     DataType::Type::kReference,
+                     SideEffectsForArchRuntimeCalls(),
+                     dex_pc),
+        special_input_(HUserRecord<HInstruction*>(current_method)),
+        proto_idx_(proto_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 GetProtoIndex() const { return proto_idx_; }
+
+  const DexFile& GetDexFile() const { return dex_file_; }
+
+  static SideEffects SideEffectsForArchRuntimeCalls() {
+    return SideEffects::CanTriggerGC();
+  }
+
+  DECLARE_INSTRUCTION(LoadMethodType);
+
+ protected:
+  DEFAULT_COPY_CONSTRUCTOR(LoadMethodType);
+
+ private:
+  // The special input is the HCurrentMethod for kRuntimeCall.
+  HUserRecord<HInstruction*> special_input_;
+
+  uint16_t proto_idx_;
+  const DexFile& dex_file_;
+};
+
 /**
  * Performs an initialization check on its Class object input.
  */
diff --git a/compiler/optimizing/reference_type_propagation.cc b/compiler/optimizing/reference_type_propagation.cc
index c47c69a..b15a0ea 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::GetMethodTypeClassHandle() {
+  return GetRootHandle(handles_,
+                       ClassLinker::kJavaLangInvokeMethodType,
+                       &method_type_class_handle_);
+}
+
 ReferenceTypeInfo::TypeHandle ReferenceTypePropagation::HandleCache::GetStringClassHandle() {
   return GetRootHandle(handles_, ClassLinker::kJavaLangString, &string_class_handle_);
 }
@@ -89,6 +95,7 @@
   void VisitLoadClass(HLoadClass* load_class) OVERRIDE;
   void VisitInstanceOf(HInstanceOf* load_class) OVERRIDE;
   void VisitClinitCheck(HClinitCheck* clinit_check) OVERRIDE;
+  void VisitLoadMethodType(HLoadMethodType* instr) OVERRIDE;
   void VisitLoadString(HLoadString* instr) OVERRIDE;
   void VisitLoadException(HLoadException* instr) OVERRIDE;
   void VisitNewArray(HNewArray* instr) OVERRIDE;
@@ -668,6 +675,11 @@
   instr->SetReferenceTypeInfo(instr->InputAt(0)->GetReferenceTypeInfo());
 }
 
+void ReferenceTypePropagation::RTPVisitor::VisitLoadMethodType(HLoadMethodType* instr) {
+  instr->SetReferenceTypeInfo(
+      ReferenceTypeInfo::Create(handle_cache_->GetMethodTypeClassHandle(), /* is_exact */ true));
+}
+
 void ReferenceTypePropagation::RTPVisitor::VisitLoadString(HLoadString* instr) {
   instr->SetReferenceTypeInfo(
       ReferenceTypeInfo::Create(handle_cache_->GetStringClassHandle(), /* is_exact */ true));
diff --git a/compiler/optimizing/reference_type_propagation.h b/compiler/optimizing/reference_type_propagation.h
index 400852f..da2193d 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 GetMethodTypeClassHandle();
     ReferenceTypeInfo::TypeHandle GetStringClassHandle();
     ReferenceTypeInfo::TypeHandle GetThrowableClassHandle();
 
@@ -83,6 +84,7 @@
 
     ReferenceTypeInfo::TypeHandle object_class_handle_;
     ReferenceTypeInfo::TypeHandle class_class_handle_;
+    ReferenceTypeInfo::TypeHandle method_type_class_handle_;
     ReferenceTypeInfo::TypeHandle string_class_handle_;
     ReferenceTypeInfo::TypeHandle throwable_class_handle_;
   };