diff options
| author | 2017-07-07 20:07:12 +0100 | |
|---|---|---|
| committer | 2017-07-14 13:04:30 +0100 | |
| commit | f8db2c3945e746fcbf307832ac2f7826d5ec178a (patch) | |
| tree | fc579f67f17b2ccbb218889f2484ef6f5013da1c | |
| parent | c5515fd96887f70101640fddf9a3189ff936c08b (diff) | |
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
| -rw-r--r-- | runtime/class_linker.cc | 346 | ||||
| -rw-r--r-- | runtime/class_linker.h | 11 | ||||
| -rw-r--r-- | runtime/mirror/method_handles_lookup.cc | 25 | ||||
| -rw-r--r-- | runtime/mirror/method_handles_lookup.h | 13 | ||||
| -rw-r--r-- | runtime/well_known_classes.cc | 28 | ||||
| -rw-r--r-- | runtime/well_known_classes.h | 4 | ||||
| -rw-r--r-- | test/952-invoke-custom-kinds/classes/invokecustom/InvokeCustom.class | bin | 8737 -> 8831 bytes | |||
| -rw-r--r-- | test/952-invoke-custom-kinds/classes/invokecustom/TestGenerator.class | bin | 8699 -> 8736 bytes | |||
| -rw-r--r-- | test/952-invoke-custom-kinds/expected.txt | 1 | ||||
| -rw-r--r-- | test/952-invoke-custom-kinds/info.txt | 5 |
10 files changed, 273 insertions, 160 deletions
diff --git a/runtime/class_linker.cc b/runtime/class_linker.cc index ca89cee377..a5d4540f88 100644 --- a/runtime/class_linker.cc +++ b/runtime/class_linker.cc @@ -8369,61 +8369,174 @@ mirror::MethodType* ClassLinker::ResolveMethodType(const DexFile& dex_file, 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 */); + is_static = false; + num_params = 2; break; } case DexFile::MethodHandleType::kInstanceGet: { kind = mirror::MethodHandle::Kind::kInstanceGet; - target_field = ResolveField(mh.field_or_method_idx_, referrer, false /* is_static */); + is_static = false; + num_params = 1; + break; + } + case DexFile::MethodHandleType::kInvokeStatic: + case DexFile::MethodHandleType::kInvokeInstance: + case DexFile::MethodHandleType::kInvokeConstructor: + case DexFile::MethodHandleType::kInvokeDirect: + case DexFile::MethodHandleType::kInvokeInterface: + UNREACHABLE(); + } + + 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 (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: { + method_params->Set(0, target_field->GetType<true>()); + return_type = hs.NewHandle(FindPrimitiveClass('V')); break; } + case DexFile::MethodHandleType::kStaticGet: { + return_type = hs.NewHandle(target_field->GetType<true>()); + break; + } + case DexFile::MethodHandleType::kInstancePut: { + method_params->Set(0, target_field->GetDeclaringClass()); + method_params->Set(1, target_field->GetType<true>()); + return_type = hs.NewHandle(FindPrimitiveClass('V')); + break; + } + case DexFile::MethodHandleType::kInstanceGet: { + method_params->Set(0, target_field->GetDeclaringClass()); + return_type = hs.NewHandle(target_field->GetType<true>()); + break; + } + case DexFile::MethodHandleType::kInvokeStatic: + case DexFile::MethodHandleType::kInvokeInstance: + case DexFile::MethodHandleType::kInvokeConstructor: + case DexFile::MethodHandleType::kInvokeDirect: + case DexFile::MethodHandleType::kInvokeInterface: + UNREACHABLE(); + } + + for (int32_t i = 0; i < num_params; ++i) { + if (UNLIKELY(method_params->Get(i) == nullptr)) { + DCHECK(self->IsExceptionPending()); + return nullptr; + } + } + + 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; + } + + 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, - mh.field_or_method_idx_, + 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, - mh.field_or_method_idx_, + method_handle.field_or_method_idx_, referrer, InvokeType::kVirtual); break; } case DexFile::MethodHandleType::kInvokeConstructor: { - UNIMPLEMENTED(FATAL) << "Invoke constructor is implemented as a transform."; + // 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 @@ -8432,26 +8545,26 @@ mirror::MethodHandle* ClassLinker::ResolveMethodHandle(uint32_t method_handle_id // then resolve again specifying the intended invocation type to // force the appropriate checks. target_method = ResolveMethodWithoutInvokeType(*dex_file, - mh.field_or_method_idx_, + method_handle.field_or_method_idx_, hs.NewHandle(referrer->GetDexCache()), hs.NewHandle(referrer->GetClassLoader())); - if (target_method == nullptr) { + if (UNLIKELY(target_method == nullptr)) { break; } if (target_method->IsPrivate()) { kind = mirror::MethodHandle::Kind::kInvokeDirect; target_method = ResolveMethod<kNoICCECheckForCache>(self, - mh.field_or_method_idx_, + method_handle.field_or_method_idx_, referrer, InvokeType::kDirect); } else { kind = mirror::MethodHandle::Kind::kInvokeSuper; target_method = ResolveMethod<kNoICCECheckForCache>(self, - mh.field_or_method_idx_, + method_handle.field_or_method_idx_, referrer, InvokeType::kSuper); - if (target_method == nullptr) { + if (UNLIKELY(target_method == nullptr)) { break; } // Find the method specified in the parent in referring class @@ -8465,75 +8578,35 @@ mirror::MethodHandle* ClassLinker::ResolveMethodHandle(uint32_t method_handle_id } case DexFile::MethodHandleType::kInvokeInterface: { kind = mirror::MethodHandle::Kind::kInvokeInterface; + receiver_count = 1; target_method = ResolveMethod<kNoICCECheckForCache>(self, - mh.field_or_method_idx_, + method_handle.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. + if (UNLIKELY(target_method == nullptr)) { 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: { - num_params = 2; - break; - } - case DexFile::MethodHandleType::kInstanceGet: { - 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::kInvokeInstance: - 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; - } + 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; } - StackHandleScope<5> hs(self); + // 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( @@ -8543,81 +8616,70 @@ mirror::MethodHandle* ClassLinker::ResolveMethodHandle(uint32_t method_handle_id return nullptr; } - Handle<mirror::Class> return_type; - switch (handle_type) { - case DexFile::MethodHandleType::kStaticPut: { - method_params->Set(0, target_field->GetType<true>()); - return_type = hs.NewHandle(FindPrimitiveClass('V')); - break; - } - case DexFile::MethodHandleType::kStaticGet: { - return_type = hs.NewHandle(target_field->GetType<true>()); - break; - } - case DexFile::MethodHandleType::kInstancePut: { - method_params->Set(0, target_field->GetDeclaringClass()); - method_params->Set(1, target_field->GetType<true>()); - return_type = hs.NewHandle(FindPrimitiveClass('V')); - break; - } - case DexFile::MethodHandleType::kInstanceGet: { - method_params->Set(0, target_field->GetDeclaringClass()); - return_type = hs.NewHandle(target_field->GetType<true>()); - break; - } - case DexFile::MethodHandleType::kInvokeDirect: - case DexFile::MethodHandleType::kInvokeInstance: - 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."; + 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(); } - if (return_type.IsNull()) { + Handle<mirror::Class> return_type = hs.NewHandle(target_method->GetReturnType(true)); + 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); + 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); } - return mirror::MethodHandleImpl::Create(self, target, kind, mt); } bool ClassLinker::IsQuickResolutionStub(const void* entry_point) const { diff --git a/runtime/class_linker.h b/runtime/class_linker.h index 00ae7582c3..8b8a6fd420 100644 --- a/runtime/class_linker.h +++ b/runtime/class_linker.h @@ -944,6 +944,17 @@ class ClassLinker { 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 0c25fa8ba0..9eada6dfdd 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 @@ MethodHandlesLookup* MethodHandlesLookup::Create(Thread* const self, Handle<Clas 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 63eb428f94..2109f601ee 100644 --- a/runtime/mirror/method_handles_lookup.h +++ b/runtime/mirror/method_handles_lookup.h @@ -30,6 +30,9 @@ class RootVisitor; namespace mirror { +class MethodHandle; +class MethodType; + // C++ mirror of java.lang.invoke.MethodHandles.Lookup class MANAGED MethodHandlesLookup : public Object { public: @@ -45,6 +48,16 @@ class MANAGED MethodHandlesLookup : public Object { 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 8d505e2582..f72fdb4b2a 100644 --- a/runtime/well_known_classes.cc +++ b/runtime/well_known_classes.cc @@ -94,6 +94,8 @@ jmethodID WellKnownClasses::java_lang_Float_valueOf; 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 @@ static jfieldID CacheField(JNIEnv* env, jclass c, bool is_static, 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 @@ jmethodID CacheMethod(JNIEnv* env, jclass c, bool is_static, 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 @@ void WellKnownClasses::Init(JNIEnv* env) { 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 c5a16c1c76..2f2f1ad3f4 100644 --- a/runtime/well_known_classes.h +++ b/runtime/well_known_classes.h @@ -33,8 +33,6 @@ class Class; // 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 @@ struct WellKnownClasses { 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 Binary files differindex a37a49bffa..b8dcd5559a 100644 --- a/test/952-invoke-custom-kinds/classes/invokecustom/InvokeCustom.class +++ b/test/952-invoke-custom-kinds/classes/invokecustom/InvokeCustom.class diff --git a/test/952-invoke-custom-kinds/classes/invokecustom/TestGenerator.class b/test/952-invoke-custom-kinds/classes/invokecustom/TestGenerator.class Binary files differindex aa7e5216a4..03dc23396c 100644 --- a/test/952-invoke-custom-kinds/classes/invokecustom/TestGenerator.class +++ b/test/952-invoke-custom-kinds/classes/invokecustom/TestGenerator.class diff --git a/test/952-invoke-custom-kinds/expected.txt b/test/952-invoke-custom-kinds/expected.txt index 55e1d0bd2f..c41b5c6d88 100644 --- a/test/952-invoke-custom-kinds/expected.txt +++ b/test/952-invoke-custom-kinds/expected.txt @@ -34,6 +34,7 @@ targetMethodTest9 ()void 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 cddb96dcf0..33b4cffc1d 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. |