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.