diff options
-rw-r--r-- | runtime/dex_file_annotations.cc | 60 | ||||
-rw-r--r-- | runtime/dex_file_annotations.h | 5 | ||||
-rw-r--r-- | runtime/native/java_lang_reflect_Executable.cc | 109 | ||||
-rw-r--r-- | runtime/well_known_classes.cc | 6 | ||||
-rw-r--r-- | runtime/well_known_classes.h | 3 |
5 files changed, 179 insertions, 4 deletions
diff --git a/runtime/dex_file_annotations.cc b/runtime/dex_file_annotations.cc index c6c87fdf36..e0d5337660 100644 --- a/runtime/dex_file_annotations.cc +++ b/runtime/dex_file_annotations.cc @@ -1027,6 +1027,66 @@ mirror::Object* GetAnnotationForMethodParameter(ArtMethod* method, annotation_class); } +bool GetParametersMetadataForMethod(ArtMethod* method, + MutableHandle<mirror::ObjectArray<mirror::String>>* names, + MutableHandle<mirror::IntArray>* access_flags) { + const DexFile::AnnotationSetItem::AnnotationSetItem* annotation_set = + FindAnnotationSetForMethod(method); + if (annotation_set == nullptr) { + return false; + } + + const DexFile* dex_file = method->GetDexFile(); + const DexFile::AnnotationItem* annotation_item = + SearchAnnotationSet(*dex_file, + annotation_set, + "Ldalvik/annotation/MethodParameters;", + DexFile::kDexVisibilitySystem); + if (annotation_item == nullptr) { + return false; + } + + StackHandleScope<5> hs(Thread::Current()); + + // Extract the parameters' names String[]. + mirror::Class* string_class = mirror::String::GetJavaLangString(); + Handle<mirror::Class> string_array_class(hs.NewHandle( + Runtime::Current()->GetClassLinker()->FindArrayClass(Thread::Current(), &string_class))); + if (UNLIKELY(string_array_class.Get() == nullptr)) { + return false; + } + + Handle<mirror::Class> klass = hs.NewHandle(method->GetDeclaringClass()); + Handle<mirror::Object> names_obj = + hs.NewHandle(GetAnnotationValue(klass, + annotation_item, + "names", + string_array_class, + DexFile::kDexAnnotationArray)); + if (names_obj.Get() == nullptr) { + return false; + } + + // Extract the parameters' access flags int[]. + Handle<mirror::Class> int_array_class(hs.NewHandle(mirror::IntArray::GetArrayClass())); + if (UNLIKELY(int_array_class.Get() == nullptr)) { + return false; + } + Handle<mirror::Object> access_flags_obj = + hs.NewHandle(GetAnnotationValue(klass, + annotation_item, + "accessFlags", + int_array_class, + DexFile::kDexAnnotationArray)); + if (access_flags_obj.Get() == nullptr) { + return false; + } + + names->Assign(names_obj.Get()->AsObjectArray<mirror::String>()); + access_flags->Assign(access_flags_obj.Get()->AsIntArray()); + return true; +} + mirror::ObjectArray<mirror::String>* GetSignatureAnnotationForMethod(ArtMethod* method) { const DexFile::AnnotationSetItem* annotation_set = FindAnnotationSetForMethod(method); if (annotation_set == nullptr) { diff --git a/runtime/dex_file_annotations.h b/runtime/dex_file_annotations.h index 7b4e8564b0..c66c5bdb8b 100644 --- a/runtime/dex_file_annotations.h +++ b/runtime/dex_file_annotations.h @@ -30,6 +30,7 @@ namespace mirror { class ArtField; class ArtMethod; class ClassLinker; +template<class T> class MutableHandle; namespace annotations { @@ -58,6 +59,10 @@ mirror::Object* GetAnnotationForMethodParameter(ArtMethod* method, uint32_t parameter_idx, Handle<mirror::Class> annotation_class) REQUIRES_SHARED(Locks::mutator_lock_); +bool GetParametersMetadataForMethod(ArtMethod* method, + MutableHandle<mirror::ObjectArray<mirror::String>>* names, + MutableHandle<mirror::IntArray>* access_flags) + REQUIRES_SHARED(Locks::mutator_lock_); mirror::ObjectArray<mirror::String>* GetSignatureAnnotationForMethod(ArtMethod* method) REQUIRES_SHARED(Locks::mutator_lock_); bool IsMethodAnnotationPresent(ArtMethod* method, Handle<mirror::Class> annotation_class, diff --git a/runtime/native/java_lang_reflect_Executable.cc b/runtime/native/java_lang_reflect_Executable.cc index 8fcf6aca08..f345c098e0 100644 --- a/runtime/native/java_lang_reflect_Executable.cc +++ b/runtime/native/java_lang_reflect_Executable.cc @@ -18,8 +18,10 @@ #include "art_method-inl.h" #include "dex_file_annotations.h" +#include "handle.h" #include "jni_internal.h" #include "mirror/class-inl.h" +#include "mirror/method.h" #include "mirror/object-inl.h" #include "mirror/object_array-inl.h" #include "reflection.h" @@ -43,8 +45,8 @@ static jobjectArray Executable_getDeclaredAnnotationsNative(JNIEnv* env, jobject } static jobject Executable_getAnnotationNative(JNIEnv* env, - jobject javaMethod, - jclass annotationType) { + jobject javaMethod, + jclass annotationType) { ScopedFastNativeObjectAccess soa(env); StackHandleScope<1> hs(soa.Self()); ArtMethod* method = ArtMethod::FromReflectedMethod(soa, javaMethod); @@ -77,9 +79,107 @@ static jobjectArray Executable_getParameterAnnotationsNative(JNIEnv* env, jobjec } } +static jobjectArray Executable_getParameters0(JNIEnv* env, jobject javaMethod) { + ScopedFastNativeObjectAccess soa(env); + Thread* self = soa.Self(); + StackHandleScope<8> hs(self); + + Handle<mirror::Method> executable = hs.NewHandle(soa.Decode<mirror::Method*>(javaMethod)); + ArtMethod* art_method = executable.Get()->GetArtMethod(); + if (art_method->GetDeclaringClass()->IsProxyClass()) { + return nullptr; + } + + // Find the MethodParameters system annotation. + MutableHandle<mirror::ObjectArray<mirror::String>> names = + hs.NewHandle<mirror::ObjectArray<mirror::String>>(nullptr); + MutableHandle<mirror::IntArray> access_flags = hs.NewHandle<mirror::IntArray>(nullptr); + if (!annotations::GetParametersMetadataForMethod(art_method, &names, &access_flags)) { + return nullptr; + } + + // Validate the MethodParameters system annotation data. + if (UNLIKELY(names.Get() == nullptr || access_flags.Get() == nullptr)) { + ThrowIllegalArgumentException( + StringPrintf("Missing parameter metadata for names or access flags for %s", + PrettyMethod(art_method).c_str()).c_str()); + return nullptr; + } + + // Check array sizes match each other + int32_t names_count = names.Get()->GetLength(); + int32_t access_flags_count = access_flags.Get()->GetLength(); + if (names_count != access_flags_count) { + ThrowIllegalArgumentException( + StringPrintf( + "Inconsistent parameter metadata for %s. names length: %d, access flags length: %d", + PrettyMethod(art_method).c_str(), + names_count, + access_flags_count).c_str()); + return nullptr; + } + + // Instantiate a Parameter[] to hold the result. + Handle<mirror::Class> parameter_array_class = + hs.NewHandle( + soa.Decode<mirror::Class*>(WellKnownClasses::java_lang_reflect_Parameter__array)); + Handle<mirror::ObjectArray<mirror::Object>> parameter_array = + hs.NewHandle( + mirror::ObjectArray<mirror::Object>::Alloc(self, + parameter_array_class.Get(), + names_count)); + if (UNLIKELY(parameter_array.Get() == nullptr)) { + self->AssertPendingException(); + return nullptr; + } + + Handle<mirror::Class> parameter_class = + hs.NewHandle(soa.Decode<mirror::Class*>(WellKnownClasses::java_lang_reflect_Parameter)); + ArtMethod* parameter_init = + soa.DecodeMethod(WellKnownClasses::java_lang_reflect_Parameter_init); + + // Mutable handles used in the loop below to ensure cleanup without scaling the number of + // handles by the number of parameters. + MutableHandle<mirror::String> name = hs.NewHandle<mirror::String>(nullptr); + MutableHandle<mirror::Object> parameter = hs.NewHandle<mirror::Object>(nullptr); + + // Populate the Parameter[] to return. + for (int32_t parameter_index = 0; parameter_index < names_count; parameter_index++) { + name.Assign(names.Get()->Get(parameter_index)); + int32_t modifiers = access_flags.Get()->Get(parameter_index); + + // Allocate / initialize the Parameter to add to parameter_array. + parameter.Assign(parameter_class->AllocObject(self)); + if (UNLIKELY(parameter.Get() == nullptr)) { + self->AssertPendingOOMException(); + return nullptr; + } + + uint32_t args[5] = { PointerToLowMemUInt32(parameter.Get()), + PointerToLowMemUInt32(name.Get()), + static_cast<uint32_t>(modifiers), + PointerToLowMemUInt32(executable.Get()), + static_cast<uint32_t>(parameter_index) + }; + JValue result; + static const char* method_signature = "VLILI"; // return + parameter types + parameter_init->Invoke(self, args, sizeof(args), &result, method_signature); + if (UNLIKELY(self->IsExceptionPending())) { + return nullptr; + } + + // Store the Parameter in the Parameter[]. + parameter_array.Get()->Set(parameter_index, parameter.Get()); + if (UNLIKELY(self->IsExceptionPending())) { + return nullptr; + } + } + return soa.AddLocalReference<jobjectArray>(parameter_array.Get()); +} + static jboolean Executable_isAnnotationPresentNative(JNIEnv* env, - jobject javaMethod, - jclass annotationType) { + jobject javaMethod, + jclass annotationType) { ScopedFastNativeObjectAccess soa(env); ArtMethod* method = ArtMethod::FromReflectedMethod(soa, javaMethod); if (method->GetDeclaringClass()->IsProxyClass()) { @@ -96,6 +196,7 @@ static JNINativeMethod gMethods[] = { NATIVE_METHOD(Executable, getDeclaredAnnotationsNative, "!()[Ljava/lang/annotation/Annotation;"), NATIVE_METHOD(Executable, getParameterAnnotationsNative, "!()[[Ljava/lang/annotation/Annotation;"), + NATIVE_METHOD(Executable, getParameters0, "!()[Ljava/lang/reflect/Parameter;"), NATIVE_METHOD(Executable, getSignatureAnnotation, "!()[Ljava/lang/String;"), NATIVE_METHOD(Executable, isAnnotationPresentNative, "!(Ljava/lang/Class;)Z"), }; diff --git a/runtime/well_known_classes.cc b/runtime/well_known_classes.cc index 6b569f410c..e5216fbcff 100644 --- a/runtime/well_known_classes.cc +++ b/runtime/well_known_classes.cc @@ -53,6 +53,8 @@ jclass WellKnownClasses::java_lang_reflect_Constructor; jclass WellKnownClasses::java_lang_reflect_Executable; jclass WellKnownClasses::java_lang_reflect_Field; jclass WellKnownClasses::java_lang_reflect_Method; +jclass WellKnownClasses::java_lang_reflect_Parameter; +jclass WellKnownClasses::java_lang_reflect_Parameter__array; jclass WellKnownClasses::java_lang_reflect_Proxy; jclass WellKnownClasses::java_lang_RuntimeException; jclass WellKnownClasses::java_lang_StackOverflowError; @@ -87,6 +89,7 @@ jmethodID WellKnownClasses::java_lang_Integer_valueOf; jmethodID WellKnownClasses::java_lang_Long_valueOf; jmethodID WellKnownClasses::java_lang_ref_FinalizerReference_add; jmethodID WellKnownClasses::java_lang_ref_ReferenceQueue_add; +jmethodID WellKnownClasses::java_lang_reflect_Parameter_init; jmethodID WellKnownClasses::java_lang_reflect_Proxy_invoke; jmethodID WellKnownClasses::java_lang_Runtime_nativeLoad; jmethodID WellKnownClasses::java_lang_Short_valueOf; @@ -280,6 +283,8 @@ void WellKnownClasses::Init(JNIEnv* env) { java_lang_reflect_Executable = CacheClass(env, "java/lang/reflect/Executable"); java_lang_reflect_Field = CacheClass(env, "java/lang/reflect/Field"); java_lang_reflect_Method = CacheClass(env, "java/lang/reflect/Method"); + java_lang_reflect_Parameter = CacheClass(env, "java/lang/reflect/Parameter"); + java_lang_reflect_Parameter__array = CacheClass(env, "[Ljava/lang/reflect/Parameter;"); java_lang_reflect_Proxy = CacheClass(env, "java/lang/reflect/Proxy"); java_lang_RuntimeException = CacheClass(env, "java/lang/RuntimeException"); java_lang_StackOverflowError = CacheClass(env, "java/lang/StackOverflowError"); @@ -312,6 +317,7 @@ void WellKnownClasses::Init(JNIEnv* env) { 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_reflect_Parameter_init = CacheMethod(env, java_lang_reflect_Parameter, false, "<init>", "(Ljava/lang/String;ILjava/lang/reflect/Executable;I)V"); java_lang_reflect_Proxy_invoke = CacheMethod(env, java_lang_reflect_Proxy, true, "invoke", "(Ljava/lang/reflect/Proxy;Ljava/lang/reflect/Method;[Ljava/lang/Object;)Ljava/lang/Object;"); java_lang_Thread_dispatchUncaughtException = CacheMethod(env, java_lang_Thread, false, "dispatchUncaughtException", "(Ljava/lang/Throwable;)V"); java_lang_Thread_init = CacheMethod(env, java_lang_Thread, false, "<init>", "(Ljava/lang/ThreadGroup;Ljava/lang/String;IZ)V"); diff --git a/runtime/well_known_classes.h b/runtime/well_known_classes.h index c9110e60d8..ddfc5b80f7 100644 --- a/runtime/well_known_classes.h +++ b/runtime/well_known_classes.h @@ -67,6 +67,8 @@ struct WellKnownClasses { static jclass java_lang_reflect_Executable; static jclass java_lang_reflect_Field; static jclass java_lang_reflect_Method; + static jclass java_lang_reflect_Parameter; + static jclass java_lang_reflect_Parameter__array; static jclass java_lang_reflect_Proxy; static jclass java_lang_RuntimeException; static jclass java_lang_StackOverflowError; @@ -101,6 +103,7 @@ struct WellKnownClasses { static jmethodID java_lang_Long_valueOf; static jmethodID java_lang_ref_FinalizerReference_add; static jmethodID java_lang_ref_ReferenceQueue_add; + static jmethodID java_lang_reflect_Parameter_init; static jmethodID java_lang_reflect_Proxy_invoke; static jmethodID java_lang_Runtime_nativeLoad; static jmethodID java_lang_Short_valueOf; |