ART: Add support for constructor method handles

Add well known methods for MethodHandles.lookup() and
MethodHandles.Lookup.findConstructor(). These are used to call the
Java code that create a constructor transform.

Separate method handle resolution paths for fields and methods in the
class linker.

Update test 952-invoke-custom-kinds to include a constructor method
handle. The test classes now match dx/tests/135-invoke-custom.

Bug: 62774190
Test: Update 952-invoke-custom-kinds
Change-Id: I9a007254a856422c24397c4df3ef3dfbf6bdd840
diff --git a/runtime/class_linker.cc b/runtime/class_linker.cc
index ca89cee..a5d4540 100644
--- a/runtime/class_linker.cc
+++ b/runtime/class_linker.cc
@@ -8369,180 +8369,73 @@
   return type.Get();
 }
 
-mirror::MethodHandle* ClassLinker::ResolveMethodHandle(uint32_t method_handle_idx,
-                                                       ArtMethod* referrer)
-    REQUIRES_SHARED(Locks::mutator_lock_) {
-  Thread* const self = Thread::Current();
-  const DexFile* const dex_file = referrer->GetDexFile();
-  const DexFile::MethodHandleItem& mh = dex_file->GetMethodHandle(method_handle_idx);
-
-  mirror::MethodHandle::Kind kind;
-  ArtField* target_field = nullptr;
-  ArtMethod* target_method = nullptr;
-
+mirror::MethodHandle* ClassLinker::ResolveMethodHandleForField(
+    Thread* self,
+    const DexFile::MethodHandleItem& method_handle,
+    ArtMethod* referrer) {
   DexFile::MethodHandleType handle_type =
-      static_cast<DexFile::MethodHandleType>(mh.method_handle_type_);
+      static_cast<DexFile::MethodHandleType>(method_handle.method_handle_type_);
+  mirror::MethodHandle::Kind kind;
+  bool is_static;
+  int32_t num_params;
   switch (handle_type) {
     case DexFile::MethodHandleType::kStaticPut: {
       kind = mirror::MethodHandle::Kind::kStaticPut;
-      target_field = ResolveField(mh.field_or_method_idx_, referrer, true /* is_static */);
+      is_static = true;
+      num_params = 1;
       break;
     }
     case DexFile::MethodHandleType::kStaticGet: {
       kind = mirror::MethodHandle::Kind::kStaticGet;
-      target_field = ResolveField(mh.field_or_method_idx_, referrer, true /* is_static */);
+      is_static = true;
+      num_params = 0;
       break;
     }
     case DexFile::MethodHandleType::kInstancePut: {
       kind = mirror::MethodHandle::Kind::kInstancePut;
-      target_field = ResolveField(mh.field_or_method_idx_, referrer, false /* is_static */);
-      break;
-    }
-    case DexFile::MethodHandleType::kInstanceGet: {
-      kind = mirror::MethodHandle::Kind::kInstanceGet;
-      target_field = ResolveField(mh.field_or_method_idx_, referrer, false /* is_static */);
-      break;
-    }
-    case DexFile::MethodHandleType::kInvokeStatic: {
-      kind = mirror::MethodHandle::Kind::kInvokeStatic;
-      target_method = ResolveMethod<kNoICCECheckForCache>(self,
-                                                          mh.field_or_method_idx_,
-                                                          referrer,
-                                                          InvokeType::kStatic);
-      break;
-    }
-    case DexFile::MethodHandleType::kInvokeInstance: {
-      kind = mirror::MethodHandle::Kind::kInvokeVirtual;
-      target_method = ResolveMethod<kNoICCECheckForCache>(self,
-                                                          mh.field_or_method_idx_,
-                                                          referrer,
-                                                          InvokeType::kVirtual);
-      break;
-    }
-    case DexFile::MethodHandleType::kInvokeConstructor: {
-      UNIMPLEMENTED(FATAL) << "Invoke constructor is implemented as a transform.";
-      break;
-    }
-    case DexFile::MethodHandleType::kInvokeDirect: {
-      StackHandleScope<2> hs(self);
-      // A constant method handle with type kInvokeDirect can refer to
-      // a method that is private or to a method in a super class. To
-      // disambiguate the two options, we resolve the method ignoring
-      // the invocation type to determine if the method is private. We
-      // then resolve again specifying the intended invocation type to
-      // force the appropriate checks.
-      target_method = ResolveMethodWithoutInvokeType(*dex_file,
-                                                     mh.field_or_method_idx_,
-                                                     hs.NewHandle(referrer->GetDexCache()),
-                                                     hs.NewHandle(referrer->GetClassLoader()));
-      if (target_method == nullptr) {
-        break;
-      }
-
-      if (target_method->IsPrivate()) {
-        kind = mirror::MethodHandle::Kind::kInvokeDirect;
-        target_method = ResolveMethod<kNoICCECheckForCache>(self,
-                                                            mh.field_or_method_idx_,
-                                                            referrer,
-                                                            InvokeType::kDirect);
-      } else {
-        kind = mirror::MethodHandle::Kind::kInvokeSuper;
-        target_method = ResolveMethod<kNoICCECheckForCache>(self,
-                                                            mh.field_or_method_idx_,
-                                                            referrer,
-                                                            InvokeType::kSuper);
-        if (target_method == nullptr) {
-          break;
-        }
-        // Find the method specified in the parent in referring class
-        // so invoke-super invokes the method in the parent of the
-        // referrer.
-        target_method =
-            referrer->GetDeclaringClass()->FindVirtualMethodForVirtual(target_method,
-                                                                       kRuntimePointerSize);
-      }
-      break;
-    }
-    case DexFile::MethodHandleType::kInvokeInterface: {
-      kind = mirror::MethodHandle::Kind::kInvokeInterface;
-      target_method = ResolveMethod<kNoICCECheckForCache>(self,
-                                                          mh.field_or_method_idx_,
-                                                          referrer,
-                                                          InvokeType::kInterface);
-      break;
-    }
-  }
-
-  if (target_field != nullptr) {
-    ObjPtr<mirror::Class> target_class = target_field->GetDeclaringClass();
-    ObjPtr<mirror::Class> referring_class = referrer->GetDeclaringClass();
-    if (!referring_class->CanAccessMember(target_class, target_field->GetAccessFlags())) {
-      ThrowIllegalAccessErrorField(referring_class, target_field);
-      return nullptr;
-    }
-  } else if (target_method != nullptr) {
-    ObjPtr<mirror::Class> target_class = target_method->GetDeclaringClass();
-    ObjPtr<mirror::Class> referring_class = referrer->GetDeclaringClass();
-    if (!referring_class->CanAccessMember(target_class, target_method->GetAccessFlags())) {
-      ThrowIllegalAccessErrorMethod(referring_class, target_method);
-      return nullptr;
-    }
-  } else {
-    // Common check for resolution failure.
-    DCHECK(Thread::Current()->IsExceptionPending());
-    return nullptr;
-  }
-
-  // Determine the number of parameters after it's safe to follow the
-  // field or method pointer.
-  uint32_t num_params;
-  switch (handle_type) {
-    case DexFile::MethodHandleType::kStaticPut: {
-      num_params = 1;
-      break;
-    }
-    case DexFile::MethodHandleType::kStaticGet: {
-      num_params = 0;
-      break;
-    }
-    case DexFile::MethodHandleType::kInstancePut: {
+      is_static = false;
       num_params = 2;
       break;
     }
     case DexFile::MethodHandleType::kInstanceGet: {
+      kind = mirror::MethodHandle::Kind::kInstanceGet;
+      is_static = false;
       num_params = 1;
       break;
     }
-    case DexFile::MethodHandleType::kInvokeStatic: {
-      uint32_t shorty_length;
-      target_method->GetShorty(&shorty_length);
-      num_params = shorty_length - 1;  // Remove 1 for the return value.
-      break;
-    }
+    case DexFile::MethodHandleType::kInvokeStatic:
     case DexFile::MethodHandleType::kInvokeInstance:
+    case DexFile::MethodHandleType::kInvokeConstructor:
     case DexFile::MethodHandleType::kInvokeDirect:
-    case DexFile::MethodHandleType::kInvokeInterface: {
-      // Add 1 for the receiver and remove 1 for the return value.
-      target_method->GetShorty(&num_params);
-      break;
-    }
-    case DexFile::MethodHandleType::kInvokeConstructor: {
-      UNIMPLEMENTED(FATAL) << "Invoke constructor is implemented as a transform.";
-      num_params = 0;
-      break;
-    }
+    case DexFile::MethodHandleType::kInvokeInterface:
+      UNREACHABLE();
   }
 
-  StackHandleScope<5> hs(self);
+  ArtField* target_field =
+      ResolveField(method_handle.field_or_method_idx_, referrer, is_static);
+  if (LIKELY(target_field != nullptr)) {
+    ObjPtr<mirror::Class> target_class = target_field->GetDeclaringClass();
+    ObjPtr<mirror::Class> referring_class = referrer->GetDeclaringClass();
+    if (UNLIKELY(!referring_class->CanAccessMember(target_class, target_field->GetAccessFlags()))) {
+      ThrowIllegalAccessErrorField(referring_class, target_field);
+      return nullptr;
+    }
+  } else {
+    DCHECK(Thread::Current()->IsExceptionPending());
+    return nullptr;
+  }
+
+  StackHandleScope<4> hs(self);
   ObjPtr<mirror::Class> class_type = mirror::Class::GetJavaLangClass();
   ObjPtr<mirror::Class> array_of_class = FindArrayClass(self, &class_type);
   Handle<mirror::ObjectArray<mirror::Class>> method_params(hs.NewHandle(
       mirror::ObjectArray<mirror::Class>::Alloc(self, array_of_class, num_params)));
-  if (method_params.Get() == nullptr) {
+  if (UNLIKELY(method_params.Get() == nullptr)) {
     DCHECK(self->IsExceptionPending());
     return nullptr;
   }
 
+  Handle<mirror::Class> constructor_class;
   Handle<mirror::Class> return_type;
   switch (handle_type) {
     case DexFile::MethodHandleType::kStaticPut: {
@@ -8565,59 +8458,228 @@
       return_type = hs.NewHandle(target_field->GetType<true>());
       break;
     }
-    case DexFile::MethodHandleType::kInvokeDirect:
+    case DexFile::MethodHandleType::kInvokeStatic:
     case DexFile::MethodHandleType::kInvokeInstance:
+    case DexFile::MethodHandleType::kInvokeConstructor:
+    case DexFile::MethodHandleType::kInvokeDirect:
     case DexFile::MethodHandleType::kInvokeInterface:
-    case DexFile::MethodHandleType::kInvokeStatic: {
-      // TODO(oth): This will not work for varargs methods as this
-      // requires instantiating a Transformer. This resolution step
-      // would be best done in managed code rather than in the run
-      // time (b/35235705)
-      Handle<mirror::DexCache> dex_cache(hs.NewHandle(referrer->GetDexCache()));
-      Handle<mirror::ClassLoader> class_loader(hs.NewHandle(referrer->GetClassLoader()));
-      DexFileParameterIterator it(*dex_file, target_method->GetPrototype());
-      int32_t index = 0;
-      if (handle_type != DexFile::MethodHandleType::kInvokeStatic) {
-        method_params->Set(index++, target_method->GetDeclaringClass());
-      }
-      while (it.HasNext()) {
-        const dex::TypeIndex type_idx = it.GetTypeIdx();
-        mirror::Class* klass = ResolveType(*dex_file, type_idx, dex_cache, class_loader);
-        if (nullptr == klass) {
-          DCHECK(self->IsExceptionPending());
-          return nullptr;
-        }
-        method_params->Set(index++, klass);
-        it.Next();
-      }
-      return_type = hs.NewHandle(target_method->GetReturnType(true));
-      break;
-    }
-    case DexFile::MethodHandleType::kInvokeConstructor: {
-      // TODO(oth): b/35235705
-      UNIMPLEMENTED(FATAL) << "Invoke constructor is implemented as a transform.";
+      UNREACHABLE();
+  }
+
+  for (int32_t i = 0; i < num_params; ++i) {
+    if (UNLIKELY(method_params->Get(i) == nullptr)) {
+      DCHECK(self->IsExceptionPending());
+      return nullptr;
     }
   }
 
-  if (return_type.IsNull()) {
+  if (UNLIKELY(return_type.IsNull())) {
     DCHECK(self->IsExceptionPending());
     return nullptr;
   }
 
   Handle<mirror::MethodType>
-      mt(hs.NewHandle(mirror::MethodType::Create(self, return_type, method_params)));
-  if (mt.IsNull()) {
+      method_type(hs.NewHandle(mirror::MethodType::Create(self, return_type, method_params)));
+  if (UNLIKELY(method_type.IsNull())) {
     DCHECK(self->IsExceptionPending());
     return nullptr;
   }
 
-  uintptr_t target;
-  if (target_field != nullptr) {
-    target = reinterpret_cast<uintptr_t>(target_field);
-  } else {
-    target = reinterpret_cast<uintptr_t>(target_method);
+  uintptr_t target = reinterpret_cast<uintptr_t>(target_field);
+  return mirror::MethodHandleImpl::Create(self, target, kind, method_type);
+}
+
+mirror::MethodHandle* ClassLinker::ResolveMethodHandleForMethod(
+    Thread* self,
+    const DexFile* const dex_file,
+    const DexFile::MethodHandleItem& method_handle,
+    ArtMethod* referrer) {
+  DexFile::MethodHandleType handle_type =
+      static_cast<DexFile::MethodHandleType>(method_handle.method_handle_type_);
+  mirror::MethodHandle::Kind kind;
+  uint32_t receiver_count = 0;
+  ArtMethod* target_method = nullptr;
+  switch (handle_type) {
+    case DexFile::MethodHandleType::kStaticPut:
+    case DexFile::MethodHandleType::kStaticGet:
+    case DexFile::MethodHandleType::kInstancePut:
+    case DexFile::MethodHandleType::kInstanceGet:
+      UNREACHABLE();
+    case DexFile::MethodHandleType::kInvokeStatic: {
+      kind = mirror::MethodHandle::Kind::kInvokeStatic;
+      receiver_count = 0;
+      target_method = ResolveMethod<kNoICCECheckForCache>(self,
+                                                          method_handle.field_or_method_idx_,
+                                                          referrer,
+                                                          InvokeType::kStatic);
+      break;
+    }
+    case DexFile::MethodHandleType::kInvokeInstance: {
+      kind = mirror::MethodHandle::Kind::kInvokeVirtual;
+      receiver_count = 1;
+      target_method = ResolveMethod<kNoICCECheckForCache>(self,
+                                                          method_handle.field_or_method_idx_,
+                                                          referrer,
+                                                          InvokeType::kVirtual);
+      break;
+    }
+    case DexFile::MethodHandleType::kInvokeConstructor: {
+      // Constructors are currently implemented as a transform. They
+      // are special cased later in this method.
+      kind = mirror::MethodHandle::Kind::kInvokeTransform;
+      receiver_count = 0;
+      target_method = ResolveMethod<kNoICCECheckForCache>(self,
+                                                          method_handle.field_or_method_idx_,
+                                                          referrer,
+                                                          InvokeType::kDirect);
+      break;
+    }
+    case DexFile::MethodHandleType::kInvokeDirect: {
+      kind = mirror::MethodHandle::Kind::kInvokeDirect;
+      receiver_count = 1;
+      StackHandleScope<2> hs(self);
+      // A constant method handle with type kInvokeDirect can refer to
+      // a method that is private or to a method in a super class. To
+      // disambiguate the two options, we resolve the method ignoring
+      // the invocation type to determine if the method is private. We
+      // then resolve again specifying the intended invocation type to
+      // force the appropriate checks.
+      target_method = ResolveMethodWithoutInvokeType(*dex_file,
+                                                     method_handle.field_or_method_idx_,
+                                                     hs.NewHandle(referrer->GetDexCache()),
+                                                     hs.NewHandle(referrer->GetClassLoader()));
+      if (UNLIKELY(target_method == nullptr)) {
+        break;
+      }
+
+      if (target_method->IsPrivate()) {
+        kind = mirror::MethodHandle::Kind::kInvokeDirect;
+        target_method = ResolveMethod<kNoICCECheckForCache>(self,
+                                                            method_handle.field_or_method_idx_,
+                                                            referrer,
+                                                            InvokeType::kDirect);
+      } else {
+        kind = mirror::MethodHandle::Kind::kInvokeSuper;
+        target_method = ResolveMethod<kNoICCECheckForCache>(self,
+                                                            method_handle.field_or_method_idx_,
+                                                            referrer,
+                                                            InvokeType::kSuper);
+        if (UNLIKELY(target_method == nullptr)) {
+          break;
+        }
+        // Find the method specified in the parent in referring class
+        // so invoke-super invokes the method in the parent of the
+        // referrer.
+        target_method =
+            referrer->GetDeclaringClass()->FindVirtualMethodForVirtual(target_method,
+                                                                       kRuntimePointerSize);
+      }
+      break;
+    }
+    case DexFile::MethodHandleType::kInvokeInterface: {
+      kind = mirror::MethodHandle::Kind::kInvokeInterface;
+      receiver_count = 1;
+      target_method = ResolveMethod<kNoICCECheckForCache>(self,
+                                                          method_handle.field_or_method_idx_,
+                                                          referrer,
+                                                          InvokeType::kInterface);
+      break;
+    }
   }
-  return mirror::MethodHandleImpl::Create(self, target, kind, mt);
+
+  if (UNLIKELY(target_method == nullptr)) {
+    DCHECK(Thread::Current()->IsExceptionPending());
+    return nullptr;
+  }
+
+  ObjPtr<mirror::Class> target_class = target_method->GetDeclaringClass();
+  ObjPtr<mirror::Class> referring_class = referrer->GetDeclaringClass();
+  uint32_t access_flags = target_method->GetAccessFlags();
+  if (UNLIKELY(!referring_class->CanAccessMember(target_class, access_flags))) {
+    ThrowIllegalAccessErrorMethod(referring_class, target_method);
+    return nullptr;
+  }
+
+  // Calculate the number of parameters from the method shorty. We add the
+  // receiver count (0 or 1) and deduct one for the return value.
+  uint32_t shorty_length;
+  target_method->GetShorty(&shorty_length);
+  int32_t num_params = static_cast<int32_t>(shorty_length + receiver_count - 1);
+
+  StackHandleScope<7> hs(self);
+  ObjPtr<mirror::Class> class_type = mirror::Class::GetJavaLangClass();
+  ObjPtr<mirror::Class> array_of_class = FindArrayClass(self, &class_type);
+  Handle<mirror::ObjectArray<mirror::Class>> method_params(hs.NewHandle(
+      mirror::ObjectArray<mirror::Class>::Alloc(self, array_of_class, num_params)));
+  if (method_params.Get() == nullptr) {
+    DCHECK(self->IsExceptionPending());
+    return nullptr;
+  }
+
+  Handle<mirror::DexCache> dex_cache(hs.NewHandle(referrer->GetDexCache()));
+  Handle<mirror::ClassLoader> class_loader(hs.NewHandle(referrer->GetClassLoader()));
+  int32_t index = 0;
+
+  if (receiver_count != 0) {
+    // Insert receiver
+    method_params->Set(index++, target_method->GetDeclaringClass());
+  }
+
+  DexFileParameterIterator it(*dex_file, target_method->GetPrototype());
+  while (it.HasNext()) {
+    const dex::TypeIndex type_idx = it.GetTypeIdx();
+    mirror::Class* klass = ResolveType(*dex_file, type_idx, dex_cache, class_loader);
+    if (nullptr == klass) {
+      DCHECK(self->IsExceptionPending());
+      return nullptr;
+    }
+    method_params->Set(index++, klass);
+    it.Next();
+  }
+
+  Handle<mirror::Class> return_type = hs.NewHandle(target_method->GetReturnType(true));
+  if (UNLIKELY(return_type.IsNull())) {
+    DCHECK(self->IsExceptionPending());
+    return nullptr;
+  }
+
+  Handle<mirror::MethodType>
+      method_type(hs.NewHandle(mirror::MethodType::Create(self, return_type, method_params)));
+  if (UNLIKELY(method_type.IsNull())) {
+    DCHECK(self->IsExceptionPending());
+    return nullptr;
+  }
+
+  if (UNLIKELY(handle_type == DexFile::MethodHandleType::kInvokeConstructor)) {
+    Handle<mirror::Class> constructor_class = hs.NewHandle(target_method->GetDeclaringClass());
+    Handle<mirror::MethodHandlesLookup> lookup =
+        hs.NewHandle(mirror::MethodHandlesLookup::GetDefault(self));
+    return lookup->FindConstructor(self, constructor_class, method_type);
+  }
+
+  uintptr_t target = reinterpret_cast<uintptr_t>(target_method);
+  return mirror::MethodHandleImpl::Create(self, target, kind, method_type);
+}
+
+mirror::MethodHandle* ClassLinker::ResolveMethodHandle(uint32_t method_handle_idx,
+                                                       ArtMethod* referrer)
+    REQUIRES_SHARED(Locks::mutator_lock_) {
+  Thread* const self = Thread::Current();
+  const DexFile* const dex_file = referrer->GetDexFile();
+  const DexFile::MethodHandleItem& method_handle = dex_file->GetMethodHandle(method_handle_idx);
+  switch (static_cast<DexFile::MethodHandleType>(method_handle.method_handle_type_)) {
+    case DexFile::MethodHandleType::kStaticPut:
+    case DexFile::MethodHandleType::kStaticGet:
+    case DexFile::MethodHandleType::kInstancePut:
+    case DexFile::MethodHandleType::kInstanceGet:
+      return ResolveMethodHandleForField(self, method_handle, referrer);
+    case DexFile::MethodHandleType::kInvokeStatic:
+    case DexFile::MethodHandleType::kInvokeInstance:
+    case DexFile::MethodHandleType::kInvokeConstructor:
+    case DexFile::MethodHandleType::kInvokeDirect:
+    case DexFile::MethodHandleType::kInvokeInterface:
+      return ResolveMethodHandleForMethod(self, dex_file, method_handle, referrer);
+  }
 }
 
 bool ClassLinker::IsQuickResolutionStub(const void* entry_point) const {
diff --git a/runtime/class_linker.h b/runtime/class_linker.h
index 00ae758..8b8a6fd 100644
--- a/runtime/class_linker.h
+++ b/runtime/class_linker.h
@@ -944,6 +944,17 @@
                    ArtMethod** out_imt)
       REQUIRES_SHARED(Locks::mutator_lock_);
 
+  mirror::MethodHandle* ResolveMethodHandleForField(Thread* self,
+                                                    const DexFile::MethodHandleItem& method_handle,
+                                                    ArtMethod* referrer)
+      REQUIRES_SHARED(Locks::mutator_lock_);
+
+  mirror::MethodHandle* ResolveMethodHandleForMethod(Thread* self,
+                                                     const DexFile* const dex_file,
+                                                     const DexFile::MethodHandleItem& method_handle,
+                                                     ArtMethod* referrer)
+      REQUIRES_SHARED(Locks::mutator_lock_);
+
   // A wrapper class representing the result of a method translation used for linking methods and
   // updating superclass default methods. For each method in a classes vtable there are 4 states it
   // could be in:
diff --git a/runtime/mirror/method_handles_lookup.cc b/runtime/mirror/method_handles_lookup.cc
index 0c25fa8..9eada6d 100644
--- a/runtime/mirror/method_handles_lookup.cc
+++ b/runtime/mirror/method_handles_lookup.cc
@@ -20,7 +20,10 @@
 #include "gc_root-inl.h"
 #include "object-inl.h"
 #include "handle_scope.h"
+#include "jni_internal.h"
+#include "mirror/method_handle_impl.h"
 #include "modifiers.h"
+#include "well_known_classes.h"
 
 namespace art {
 namespace mirror {
@@ -54,5 +57,27 @@
   return mhl.Get();
 }
 
+MethodHandlesLookup* MethodHandlesLookup::GetDefault(Thread* const self) {
+  ArtMethod* lookup = jni::DecodeArtMethod(WellKnownClasses::java_lang_invoke_MethodHandles_lookup);
+  JValue result;
+  lookup->Invoke(self, nullptr, 0, &result, "L");
+  return down_cast<MethodHandlesLookup*>(result.GetL());
+}
+
+MethodHandle* MethodHandlesLookup::FindConstructor(Thread* const self,
+                                                           Handle<Class> klass,
+                                                           Handle<MethodType> method_type) {
+  ArtMethod* findConstructor =
+      jni::DecodeArtMethod(WellKnownClasses::java_lang_invoke_MethodHandles_Lookup_findConstructor);
+  uint32_t args[] = {
+    static_cast<uint32_t>(reinterpret_cast<uintptr_t>(this)),
+    static_cast<uint32_t>(reinterpret_cast<uintptr_t>(klass.Get())),
+    static_cast<uint32_t>(reinterpret_cast<uintptr_t>(method_type.Get()))
+  };
+  JValue result;
+  findConstructor->Invoke(self, args, sizeof(args), &result, "LLL");
+  return down_cast<MethodHandle*>(result.GetL());
+}
+
 }  // namespace mirror
 }  // namespace art
diff --git a/runtime/mirror/method_handles_lookup.h b/runtime/mirror/method_handles_lookup.h
index 63eb428..2109f60 100644
--- a/runtime/mirror/method_handles_lookup.h
+++ b/runtime/mirror/method_handles_lookup.h
@@ -30,6 +30,9 @@
 
 namespace mirror {
 
+class MethodHandle;
+class MethodType;
+
 // C++ mirror of java.lang.invoke.MethodHandles.Lookup
 class MANAGED MethodHandlesLookup : public Object {
  public:
@@ -45,6 +48,16 @@
   static void ResetClass() REQUIRES_SHARED(Locks::mutator_lock_);
   static void VisitRoots(RootVisitor* visitor) REQUIRES_SHARED(Locks::mutator_lock_);
 
+  // Returns the result of java.lang.invoke.MethodHandles.lookup().
+  static mirror::MethodHandlesLookup* GetDefault(Thread* const self)
+      REQUIRES_SHARED(Locks::mutator_lock_);
+
+  // Find constructor using java.lang.invoke.MethodHandles$Lookup.findConstructor().
+  mirror::MethodHandle* FindConstructor(Thread* const self,
+                                        Handle<Class> klass,
+                                        Handle<MethodType> method_type)
+      REQUIRES_SHARED(Locks::mutator_lock_);
+
  private:
   static MemberOffset AllowedModesOffset() {
     return MemberOffset(OFFSETOF_MEMBER(MethodHandlesLookup, allowed_modes_));
diff --git a/runtime/well_known_classes.cc b/runtime/well_known_classes.cc
index 8d505e2..f72fdb4 100644
--- a/runtime/well_known_classes.cc
+++ b/runtime/well_known_classes.cc
@@ -94,6 +94,8 @@
 jmethodID WellKnownClasses::java_lang_Integer_valueOf;
 jmethodID WellKnownClasses::java_lang_invoke_MethodHandle_invoke;
 jmethodID WellKnownClasses::java_lang_invoke_MethodHandle_invokeExact;
+jmethodID WellKnownClasses::java_lang_invoke_MethodHandles_lookup;
+jmethodID WellKnownClasses::java_lang_invoke_MethodHandles_Lookup_findConstructor;
 jmethodID WellKnownClasses::java_lang_Long_valueOf;
 jmethodID WellKnownClasses::java_lang_ref_FinalizerReference_add;
 jmethodID WellKnownClasses::java_lang_ref_ReferenceQueue_add;
@@ -173,8 +175,8 @@
   return fid;
 }
 
-jmethodID CacheMethod(JNIEnv* env, jclass c, bool is_static,
-                      const char* name, const char* signature) {
+static jmethodID CacheMethod(JNIEnv* env, jclass c, bool is_static,
+                             const char* name, const char* signature) {
   jmethodID mid = is_static ? env->GetStaticMethodID(c, name, signature) :
       env->GetMethodID(c, name, signature);
   if (mid == nullptr) {
@@ -190,6 +192,12 @@
   return mid;
 }
 
+static jmethodID CacheMethod(JNIEnv* env, const char* klass, bool is_static,
+                      const char* name, const char* signature) {
+  ScopedLocalRef<jclass> java_class(env, env->FindClass(klass));
+  return CacheMethod(env, java_class.get(), is_static, name, signature);
+}
+
 static jmethodID CachePrimitiveBoxingMethod(JNIEnv* env, char prim_name, const char* boxed_name) {
   ScopedLocalRef<jclass> boxed_class(env, env->FindClass(boxed_name));
   return CacheMethod(env, boxed_class.get(), true, "valueOf",
@@ -322,16 +330,12 @@
   java_lang_Daemons_requestHeapTrim = CacheMethod(env, java_lang_Daemons, true, "requestHeapTrim", "()V");
   java_lang_Daemons_start = CacheMethod(env, java_lang_Daemons, true, "start", "()V");
   java_lang_Daemons_stop = CacheMethod(env, java_lang_Daemons, true, "stop", "()V");
-  java_lang_invoke_MethodHandle_invoke =
-      CacheMethod(env, java_lang_invoke_MethodHandle, false,
-                  "invoke", "([Ljava/lang/Object;)Ljava/lang/Object;");
-  java_lang_invoke_MethodHandle_invokeExact =
-      CacheMethod(env, java_lang_invoke_MethodHandle, false,
-                  "invokeExact", "([Ljava/lang/Object;)Ljava/lang/Object;");
-  ScopedLocalRef<jclass> java_lang_ref_FinalizerReference(env, env->FindClass("java/lang/ref/FinalizerReference"));
-  java_lang_ref_FinalizerReference_add = CacheMethod(env, java_lang_ref_FinalizerReference.get(), true, "add", "(Ljava/lang/Object;)V");
-  ScopedLocalRef<jclass> java_lang_ref_ReferenceQueue(env, env->FindClass("java/lang/ref/ReferenceQueue"));
-  java_lang_ref_ReferenceQueue_add = CacheMethod(env, java_lang_ref_ReferenceQueue.get(), true, "add", "(Ljava/lang/ref/Reference;)V");
+  java_lang_invoke_MethodHandle_invoke = CacheMethod(env, java_lang_invoke_MethodHandle, false, "invoke", "([Ljava/lang/Object;)Ljava/lang/Object;");
+  java_lang_invoke_MethodHandle_invokeExact = CacheMethod(env, java_lang_invoke_MethodHandle, false, "invokeExact", "([Ljava/lang/Object;)Ljava/lang/Object;");
+  java_lang_invoke_MethodHandles_lookup = CacheMethod(env, "java/lang/invoke/MethodHandles", true, "lookup", "()Ljava/lang/invoke/MethodHandles$Lookup;");
+  java_lang_invoke_MethodHandles_Lookup_findConstructor = CacheMethod(env, "java/lang/invoke/MethodHandles$Lookup", false, "findConstructor", "(Ljava/lang/Class;Ljava/lang/invoke/MethodType;)Ljava/lang/invoke/MethodHandle;");
+  java_lang_ref_FinalizerReference_add = CacheMethod(env, "java/lang/ref/FinalizerReference", true, "add", "(Ljava/lang/Object;)V");
+  java_lang_ref_ReferenceQueue_add = CacheMethod(env, "java/lang/ref/ReferenceQueue", true, "add", "(Ljava/lang/ref/Reference;)V");
 
   java_lang_reflect_Parameter_init = CacheMethod(env, java_lang_reflect_Parameter, false, "<init>", "(Ljava/lang/String;ILjava/lang/reflect/Executable;I)V");
   java_lang_String_charAt = CacheMethod(env, java_lang_String, false, "charAt", "(I)C");
diff --git a/runtime/well_known_classes.h b/runtime/well_known_classes.h
index c5a16c1..2f2f1ad 100644
--- a/runtime/well_known_classes.h
+++ b/runtime/well_known_classes.h
@@ -33,8 +33,6 @@
 // them up. Similar to libcore's JniConstants (except there's no overlap, so
 // we keep them separate).
 
-jmethodID CacheMethod(JNIEnv* env, jclass c, bool is_static, const char* name, const char* signature);
-
 struct WellKnownClasses {
  public:
   static void Init(JNIEnv* env);  // Run before native methods are registered.
@@ -104,6 +102,8 @@
   static jmethodID java_lang_Integer_valueOf;
   static jmethodID java_lang_invoke_MethodHandle_invoke;
   static jmethodID java_lang_invoke_MethodHandle_invokeExact;
+  static jmethodID java_lang_invoke_MethodHandles_lookup;
+  static jmethodID java_lang_invoke_MethodHandles_Lookup_findConstructor;
   static jmethodID java_lang_Long_valueOf;
   static jmethodID java_lang_ref_FinalizerReference_add;
   static jmethodID java_lang_ref_ReferenceQueue_add;
diff --git a/test/952-invoke-custom-kinds/classes/invokecustom/InvokeCustom.class b/test/952-invoke-custom-kinds/classes/invokecustom/InvokeCustom.class
index a37a49b..b8dcd55 100644
--- a/test/952-invoke-custom-kinds/classes/invokecustom/InvokeCustom.class
+++ b/test/952-invoke-custom-kinds/classes/invokecustom/InvokeCustom.class
Binary files differ
diff --git a/test/952-invoke-custom-kinds/classes/invokecustom/TestGenerator.class b/test/952-invoke-custom-kinds/classes/invokecustom/TestGenerator.class
index aa7e521..03dc233 100644
--- a/test/952-invoke-custom-kinds/classes/invokecustom/TestGenerator.class
+++ b/test/952-invoke-custom-kinds/classes/invokecustom/TestGenerator.class
Binary files differ
diff --git a/test/952-invoke-custom-kinds/expected.txt b/test/952-invoke-custom-kinds/expected.txt
index 55e1d0b..c41b5c6 100644
--- a/test/952-invoke-custom-kinds/expected.txt
+++ b/test/952-invoke-custom-kinds/expected.txt
@@ -34,6 +34,7 @@
 checkStaticFieldTest9: old 0 new 1985229328 expected 1985229328 OK
 checkFieldTest9: old 0.0 new 1.99E-19 expected 1.99E-19 OK
 helperMethodTest9 in class invokecustom.InvokeCustom
+InvokeCustom.<init>(3)
 run() for Test9
 InvokeCustom.privateMethodTest9()
 targetMethodTest9()
diff --git a/test/952-invoke-custom-kinds/info.txt b/test/952-invoke-custom-kinds/info.txt
index cddb96d..33b4cff 100644
--- a/test/952-invoke-custom-kinds/info.txt
+++ b/test/952-invoke-custom-kinds/info.txt
@@ -1,7 +1,4 @@
 This test checks call sites and constant method handles in DEX files used
 by invoke-custom.
 
-It is derived from a dx test (dalvik/dx/tests/135-invoke-custom) which
-generates the invoke-custom using ASM to generate class files. The
-test here differs as it not include an instance a constant method
-handle with a constructor kind (see b/62774190).
+The class files come from dalvik/dx/tests/135-invoke-custom.