diff options
author | Mathieu Chartier <mathieuc@google.com> | 2015-04-16 18:00:39 -0700 |
---|---|---|
committer | Mathieu Chartier <mathieuc@google.com> | 2015-04-21 15:51:29 -0700 |
commit | fc58af45e342ba9e18bbdf597f205a58ec731658 (patch) | |
tree | 3f93906235cb4d2462d237223b72ccf4eedef645 /runtime | |
parent | bbf02afc641a393d33342976e269218668c07386 (diff) | |
download | art-fc58af45e342ba9e18bbdf597f205a58ec731658.zip art-fc58af45e342ba9e18bbdf597f205a58ec731658.tar.gz art-fc58af45e342ba9e18bbdf597f205a58ec731658.tar.bz2 |
Add AbstractMethod, Constructor, Method
Moves functionality to ART from libcore. Precursor to moving
ArtMethods to native. Mostly performance improvements.
N5 perf before (irrelevant results removed):
Class_getConstructor 962.87 ===========
Class_getDeclaredMethod 2394.37 ============================
Class_getMethod 2509.20 ==============================
Class_newInstance 1999.81 =======================
Method_invokeI 1439.02 =================
Method_invokePreBoxedI 1415.82 ================
Method_invokeStaticI 1456.24 =================
Method_invokeStaticPreBoxedI 1427.32 =================
Method_invokeStaticV 814.47 =========
Method_invokeV 816.56 =========
After:
benchmark ns linear runtime
Class_getConstructor 1302.04 ================
Class_getDeclaredMethod 1459.01 ==================
Class_getMethod 1560.40 ===================
Class_newInstance 2029.94 =========================
Method_invokeI 1312.89 ================
Method_invokePreBoxedI 1255.01 ===============
Method_invokeStaticI 1289.13 ===============
Method_invokeStaticPreBoxedI 1196.52 ==============
Method_invokeStaticV 790.82 =========
Method_invokeV 791.73 =========
Performance improvements are more than just fixing regressions introduced
in: http://android-review.googlesource.com/#/c/146069/
Bug: 19264997
Change-Id: Ife79c469fdb09f30e3aefcfc3e0ce5ed32303fce
Diffstat (limited to 'runtime')
26 files changed, 911 insertions, 300 deletions
diff --git a/runtime/Android.mk b/runtime/Android.mk index d3488fc..86201ba 100644 --- a/runtime/Android.mk +++ b/runtime/Android.mk @@ -100,11 +100,13 @@ LIBART_COMMON_SRC_FILES := \ linear_alloc.cc \ mem_map.cc \ memory_region.cc \ + mirror/abstract_method.cc \ mirror/art_method.cc \ mirror/array.cc \ mirror/class.cc \ mirror/dex_cache.cc \ mirror/field.cc \ + mirror/method.cc \ mirror/object.cc \ mirror/reference.cc \ mirror/stack_trace_element.cc \ diff --git a/runtime/class_linker.cc b/runtime/class_linker.cc index 4e59217..85b245f 100644 --- a/runtime/class_linker.cc +++ b/runtime/class_linker.cc @@ -59,6 +59,7 @@ #include "mirror/dex_cache-inl.h" #include "mirror/field.h" #include "mirror/iftable-inl.h" +#include "mirror/method.h" #include "mirror/object-inl.h" #include "mirror/object_array-inl.h" #include "mirror/proxy.h" @@ -258,8 +259,8 @@ void ClassLinker::InitWithoutImage(std::vector<std::unique_ptr<const DexFile>> b CHECK(!init_done_); // java_lang_Class comes first, it's needed for AllocClass - Thread* self = Thread::Current(); - gc::Heap* heap = Runtime::Current()->GetHeap(); + Thread* const self = Thread::Current(); + gc::Heap* const heap = Runtime::Current()->GetHeap(); // The GC can't handle an object with a null class since we can't get the size of this object. heap->IncrementDisableMovingGC(self); StackHandleScope<64> hs(self); // 64 is picked arbitrarily. @@ -436,20 +437,19 @@ void ClassLinker::InitWithoutImage(std::vector<std::unique_ptr<const DexFile>> b // Object, String and DexCache need to be rerun through FindSystemClass to finish init mirror::Class::SetStatus(java_lang_Object, mirror::Class::kStatusNotReady, self); - mirror::Class* Object_class = FindSystemClass(self, "Ljava/lang/Object;"); - CHECK_EQ(java_lang_Object.Get(), Object_class); + CHECK_EQ(java_lang_Object.Get(), FindSystemClass(self, "Ljava/lang/Object;")); CHECK_EQ(java_lang_Object->GetObjectSize(), mirror::Object::InstanceSize()); mirror::Class::SetStatus(java_lang_String, mirror::Class::kStatusNotReady, self); mirror::Class* String_class = FindSystemClass(self, "Ljava/lang/String;"); - std::ostringstream os1, os2; - java_lang_String->DumpClass(os1, mirror::Class::kDumpClassFullDetail); - String_class->DumpClass(os2, mirror::Class::kDumpClassFullDetail); - CHECK_EQ(java_lang_String.Get(), String_class) << os1.str() << "\n\n" << os2.str(); + if (java_lang_String.Get() != String_class) { + std::ostringstream os1, os2; + java_lang_String->DumpClass(os1, mirror::Class::kDumpClassFullDetail); + String_class->DumpClass(os2, mirror::Class::kDumpClassFullDetail); + LOG(FATAL) << os1.str() << "\n\n" << os2.str(); + } CHECK_EQ(java_lang_String->GetObjectSize(), mirror::String::InstanceSize()); mirror::Class::SetStatus(java_lang_DexCache, mirror::Class::kStatusNotReady, self); - mirror::Class* DexCache_class = FindSystemClass(self, "Ljava/lang/DexCache;"); - CHECK_EQ(java_lang_String.Get(), String_class); - CHECK_EQ(java_lang_DexCache.Get(), DexCache_class); + CHECK_EQ(java_lang_DexCache.Get(), FindSystemClass(self, "Ljava/lang/DexCache;")); CHECK_EQ(java_lang_DexCache->GetObjectSize(), mirror::DexCache::InstanceSize()); // Setup the primitive array type classes - can't be done until Object has a vtable. @@ -459,17 +459,14 @@ void ClassLinker::InitWithoutImage(std::vector<std::unique_ptr<const DexFile>> b SetClassRoot(kByteArrayClass, FindSystemClass(self, "[B")); mirror::ByteArray::SetArrayClass(GetClassRoot(kByteArrayClass)); - mirror::Class* found_char_array_class = FindSystemClass(self, "[C"); - CHECK_EQ(char_array_class.Get(), found_char_array_class); + CHECK_EQ(char_array_class.Get(), FindSystemClass(self, "[C")); SetClassRoot(kShortArrayClass, FindSystemClass(self, "[S")); mirror::ShortArray::SetArrayClass(GetClassRoot(kShortArrayClass)); - mirror::Class* found_int_array_class = FindSystemClass(self, "[I"); - CHECK_EQ(int_array_class.Get(), found_int_array_class); + CHECK_EQ(int_array_class.Get(), FindSystemClass(self, "[I")); - mirror::Class* found_long_array_class = FindSystemClass(self, "[J"); - CHECK_EQ(long_array_class.Get(), found_long_array_class); + CHECK_EQ(long_array_class.Get(), FindSystemClass(self, "[J")); SetClassRoot(kFloatArrayClass, FindSystemClass(self, "[F")); mirror::FloatArray::SetArrayClass(GetClassRoot(kFloatArrayClass)); @@ -477,97 +474,101 @@ void ClassLinker::InitWithoutImage(std::vector<std::unique_ptr<const DexFile>> b SetClassRoot(kDoubleArrayClass, FindSystemClass(self, "[D")); mirror::DoubleArray::SetArrayClass(GetClassRoot(kDoubleArrayClass)); - mirror::Class* found_class_array_class = FindSystemClass(self, "[Ljava/lang/Class;"); - CHECK_EQ(class_array_class.Get(), found_class_array_class); + CHECK_EQ(class_array_class.Get(), FindSystemClass(self, "[Ljava/lang/Class;")); - mirror::Class* found_object_array_class = FindSystemClass(self, "[Ljava/lang/Object;"); - CHECK_EQ(object_array_class.Get(), found_object_array_class); + CHECK_EQ(object_array_class.Get(), FindSystemClass(self, "[Ljava/lang/Object;")); // Setup the single, global copy of "iftable". - mirror::Class* java_lang_Cloneable = FindSystemClass(self, "Ljava/lang/Cloneable;"); - CHECK(java_lang_Cloneable != nullptr); - mirror::Class* java_io_Serializable = FindSystemClass(self, "Ljava/io/Serializable;"); - CHECK(java_io_Serializable != nullptr); + auto java_lang_Cloneable = hs.NewHandle(FindSystemClass(self, "Ljava/lang/Cloneable;")); + CHECK(java_lang_Cloneable.Get() != nullptr); + auto java_io_Serializable = hs.NewHandle(FindSystemClass(self, "Ljava/io/Serializable;")); + CHECK(java_io_Serializable.Get() != nullptr); // We assume that Cloneable/Serializable don't have superinterfaces -- normally we'd have to // crawl up and explicitly list all of the supers as well. - { - mirror::IfTable* array_iftable = array_iftable_.Read(); - array_iftable->SetInterface(0, java_lang_Cloneable); - array_iftable->SetInterface(1, java_io_Serializable); - } - - // Sanity check Class[] and Object[]'s interfaces. - CHECK_EQ(java_lang_Cloneable, mirror::Class::GetDirectInterface(self, class_array_class, 0)); - CHECK_EQ(java_io_Serializable, mirror::Class::GetDirectInterface(self, class_array_class, 1)); - CHECK_EQ(java_lang_Cloneable, mirror::Class::GetDirectInterface(self, object_array_class, 0)); - CHECK_EQ(java_io_Serializable, mirror::Class::GetDirectInterface(self, object_array_class, 1)); + array_iftable_.Read()->SetInterface(0, java_lang_Cloneable.Get()); + array_iftable_.Read()->SetInterface(1, java_io_Serializable.Get()); + + // Sanity check Class[] and Object[]'s interfaces. GetDirectInterface may cause thread + // suspension. + CHECK_EQ(java_lang_Cloneable.Get(), + mirror::Class::GetDirectInterface(self, class_array_class, 0)); + CHECK_EQ(java_io_Serializable.Get(), + mirror::Class::GetDirectInterface(self, class_array_class, 1)); + CHECK_EQ(java_lang_Cloneable.Get(), + mirror::Class::GetDirectInterface(self, object_array_class, 0)); + CHECK_EQ(java_io_Serializable.Get(), + mirror::Class::GetDirectInterface(self, object_array_class, 1)); // Run Class, ArtField, and ArtMethod through FindSystemClass. This initializes their // dex_cache_ fields and register them in class_table_. - mirror::Class* Class_class = FindSystemClass(self, "Ljava/lang/Class;"); - CHECK_EQ(java_lang_Class.Get(), Class_class); + CHECK_EQ(java_lang_Class.Get(), FindSystemClass(self, "Ljava/lang/Class;")); mirror::Class::SetStatus(java_lang_reflect_ArtMethod, mirror::Class::kStatusNotReady, self); - mirror::Class* Art_method_class = FindSystemClass(self, "Ljava/lang/reflect/ArtMethod;"); - CHECK_EQ(java_lang_reflect_ArtMethod.Get(), Art_method_class); - - mirror::Class* String_array_class = - FindSystemClass(self, GetClassRootDescriptor(kJavaLangStringArrayClass)); - CHECK_EQ(object_array_string.Get(), String_array_class); - - mirror::Class* Art_method_array_class = - FindSystemClass(self, GetClassRootDescriptor(kJavaLangReflectArtMethodArrayClass)); - CHECK_EQ(object_array_art_method.Get(), Art_method_array_class); + CHECK_EQ(java_lang_reflect_ArtMethod.Get(), + FindSystemClass(self, "Ljava/lang/reflect/ArtMethod;")); + CHECK_EQ(object_array_string.Get(), + FindSystemClass(self, GetClassRootDescriptor(kJavaLangStringArrayClass))); + CHECK_EQ(object_array_art_method.Get(), + FindSystemClass(self, GetClassRootDescriptor(kJavaLangReflectArtMethodArrayClass))); // End of special init trickery, subsequent classes may be loaded via FindSystemClass. // Create java.lang.reflect.Proxy root. - mirror::Class* java_lang_reflect_Proxy = FindSystemClass(self, "Ljava/lang/reflect/Proxy;"); - SetClassRoot(kJavaLangReflectProxy, java_lang_reflect_Proxy); + SetClassRoot(kJavaLangReflectProxy, FindSystemClass(self, "Ljava/lang/reflect/Proxy;")); // Create java.lang.reflect.Field.class root. - mirror::Class* java_lang_reflect_Field = FindSystemClass(self, "Ljava/lang/reflect/Field;"); - CHECK(java_lang_reflect_Field != nullptr); - SetClassRoot(kJavaLangReflectField, java_lang_reflect_Field); - mirror::Field::SetClass(java_lang_reflect_Field); + auto* class_root = FindSystemClass(self, "Ljava/lang/reflect/Field;"); + CHECK(class_root != nullptr); + SetClassRoot(kJavaLangReflectField, class_root); + mirror::Field::SetClass(class_root); // Create java.lang.reflect.Field array root. - mirror::Class* java_lang_reflect_Field_array = - FindSystemClass(self, "[Ljava/lang/reflect/Field;"); - CHECK(java_lang_reflect_Field_array != nullptr); - SetClassRoot(kJavaLangReflectFieldArrayClass, java_lang_reflect_Field_array); - mirror::Field::SetArrayClass(java_lang_reflect_Field_array); + class_root = FindSystemClass(self, "[Ljava/lang/reflect/Field;"); + CHECK(class_root != nullptr); + SetClassRoot(kJavaLangReflectFieldArrayClass, class_root); + mirror::Field::SetArrayClass(class_root); + + // Create java.lang.reflect.Constructor.class root and array root. + class_root = FindSystemClass(self, "Ljava/lang/reflect/Constructor;"); + CHECK(class_root != nullptr); + SetClassRoot(kJavaLangReflectConstructor, class_root); + mirror::Constructor::SetClass(class_root); + class_root = FindSystemClass(self, "[Ljava/lang/reflect/Constructor;"); + CHECK(class_root != nullptr); + SetClassRoot(kJavaLangReflectConstructorArrayClass, class_root); + mirror::Constructor::SetArrayClass(class_root); + + // Create java.lang.reflect.Method.class root and array root. + class_root = FindSystemClass(self, "Ljava/lang/reflect/Method;"); + CHECK(class_root != nullptr); + SetClassRoot(kJavaLangReflectMethod, class_root); + mirror::Method::SetClass(class_root); + class_root = FindSystemClass(self, "[Ljava/lang/reflect/Method;"); + CHECK(class_root != nullptr); + SetClassRoot(kJavaLangReflectMethodArrayClass, class_root); + mirror::Method::SetArrayClass(class_root); // java.lang.ref classes need to be specially flagged, but otherwise are normal classes // finish initializing Reference class mirror::Class::SetStatus(java_lang_ref_Reference, mirror::Class::kStatusNotReady, self); - mirror::Class* Reference_class = FindSystemClass(self, "Ljava/lang/ref/Reference;"); - CHECK_EQ(java_lang_ref_Reference.Get(), Reference_class); + CHECK_EQ(java_lang_ref_Reference.Get(), FindSystemClass(self, "Ljava/lang/ref/Reference;")); CHECK_EQ(java_lang_ref_Reference->GetObjectSize(), mirror::Reference::InstanceSize()); CHECK_EQ(java_lang_ref_Reference->GetClassSize(), mirror::Reference::ClassSize()); - mirror::Class* java_lang_ref_FinalizerReference = - FindSystemClass(self, "Ljava/lang/ref/FinalizerReference;"); - java_lang_ref_FinalizerReference->SetAccessFlags( - java_lang_ref_FinalizerReference->GetAccessFlags() | - kAccClassIsReference | kAccClassIsFinalizerReference); - mirror::Class* java_lang_ref_PhantomReference = - FindSystemClass(self, "Ljava/lang/ref/PhantomReference;"); - java_lang_ref_PhantomReference->SetAccessFlags( - java_lang_ref_PhantomReference->GetAccessFlags() | - kAccClassIsReference | kAccClassIsPhantomReference); - mirror::Class* java_lang_ref_SoftReference = - FindSystemClass(self, "Ljava/lang/ref/SoftReference;"); - java_lang_ref_SoftReference->SetAccessFlags( - java_lang_ref_SoftReference->GetAccessFlags() | kAccClassIsReference); - mirror::Class* java_lang_ref_WeakReference = - FindSystemClass(self, "Ljava/lang/ref/WeakReference;"); - java_lang_ref_WeakReference->SetAccessFlags( - java_lang_ref_WeakReference->GetAccessFlags() | - kAccClassIsReference | kAccClassIsWeakReference); + class_root = FindSystemClass(self, "Ljava/lang/ref/FinalizerReference;"); + class_root->SetAccessFlags(class_root->GetAccessFlags() | + kAccClassIsReference | kAccClassIsFinalizerReference); + class_root = FindSystemClass(self, "Ljava/lang/ref/PhantomReference;"); + class_root->SetAccessFlags(class_root->GetAccessFlags() | kAccClassIsReference | + kAccClassIsPhantomReference); + class_root = FindSystemClass(self, "Ljava/lang/ref/SoftReference;"); + class_root->SetAccessFlags(class_root->GetAccessFlags() | kAccClassIsReference); + class_root = FindSystemClass(self, "Ljava/lang/ref/WeakReference;"); + class_root->SetAccessFlags(class_root->GetAccessFlags() | kAccClassIsReference | + kAccClassIsWeakReference); // Setup the ClassLoader, verifying the object_size_. - mirror::Class* java_lang_ClassLoader = FindSystemClass(self, "Ljava/lang/ClassLoader;"); - CHECK_EQ(java_lang_ClassLoader->GetObjectSize(), mirror::ClassLoader::InstanceSize()); - SetClassRoot(kJavaLangClassLoader, java_lang_ClassLoader); + class_root = FindSystemClass(self, "Ljava/lang/ClassLoader;"); + CHECK_EQ(class_root->GetObjectSize(), mirror::ClassLoader::InstanceSize()); + SetClassRoot(kJavaLangClassLoader, class_root); // Set up java.lang.Throwable, java.lang.ClassNotFoundException, and // java.lang.StackTraceElement as a convenience. @@ -911,6 +912,10 @@ void ClassLinker::InitFromImage() { // String class root was set above mirror::Field::SetClass(GetClassRoot(kJavaLangReflectField)); mirror::Field::SetArrayClass(GetClassRoot(kJavaLangReflectFieldArrayClass)); + mirror::Constructor::SetClass(GetClassRoot(kJavaLangReflectConstructor)); + mirror::Constructor::SetArrayClass(GetClassRoot(kJavaLangReflectConstructorArrayClass)); + mirror::Method::SetClass(GetClassRoot(kJavaLangReflectMethod)); + mirror::Method::SetArrayClass(GetClassRoot(kJavaLangReflectMethodArrayClass)); mirror::Reference::SetClass(GetClassRoot(kJavaLangRefReference)); mirror::BooleanArray::SetArrayClass(GetClassRoot(kBooleanArrayClass)); mirror::ByteArray::SetArrayClass(GetClassRoot(kByteArrayClass)); @@ -1096,22 +1101,26 @@ void ClassLinker::VisitClassesWithoutClassesLock(ClassVisitor* visitor, void* ar } ClassLinker::~ClassLinker() { - mirror::Class::ResetClass(); - mirror::String::ResetClass(); - mirror::Reference::ResetClass(); mirror::ArtMethod::ResetClass(); + mirror::Class::ResetClass(); + mirror::Constructor::ResetClass(); mirror::Field::ResetClass(); - mirror::Field::ResetArrayClass(); + mirror::Method::ResetClass(); + mirror::Reference::ResetClass(); + mirror::StackTraceElement::ResetClass(); + mirror::String::ResetClass(); + mirror::Throwable::ResetClass(); mirror::BooleanArray::ResetArrayClass(); mirror::ByteArray::ResetArrayClass(); mirror::CharArray::ResetArrayClass(); + mirror::Constructor::ResetArrayClass(); mirror::DoubleArray::ResetArrayClass(); + mirror::Field::ResetArrayClass(); mirror::FloatArray::ResetArrayClass(); + mirror::Method::ResetArrayClass(); mirror::IntArray::ResetArrayClass(); mirror::LongArray::ResetArrayClass(); mirror::ShortArray::ResetArrayClass(); - mirror::Throwable::ResetClass(); - mirror::StackTraceElement::ResetClass(); STLDeleteElements(&oat_files_); } @@ -2947,7 +2956,7 @@ mirror::Class* ClassLinker::CreateProxyClass(ScopedObjectAccessAlreadyRunnable& jobjectArray interfaces, jobject loader, jobjectArray methods, jobjectArray throws) { Thread* self = soa.Self(); - StackHandleScope<8> hs(self); + StackHandleScope<9> hs(self); MutableHandle<mirror::Class> klass(hs.NewHandle( AllocClass(self, GetClassRoot(kJavaLangClass), sizeof(mirror::Class)))); if (klass.Get() == nullptr) { @@ -3001,8 +3010,10 @@ mirror::Class* ClassLinker::CreateProxyClass(ScopedObjectAccessAlreadyRunnable& } // Create virtual method using specified prototypes. - size_t num_virtual_methods = - soa.Decode<mirror::ObjectArray<mirror::ArtMethod>*>(methods)->GetLength(); + auto h_methods = hs.NewHandle(soa.Decode<mirror::ObjectArray<mirror::Method>*>(methods)); + DCHECK_EQ(h_methods->GetClass(), mirror::Method::ArrayClass()) + << PrettyClass(h_methods->GetClass()); + const size_t num_virtual_methods = h_methods->GetLength(); { mirror::ObjectArray<mirror::ArtMethod>* virtuals = AllocArtMethodArray(self, num_virtual_methods); @@ -3014,9 +3025,7 @@ mirror::Class* ClassLinker::CreateProxyClass(ScopedObjectAccessAlreadyRunnable& } for (size_t i = 0; i < num_virtual_methods; ++i) { StackHandleScope<1> hs2(self); - mirror::ObjectArray<mirror::ArtMethod>* decoded_methods = - soa.Decode<mirror::ObjectArray<mirror::ArtMethod>*>(methods); - Handle<mirror::ArtMethod> prototype(hs2.NewHandle(decoded_methods->Get(i))); + Handle<mirror::ArtMethod> prototype(hs2.NewHandle(h_methods->Get(i)->GetArtMethod())); mirror::ArtMethod* clone = CreateProxyMethod(self, klass, prototype); if (UNLIKELY(clone == nullptr)) { CHECK(self->IsExceptionPending()); // OOME. @@ -3066,9 +3075,7 @@ mirror::Class* ClassLinker::CreateProxyClass(ScopedObjectAccessAlreadyRunnable& CheckProxyConstructor(klass->GetDirectMethod(0)); for (size_t i = 0; i < num_virtual_methods; ++i) { StackHandleScope<2> hs2(self); - mirror::ObjectArray<mirror::ArtMethod>* decoded_methods = - soa.Decode<mirror::ObjectArray<mirror::ArtMethod>*>(methods); - Handle<mirror::ArtMethod> prototype(hs2.NewHandle(decoded_methods->Get(i))); + Handle<mirror::ArtMethod> prototype(hs2.NewHandle(h_methods->Get(i)->GetArtMethod())); Handle<mirror::ArtMethod> virtual_method(hs2.NewHandle(klass->GetVirtualMethod(i))); CheckProxyMethod(virtual_method, prototype); } @@ -3104,23 +3111,22 @@ mirror::ArtMethod* ClassLinker::FindMethodForProxy(mirror::Class* proxy_class, mirror::ArtMethod* proxy_method) { DCHECK(proxy_class->IsProxyClass()); DCHECK(proxy_method->IsProxyMethod()); - // Locate the dex cache of the original interface/Object - mirror::DexCache* dex_cache = nullptr; { ReaderMutexLock mu(Thread::Current(), dex_lock_); - for (size_t i = 0; i != dex_caches_.size(); ++i) { - mirror::DexCache* a_dex_cache = GetDexCache(i); - if (proxy_method->HasSameDexCacheResolvedTypes(a_dex_cache->GetResolvedTypes())) { - dex_cache = a_dex_cache; - break; + // Locate the dex cache of the original interface/Object + for (const GcRoot<mirror::DexCache>& root : dex_caches_) { + auto* dex_cache = root.Read(); + if (proxy_method->HasSameDexCacheResolvedTypes(dex_cache->GetResolvedTypes())) { + mirror::ArtMethod* resolved_method = dex_cache->GetResolvedMethod( + proxy_method->GetDexMethodIndex()); + CHECK(resolved_method != nullptr); + return resolved_method; } } } - CHECK(dex_cache != nullptr); - uint32_t method_idx = proxy_method->GetDexMethodIndex(); - mirror::ArtMethod* resolved_method = dex_cache->GetResolvedMethod(method_idx); - CHECK(resolved_method != nullptr); - return resolved_method; + LOG(FATAL) << "Didn't find dex cache for " << PrettyClass(proxy_class) << " " + << PrettyMethod(proxy_method); + UNREACHABLE(); } @@ -3163,8 +3169,11 @@ mirror::ArtMethod* ClassLinker::CreateProxyMethod(Thread* self, Handle<mirror::ArtMethod> prototype) { // Ensure prototype is in dex cache so that we can use the dex cache to look up the overridden // prototype method - prototype->GetDeclaringClass()->GetDexCache()->SetResolvedMethod(prototype->GetDexMethodIndex(), - prototype.Get()); + auto* dex_cache = prototype->GetDeclaringClass()->GetDexCache(); + // Avoid dirtying the dex cache unless we need to. + if (dex_cache->GetResolvedMethod(prototype->GetDexMethodIndex()) != prototype.Get()) { + dex_cache->SetResolvedMethod(prototype->GetDexMethodIndex(), prototype.Get()); + } // We steal everything from the prototype (such as DexCache, invoke stub, etc.) then specialize // as necessary mirror::ArtMethod* method = down_cast<mirror::ArtMethod*>(prototype->Clone(self)); @@ -3198,6 +3207,7 @@ static void CheckProxyMethod(Handle<mirror::ArtMethod> method, // interface prototype. The exception to this are Constructors and the Class of the Proxy itself. CHECK(prototype->HasSameDexCacheResolvedMethods(method.Get())); CHECK(prototype->HasSameDexCacheResolvedTypes(method.Get())); + CHECK_EQ(prototype->GetDeclaringClass()->GetDexCache(), method->GetDexCache()); CHECK_EQ(prototype->GetDexMethodIndex(), method->GetDexMethodIndex()); CHECK_STREQ(method->GetName(), prototype->GetName()); @@ -5210,11 +5220,15 @@ const char* ClassLinker::GetClassRootDescriptor(ClassRoot class_root) { "Ljava/lang/DexCache;", "Ljava/lang/ref/Reference;", "Ljava/lang/reflect/ArtMethod;", + "Ljava/lang/reflect/Constructor;", "Ljava/lang/reflect/Field;", + "Ljava/lang/reflect/Method;", "Ljava/lang/reflect/Proxy;", "[Ljava/lang/String;", "[Ljava/lang/reflect/ArtMethod;", + "[Ljava/lang/reflect/Constructor;", "[Ljava/lang/reflect/Field;", + "[Ljava/lang/reflect/Method;", "Ljava/lang/ClassLoader;", "Ljava/lang/Throwable;", "Ljava/lang/ClassNotFoundException;", diff --git a/runtime/class_linker.h b/runtime/class_linker.h index 68624b0..d7c625d 100644 --- a/runtime/class_linker.h +++ b/runtime/class_linker.h @@ -71,11 +71,15 @@ class ClassLinker { kJavaLangDexCache, kJavaLangRefReference, kJavaLangReflectArtMethod, + kJavaLangReflectConstructor, kJavaLangReflectField, + kJavaLangReflectMethod, kJavaLangReflectProxy, kJavaLangStringArrayClass, kJavaLangReflectArtMethodArrayClass, + kJavaLangReflectConstructorArrayClass, kJavaLangReflectFieldArrayClass, + kJavaLangReflectMethodArrayClass, kJavaLangClassLoader, kJavaLangThrowable, kJavaLangClassNotFoundException, diff --git a/runtime/class_linker_test.cc b/runtime/class_linker_test.cc index a31a785..7bee98f 100644 --- a/runtime/class_linker_test.cc +++ b/runtime/class_linker_test.cc @@ -25,6 +25,7 @@ #include "dex_file.h" #include "entrypoints/entrypoint_utils-inl.h" #include "gc/heap.h" +#include "mirror/abstract_method.h" #include "mirror/accessible_object.h" #include "mirror/art_method-inl.h" #include "mirror/class-inl.h" @@ -463,6 +464,10 @@ struct CheckOffsets { return !error; }; + void addOffset(size_t offset, const char* name) { + offsets.push_back(CheckOffset(offset, name)); + } + private: DISALLOW_IMPLICIT_CONSTRUCTORS(CheckOffsets); }; @@ -472,142 +477,162 @@ struct CheckOffsets { struct ObjectOffsets : public CheckOffsets<mirror::Object> { ObjectOffsets() : CheckOffsets<mirror::Object>(false, "Ljava/lang/Object;") { - offsets.push_back(CheckOffset(OFFSETOF_MEMBER(mirror::Object, klass_), "shadow$_klass_")); - offsets.push_back(CheckOffset(OFFSETOF_MEMBER(mirror::Object, monitor_), "shadow$_monitor_")); + addOffset(OFFSETOF_MEMBER(mirror::Object, klass_), "shadow$_klass_"); + addOffset(OFFSETOF_MEMBER(mirror::Object, monitor_), "shadow$_monitor_"); #ifdef USE_BAKER_OR_BROOKS_READ_BARRIER - offsets.push_back(CheckOffset(OFFSETOF_MEMBER(mirror::Object, x_rb_ptr_), "shadow$_x_rb_ptr_")); - offsets.push_back(CheckOffset(OFFSETOF_MEMBER(mirror::Object, x_xpadding_), "shadow$_x_xpadding_")); + addOffset(OFFSETOF_MEMBER(mirror::Object, x_rb_ptr_), "shadow$_x_rb_ptr_"); + addOffset(OFFSETOF_MEMBER(mirror::Object, x_xpadding_), "shadow$_x_xpadding_"); #endif }; }; struct ArtMethodOffsets : public CheckOffsets<mirror::ArtMethod> { ArtMethodOffsets() : CheckOffsets<mirror::ArtMethod>(false, "Ljava/lang/reflect/ArtMethod;") { - offsets.push_back(CheckOffset(OFFSETOF_MEMBER(mirror::ArtMethod, access_flags_), "accessFlags")); - offsets.push_back(CheckOffset(OFFSETOF_MEMBER(mirror::ArtMethod, declaring_class_), "declaringClass")); - offsets.push_back(CheckOffset(OFFSETOF_MEMBER(mirror::ArtMethod, dex_cache_resolved_methods_), "dexCacheResolvedMethods")); - offsets.push_back(CheckOffset(OFFSETOF_MEMBER(mirror::ArtMethod, dex_cache_resolved_types_), "dexCacheResolvedTypes")); - offsets.push_back(CheckOffset(OFFSETOF_MEMBER(mirror::ArtMethod, dex_code_item_offset_), "dexCodeItemOffset")); - offsets.push_back(CheckOffset(OFFSETOF_MEMBER(mirror::ArtMethod, dex_method_index_), "dexMethodIndex")); - offsets.push_back(CheckOffset(OFFSETOF_MEMBER(mirror::ArtMethod, method_index_), "methodIndex")); + addOffset(OFFSETOF_MEMBER(mirror::ArtMethod, access_flags_), "accessFlags"); + addOffset(OFFSETOF_MEMBER(mirror::ArtMethod, declaring_class_), "declaringClass"); + addOffset(OFFSETOF_MEMBER(mirror::ArtMethod, dex_cache_resolved_methods_), + "dexCacheResolvedMethods"); + addOffset(OFFSETOF_MEMBER(mirror::ArtMethod, dex_cache_resolved_types_), + "dexCacheResolvedTypes"); + addOffset(OFFSETOF_MEMBER(mirror::ArtMethod, dex_code_item_offset_), "dexCodeItemOffset"); + addOffset(OFFSETOF_MEMBER(mirror::ArtMethod, dex_method_index_), "dexMethodIndex"); + addOffset(OFFSETOF_MEMBER(mirror::ArtMethod, method_index_), "methodIndex"); }; }; struct ClassOffsets : public CheckOffsets<mirror::Class> { ClassOffsets() : CheckOffsets<mirror::Class>(false, "Ljava/lang/Class;") { - offsets.push_back(CheckOffset(OFFSETOF_MEMBER(mirror::Class, access_flags_), "accessFlags")); - offsets.push_back(CheckOffset(OFFSETOF_MEMBER(mirror::Class, class_loader_), "classLoader")); - offsets.push_back(CheckOffset(OFFSETOF_MEMBER(mirror::Class, class_size_), "classSize")); - offsets.push_back(CheckOffset(OFFSETOF_MEMBER(mirror::Class, clinit_thread_id_), "clinitThreadId")); - offsets.push_back(CheckOffset(OFFSETOF_MEMBER(mirror::Class, component_type_), "componentType")); - offsets.push_back(CheckOffset(OFFSETOF_MEMBER(mirror::Class, dex_cache_), "dexCache")); - offsets.push_back(CheckOffset(OFFSETOF_MEMBER(mirror::Class, dex_cache_strings_), "dexCacheStrings")); - offsets.push_back(CheckOffset(OFFSETOF_MEMBER(mirror::Class, dex_class_def_idx_), "dexClassDefIndex")); - offsets.push_back(CheckOffset(OFFSETOF_MEMBER(mirror::Class, dex_type_idx_), "dexTypeIndex")); - offsets.push_back(CheckOffset(OFFSETOF_MEMBER(mirror::Class, direct_methods_), "directMethods")); - offsets.push_back(CheckOffset(OFFSETOF_MEMBER(mirror::Class, ifields_), "iFields")); - offsets.push_back(CheckOffset(OFFSETOF_MEMBER(mirror::Class, iftable_), "ifTable")); - offsets.push_back(CheckOffset(OFFSETOF_MEMBER(mirror::Class, name_), "name")); - offsets.push_back(CheckOffset(OFFSETOF_MEMBER(mirror::Class, num_instance_fields_), "numInstanceFields")); - offsets.push_back(CheckOffset(OFFSETOF_MEMBER(mirror::Class, num_reference_instance_fields_), "numReferenceInstanceFields")); - offsets.push_back(CheckOffset(OFFSETOF_MEMBER(mirror::Class, num_reference_static_fields_), "numReferenceStaticFields")); - offsets.push_back(CheckOffset(OFFSETOF_MEMBER(mirror::Class, num_static_fields_), "numStaticFields")); - offsets.push_back(CheckOffset(OFFSETOF_MEMBER(mirror::Class, object_size_), "objectSize")); - offsets.push_back(CheckOffset(OFFSETOF_MEMBER(mirror::Class, primitive_type_), "primitiveType")); - offsets.push_back(CheckOffset(OFFSETOF_MEMBER(mirror::Class, reference_instance_offsets_), "referenceInstanceOffsets")); - offsets.push_back(CheckOffset(OFFSETOF_MEMBER(mirror::Class, sfields_), "sFields")); - offsets.push_back(CheckOffset(OFFSETOF_MEMBER(mirror::Class, status_), "status")); - offsets.push_back(CheckOffset(OFFSETOF_MEMBER(mirror::Class, super_class_), "superClass")); - offsets.push_back(CheckOffset(OFFSETOF_MEMBER(mirror::Class, verify_error_class_), "verifyErrorClass")); - offsets.push_back(CheckOffset(OFFSETOF_MEMBER(mirror::Class, virtual_methods_), "virtualMethods")); - offsets.push_back(CheckOffset(OFFSETOF_MEMBER(mirror::Class, vtable_), "vtable")); + addOffset(OFFSETOF_MEMBER(mirror::Class, access_flags_), "accessFlags"); + addOffset(OFFSETOF_MEMBER(mirror::Class, class_loader_), "classLoader"); + addOffset(OFFSETOF_MEMBER(mirror::Class, class_size_), "classSize"); + addOffset(OFFSETOF_MEMBER(mirror::Class, clinit_thread_id_), "clinitThreadId"); + addOffset(OFFSETOF_MEMBER(mirror::Class, component_type_), "componentType"); + addOffset(OFFSETOF_MEMBER(mirror::Class, dex_cache_), "dexCache"); + addOffset(OFFSETOF_MEMBER(mirror::Class, dex_cache_strings_), "dexCacheStrings"); + addOffset(OFFSETOF_MEMBER(mirror::Class, dex_class_def_idx_), "dexClassDefIndex"); + addOffset(OFFSETOF_MEMBER(mirror::Class, dex_type_idx_), "dexTypeIndex"); + addOffset(OFFSETOF_MEMBER(mirror::Class, direct_methods_), "directMethods"); + addOffset(OFFSETOF_MEMBER(mirror::Class, ifields_), "iFields"); + addOffset(OFFSETOF_MEMBER(mirror::Class, iftable_), "ifTable"); + addOffset(OFFSETOF_MEMBER(mirror::Class, name_), "name"); + addOffset(OFFSETOF_MEMBER(mirror::Class, num_instance_fields_), "numInstanceFields"); + addOffset(OFFSETOF_MEMBER(mirror::Class, num_reference_instance_fields_), + "numReferenceInstanceFields"); + addOffset(OFFSETOF_MEMBER(mirror::Class, num_reference_static_fields_), + "numReferenceStaticFields"); + addOffset(OFFSETOF_MEMBER(mirror::Class, num_static_fields_), "numStaticFields"); + addOffset(OFFSETOF_MEMBER(mirror::Class, object_size_), "objectSize"); + addOffset(OFFSETOF_MEMBER(mirror::Class, primitive_type_), "primitiveType"); + addOffset(OFFSETOF_MEMBER(mirror::Class, reference_instance_offsets_), + "referenceInstanceOffsets"); + addOffset(OFFSETOF_MEMBER(mirror::Class, sfields_), "sFields"); + addOffset(OFFSETOF_MEMBER(mirror::Class, status_), "status"); + addOffset(OFFSETOF_MEMBER(mirror::Class, super_class_), "superClass"); + addOffset(OFFSETOF_MEMBER(mirror::Class, verify_error_class_), "verifyErrorClass"); + addOffset(OFFSETOF_MEMBER(mirror::Class, virtual_methods_), "virtualMethods"); + addOffset(OFFSETOF_MEMBER(mirror::Class, vtable_), "vtable"); }; }; struct StringOffsets : public CheckOffsets<mirror::String> { StringOffsets() : CheckOffsets<mirror::String>(false, "Ljava/lang/String;") { - offsets.push_back(CheckOffset(OFFSETOF_MEMBER(mirror::String, count_), "count")); - offsets.push_back(CheckOffset(OFFSETOF_MEMBER(mirror::String, hash_code_), "hashCode")); - offsets.push_back(CheckOffset(OFFSETOF_MEMBER(mirror::String, offset_), "offset")); - offsets.push_back(CheckOffset(OFFSETOF_MEMBER(mirror::String, array_), "value")); + addOffset(OFFSETOF_MEMBER(mirror::String, count_), "count"); + addOffset(OFFSETOF_MEMBER(mirror::String, hash_code_), "hashCode"); + addOffset(OFFSETOF_MEMBER(mirror::String, offset_), "offset"); + addOffset(OFFSETOF_MEMBER(mirror::String, array_), "value"); }; }; struct ThrowableOffsets : public CheckOffsets<mirror::Throwable> { ThrowableOffsets() : CheckOffsets<mirror::Throwable>(false, "Ljava/lang/Throwable;") { - offsets.push_back(CheckOffset(OFFSETOF_MEMBER(mirror::Throwable, cause_), "cause")); - offsets.push_back(CheckOffset(OFFSETOF_MEMBER(mirror::Throwable, detail_message_), "detailMessage")); - offsets.push_back(CheckOffset(OFFSETOF_MEMBER(mirror::Throwable, stack_state_), "stackState")); - offsets.push_back(CheckOffset(OFFSETOF_MEMBER(mirror::Throwable, stack_trace_), "stackTrace")); - offsets.push_back(CheckOffset(OFFSETOF_MEMBER(mirror::Throwable, suppressed_exceptions_), "suppressedExceptions")); + addOffset(OFFSETOF_MEMBER(mirror::Throwable, cause_), "cause"); + addOffset(OFFSETOF_MEMBER(mirror::Throwable, detail_message_), "detailMessage"); + addOffset(OFFSETOF_MEMBER(mirror::Throwable, stack_state_), "stackState"); + addOffset(OFFSETOF_MEMBER(mirror::Throwable, stack_trace_), "stackTrace"); + addOffset(OFFSETOF_MEMBER(mirror::Throwable, suppressed_exceptions_), "suppressedExceptions"); }; }; struct StackTraceElementOffsets : public CheckOffsets<mirror::StackTraceElement> { - StackTraceElementOffsets() : CheckOffsets<mirror::StackTraceElement>(false, "Ljava/lang/StackTraceElement;") { - offsets.push_back(CheckOffset(OFFSETOF_MEMBER(mirror::StackTraceElement, declaring_class_), "declaringClass")); - offsets.push_back(CheckOffset(OFFSETOF_MEMBER(mirror::StackTraceElement, file_name_), "fileName")); - offsets.push_back(CheckOffset(OFFSETOF_MEMBER(mirror::StackTraceElement, line_number_), "lineNumber")); - offsets.push_back(CheckOffset(OFFSETOF_MEMBER(mirror::StackTraceElement, method_name_), "methodName")); + StackTraceElementOffsets() : CheckOffsets<mirror::StackTraceElement>( + false, "Ljava/lang/StackTraceElement;") { + addOffset(OFFSETOF_MEMBER(mirror::StackTraceElement, declaring_class_), "declaringClass"); + addOffset(OFFSETOF_MEMBER(mirror::StackTraceElement, file_name_), "fileName"); + addOffset(OFFSETOF_MEMBER(mirror::StackTraceElement, line_number_), "lineNumber"); + addOffset(OFFSETOF_MEMBER(mirror::StackTraceElement, method_name_), "methodName"); }; }; struct ClassLoaderOffsets : public CheckOffsets<mirror::ClassLoader> { ClassLoaderOffsets() : CheckOffsets<mirror::ClassLoader>(false, "Ljava/lang/ClassLoader;") { - offsets.push_back(CheckOffset(OFFSETOF_MEMBER(mirror::ClassLoader, packages_), "packages")); - offsets.push_back(CheckOffset(OFFSETOF_MEMBER(mirror::ClassLoader, parent_), "parent")); - offsets.push_back(CheckOffset(OFFSETOF_MEMBER(mirror::ClassLoader, proxyCache_), "proxyCache")); + addOffset(OFFSETOF_MEMBER(mirror::ClassLoader, packages_), "packages"); + addOffset(OFFSETOF_MEMBER(mirror::ClassLoader, parent_), "parent"); + addOffset(OFFSETOF_MEMBER(mirror::ClassLoader, proxyCache_), "proxyCache"); }; }; struct ProxyOffsets : public CheckOffsets<mirror::Proxy> { ProxyOffsets() : CheckOffsets<mirror::Proxy>(false, "Ljava/lang/reflect/Proxy;") { - offsets.push_back(CheckOffset(OFFSETOF_MEMBER(mirror::Proxy, h_), "h")); + addOffset(OFFSETOF_MEMBER(mirror::Proxy, h_), "h"); }; }; struct DexCacheOffsets : public CheckOffsets<mirror::DexCache> { DexCacheOffsets() : CheckOffsets<mirror::DexCache>(false, "Ljava/lang/DexCache;") { - offsets.push_back(CheckOffset(OFFSETOF_MEMBER(mirror::DexCache, dex_), "dex")); - offsets.push_back(CheckOffset(OFFSETOF_MEMBER(mirror::DexCache, dex_file_), "dexFile")); - offsets.push_back(CheckOffset(OFFSETOF_MEMBER(mirror::DexCache, location_), "location")); - offsets.push_back(CheckOffset(OFFSETOF_MEMBER(mirror::DexCache, resolved_fields_), "resolvedFields")); - offsets.push_back(CheckOffset(OFFSETOF_MEMBER(mirror::DexCache, resolved_methods_), "resolvedMethods")); - offsets.push_back(CheckOffset(OFFSETOF_MEMBER(mirror::DexCache, resolved_types_), "resolvedTypes")); - offsets.push_back(CheckOffset(OFFSETOF_MEMBER(mirror::DexCache, strings_), "strings")); + addOffset(OFFSETOF_MEMBER(mirror::DexCache, dex_), "dex"); + addOffset(OFFSETOF_MEMBER(mirror::DexCache, dex_file_), "dexFile"); + addOffset(OFFSETOF_MEMBER(mirror::DexCache, location_), "location"); + addOffset(OFFSETOF_MEMBER(mirror::DexCache, resolved_fields_), "resolvedFields"); + addOffset(OFFSETOF_MEMBER(mirror::DexCache, resolved_methods_), "resolvedMethods"); + addOffset(OFFSETOF_MEMBER(mirror::DexCache, resolved_types_), "resolvedTypes"); + addOffset(OFFSETOF_MEMBER(mirror::DexCache, strings_), "strings"); }; }; struct ReferenceOffsets : public CheckOffsets<mirror::Reference> { ReferenceOffsets() : CheckOffsets<mirror::Reference>(false, "Ljava/lang/ref/Reference;") { - offsets.push_back(CheckOffset(OFFSETOF_MEMBER(mirror::Reference, pending_next_), "pendingNext")); - offsets.push_back(CheckOffset(OFFSETOF_MEMBER(mirror::Reference, queue_), "queue")); - offsets.push_back(CheckOffset(OFFSETOF_MEMBER(mirror::Reference, queue_next_), "queueNext")); - offsets.push_back(CheckOffset(OFFSETOF_MEMBER(mirror::Reference, referent_), "referent")); + addOffset(OFFSETOF_MEMBER(mirror::Reference, pending_next_), "pendingNext"); + addOffset(OFFSETOF_MEMBER(mirror::Reference, queue_), "queue"); + addOffset(OFFSETOF_MEMBER(mirror::Reference, queue_next_), "queueNext"); + addOffset(OFFSETOF_MEMBER(mirror::Reference, referent_), "referent"); }; }; struct FinalizerReferenceOffsets : public CheckOffsets<mirror::FinalizerReference> { - FinalizerReferenceOffsets() : CheckOffsets<mirror::FinalizerReference>(false, "Ljava/lang/ref/FinalizerReference;") { - offsets.push_back(CheckOffset(OFFSETOF_MEMBER(mirror::FinalizerReference, next_), "next")); - offsets.push_back(CheckOffset(OFFSETOF_MEMBER(mirror::FinalizerReference, prev_), "prev")); - offsets.push_back(CheckOffset(OFFSETOF_MEMBER(mirror::FinalizerReference, zombie_), "zombie")); + FinalizerReferenceOffsets() : CheckOffsets<mirror::FinalizerReference>( + false, "Ljava/lang/ref/FinalizerReference;") { + addOffset(OFFSETOF_MEMBER(mirror::FinalizerReference, next_), "next"); + addOffset(OFFSETOF_MEMBER(mirror::FinalizerReference, prev_), "prev"); + addOffset(OFFSETOF_MEMBER(mirror::FinalizerReference, zombie_), "zombie"); }; }; struct AccessibleObjectOffsets : public CheckOffsets<mirror::AccessibleObject> { - AccessibleObjectOffsets() : CheckOffsets<mirror::AccessibleObject>(false, "Ljava/lang/reflect/AccessibleObject;") { - offsets.push_back(CheckOffset(mirror::AccessibleObject::FlagOffset().Uint32Value(), "flag")); + AccessibleObjectOffsets() : CheckOffsets<mirror::AccessibleObject>( + false, "Ljava/lang/reflect/AccessibleObject;") { + addOffset(mirror::AccessibleObject::FlagOffset().Uint32Value(), "flag"); }; }; struct FieldOffsets : public CheckOffsets<mirror::Field> { FieldOffsets() : CheckOffsets<mirror::Field>(false, "Ljava/lang/reflect/Field;") { - offsets.push_back(CheckOffset(OFFSETOF_MEMBER(mirror::Field, access_flags_), "accessFlags")); - offsets.push_back(CheckOffset(OFFSETOF_MEMBER(mirror::Field, declaring_class_), "declaringClass")); - offsets.push_back(CheckOffset(OFFSETOF_MEMBER(mirror::Field, dex_field_index_), "dexFieldIndex")); - offsets.push_back(CheckOffset(OFFSETOF_MEMBER(mirror::Field, offset_), "offset")); - offsets.push_back(CheckOffset(OFFSETOF_MEMBER(mirror::Field, type_), "type")); + addOffset(OFFSETOF_MEMBER(mirror::Field, access_flags_), "accessFlags"); + addOffset(OFFSETOF_MEMBER(mirror::Field, declaring_class_), "declaringClass"); + addOffset(OFFSETOF_MEMBER(mirror::Field, dex_field_index_), "dexFieldIndex"); + addOffset(OFFSETOF_MEMBER(mirror::Field, offset_), "offset"); + addOffset(OFFSETOF_MEMBER(mirror::Field, type_), "type"); + }; +}; + +struct AbstractMethodOffsets : public CheckOffsets<mirror::AbstractMethod> { + AbstractMethodOffsets() : CheckOffsets<mirror::AbstractMethod>( + false, "Ljava/lang/reflect/AbstractMethod;") { + addOffset(OFFSETOF_MEMBER(mirror::AbstractMethod, access_flags_), "accessFlags"); + addOffset(OFFSETOF_MEMBER(mirror::AbstractMethod, art_method_), "artMethod"); + addOffset(OFFSETOF_MEMBER(mirror::AbstractMethod, declaring_class_), "declaringClass"); + addOffset(OFFSETOF_MEMBER(mirror::AbstractMethod, declaring_class_of_overridden_method_), + "declaringClassOfOverriddenMethod"); + addOffset(OFFSETOF_MEMBER(mirror::AbstractMethod, dex_method_index_), "dexMethodIndex"); }; }; @@ -629,6 +654,7 @@ TEST_F(ClassLinkerTest, ValidateFieldOrderOfJavaCppUnionClasses) { EXPECT_TRUE(FinalizerReferenceOffsets().Check()); EXPECT_TRUE(AccessibleObjectOffsets().Check()); EXPECT_TRUE(FieldOffsets().Check()); + EXPECT_TRUE(AbstractMethodOffsets().Check()); } TEST_F(ClassLinkerTest, FindClassNonexistent) { diff --git a/runtime/entrypoints/entrypoint_utils.cc b/runtime/entrypoints/entrypoint_utils.cc index 1d8df68..768f505 100644 --- a/runtime/entrypoints/entrypoint_utils.cc +++ b/runtime/entrypoints/entrypoint_utils.cc @@ -23,6 +23,7 @@ #include "gc/accounting/card_table-inl.h" #include "mirror/art_method-inl.h" #include "mirror/class-inl.h" +#include "mirror/method.h" #include "mirror/object-inl.h" #include "mirror/object_array-inl.h" #include "reflection.h" @@ -257,7 +258,7 @@ JValue InvokeProxyInvocationHandler(ScopedObjectAccessAlreadyRunnable& soa, cons } } - // Call Proxy.invoke(Proxy proxy, ArtMethod method, Object[] args). + // Call Proxy.invoke(Proxy proxy, Method method, Object[] args). jvalue invocation_args[3]; invocation_args[0].l = rcvr_jobj; invocation_args[1].l = interface_method_jobj; @@ -274,10 +275,9 @@ JValue InvokeProxyInvocationHandler(ScopedObjectAccessAlreadyRunnable& soa, cons return zero; } else { StackHandleScope<1> hs(soa.Self()); - Handle<mirror::ArtMethod> h_interface_method( - hs.NewHandle(soa.Decode<mirror::ArtMethod*>(interface_method_jobj))); + auto h_interface_method(hs.NewHandle(soa.Decode<mirror::Method*>(interface_method_jobj))); // This can cause thread suspension. - mirror::Class* result_type = h_interface_method->GetReturnType(); + mirror::Class* result_type = h_interface_method->GetArtMethod()->GetReturnType(); mirror::Object* result_ref = soa.Decode<mirror::Object*>(result); JValue result_unboxed; if (!UnboxPrimitiveForResult(result_ref, result_type, &result_unboxed)) { @@ -293,10 +293,9 @@ JValue InvokeProxyInvocationHandler(ScopedObjectAccessAlreadyRunnable& soa, cons if (exception->IsCheckedException()) { mirror::Object* rcvr = soa.Decode<mirror::Object*>(rcvr_jobj); mirror::Class* proxy_class = rcvr->GetClass(); - mirror::ArtMethod* interface_method = - soa.Decode<mirror::ArtMethod*>(interface_method_jobj); + mirror::Method* interface_method = soa.Decode<mirror::Method*>(interface_method_jobj); mirror::ArtMethod* proxy_method = - rcvr->GetClass()->FindVirtualMethodForInterface(interface_method); + rcvr->GetClass()->FindVirtualMethodForInterface(interface_method->GetArtMethod()); int throws_index = -1; size_t num_virt_methods = proxy_class->NumVirtualMethods(); for (size_t i = 0; i < num_virt_methods; i++) { diff --git a/runtime/entrypoints/quick/quick_trampoline_entrypoints.cc b/runtime/entrypoints/quick/quick_trampoline_entrypoints.cc index 2e813c8..2e7e2df 100644 --- a/runtime/entrypoints/quick/quick_trampoline_entrypoints.cc +++ b/runtime/entrypoints/quick/quick_trampoline_entrypoints.cc @@ -26,6 +26,7 @@ #include "mirror/art_method-inl.h" #include "mirror/class-inl.h" #include "mirror/dex_cache-inl.h" +#include "mirror/method.h" #include "mirror/object-inl.h" #include "mirror/object_array-inl.h" #include "runtime.h" @@ -760,11 +761,12 @@ extern "C" uint64_t artQuickProxyInvokeHandler(mirror::ArtMethod* proxy_method, mirror::ArtMethod* interface_method = proxy_method->FindOverriddenMethod(); DCHECK(interface_method != nullptr) << PrettyMethod(proxy_method); DCHECK(!interface_method->IsProxyMethod()) << PrettyMethod(interface_method); - jobject interface_method_jobj = soa.AddLocalReference<jobject>(interface_method); + self->EndAssertNoThreadSuspension(old_cause); + jobject interface_method_jobj = soa.AddLocalReference<jobject>( + mirror::Method::CreateFromArtMethod(soa.Self(), interface_method)); // All naked Object*s should now be in jobjects, so its safe to go into the main invoke code // that performs allocations. - self->EndAssertNoThreadSuspension(old_cause); JValue result = InvokeProxyInvocationHandler(soa, shorty, rcvr_jobj, interface_method_jobj, args); // Restore references which might have moved. local_ref_visitor.FixupReferences(); diff --git a/runtime/jni_internal.cc b/runtime/jni_internal.cc index 8a5461b..554a28d 100644 --- a/runtime/jni_internal.cc +++ b/runtime/jni_internal.cc @@ -42,6 +42,7 @@ #include "mirror/class-inl.h" #include "mirror/class_loader.h" #include "mirror/field-inl.h" +#include "mirror/method.h" #include "mirror/object-inl.h" #include "mirror/object_array-inl.h" #include "mirror/string-inl.h" @@ -361,19 +362,13 @@ class JNI { ScopedObjectAccess soa(env); mirror::ArtMethod* m = soa.DecodeMethod(mid); CHECK(!kMovingMethods); - ScopedLocalRef<jobject> art_method(env, soa.AddLocalReference<jobject>(m)); - jobject reflect_method; + mirror::AbstractMethod* method; if (m->IsConstructor()) { - reflect_method = env->AllocObject(WellKnownClasses::java_lang_reflect_Constructor); + method = mirror::Constructor::CreateFromArtMethod(soa.Self(), m); } else { - reflect_method = env->AllocObject(WellKnownClasses::java_lang_reflect_Method); + method = mirror::Method::CreateFromArtMethod(soa.Self(), m); } - if (env->ExceptionCheck()) { - return nullptr; - } - SetObjectField(env, reflect_method, - WellKnownClasses::java_lang_reflect_AbstractMethod_artMethod, art_method.get()); - return reflect_method; + return soa.AddLocalReference<jobject>(method); } static jobject ToReflectedField(JNIEnv* env, jclass, jfieldID fid, jboolean) { diff --git a/runtime/mirror/abstract_method.cc b/runtime/mirror/abstract_method.cc new file mode 100644 index 0000000..81c656b --- /dev/null +++ b/runtime/mirror/abstract_method.cc @@ -0,0 +1,44 @@ +/* + * Copyright (C) 2015 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "abstract_method.h" + +#include "mirror/art_method-inl.h" + +namespace art { +namespace mirror { + +bool AbstractMethod::CreateFromArtMethod(mirror::ArtMethod* method) { + auto* interface_method = method->GetInterfaceMethodIfProxy(); + SetFieldObject<false>(ArtMethodOffset(), method); + SetFieldObject<false>(DeclaringClassOffset(), method->GetDeclaringClass()); + SetFieldObject<false>( + DeclaringClassOfOverriddenMethodOffset(), interface_method->GetDeclaringClass()); + SetField32<false>(AccessFlagsOffset(), method->GetAccessFlags()); + SetField32<false>(DexMethodIndexOffset(), method->GetDexMethodIndex()); + return true; +} + +mirror::ArtMethod* AbstractMethod::GetArtMethod() { + return GetFieldObject<mirror::ArtMethod>(ArtMethodOffset()); +} + +mirror::Class* AbstractMethod::GetDeclaringClass() { + return GetFieldObject<mirror::Class>(DeclaringClassOffset()); +} + +} // namespace mirror +} // namespace art diff --git a/runtime/mirror/abstract_method.h b/runtime/mirror/abstract_method.h new file mode 100644 index 0000000..ef51d7f --- /dev/null +++ b/runtime/mirror/abstract_method.h @@ -0,0 +1,73 @@ +/* + * Copyright (C) 2015 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef ART_RUNTIME_MIRROR_ABSTRACT_METHOD_H_ +#define ART_RUNTIME_MIRROR_ABSTRACT_METHOD_H_ + +#include "accessible_object.h" +#include "gc_root.h" +#include "object.h" +#include "object_callbacks.h" +#include "read_barrier_option.h" + +namespace art { + +struct AbstractMethodOffsets; + +namespace mirror { + +class ArtMethod; + +// C++ mirror of java.lang.reflect.AbstractMethod. +class MANAGED AbstractMethod : public AccessibleObject { + public: + // Called from Constructor::CreateFromArtMethod, Method::CreateFromArtMethod. + bool CreateFromArtMethod(mirror::ArtMethod* method) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_); + + mirror::ArtMethod* GetArtMethod() SHARED_LOCKS_REQUIRED(Locks::mutator_lock_); + mirror::Class* GetDeclaringClass() SHARED_LOCKS_REQUIRED(Locks::mutator_lock_); + + private: + static MemberOffset ArtMethodOffset() { + return MemberOffset(OFFSETOF_MEMBER(AbstractMethod, art_method_)); + } + static MemberOffset DeclaringClassOffset() { + return MemberOffset(OFFSETOF_MEMBER(AbstractMethod, declaring_class_)); + } + static MemberOffset DeclaringClassOfOverriddenMethodOffset() { + return MemberOffset(OFFSETOF_MEMBER(AbstractMethod, declaring_class_of_overridden_method_)); + } + static MemberOffset AccessFlagsOffset() { + return MemberOffset(OFFSETOF_MEMBER(AbstractMethod, access_flags_)); + } + static MemberOffset DexMethodIndexOffset() { + return MemberOffset(OFFSETOF_MEMBER(AbstractMethod, dex_method_index_)); + } + + HeapReference<mirror::ArtMethod> art_method_; + HeapReference<mirror::Class> declaring_class_; + HeapReference<mirror::Class> declaring_class_of_overridden_method_; + uint32_t access_flags_; + uint32_t dex_method_index_; + + friend struct art::AbstractMethodOffsets; // for verifying offset information + DISALLOW_IMPLICIT_CONSTRUCTORS(AbstractMethod); +}; + +} // namespace mirror +} // namespace art + +#endif // ART_RUNTIME_MIRROR_ABSTRACT_METHOD_H_ diff --git a/runtime/mirror/art_method-inl.h b/runtime/mirror/art_method-inl.h index a300d52..5fc96ad 100644 --- a/runtime/mirror/art_method-inl.h +++ b/runtime/mirror/art_method-inl.h @@ -36,7 +36,7 @@ namespace art { namespace mirror { inline uint32_t ArtMethod::ClassSize() { - uint32_t vtable_entries = Object::kVTableLength + 7; + uint32_t vtable_entries = Object::kVTableLength; return Class::ComputeClassSize(true, vtable_entries, 0, 0, 0, 0, 0); } diff --git a/runtime/mirror/art_method.cc b/runtime/mirror/art_method.cc index 92aea1f..9483ba6 100644 --- a/runtime/mirror/art_method.cc +++ b/runtime/mirror/art_method.cc @@ -16,6 +16,7 @@ #include "art_method.h" +#include "abstract_method.h" #include "arch/context.h" #include "art_field-inl.h" #include "art_method-inl.h" @@ -53,14 +54,11 @@ GcRoot<Class> ArtMethod::java_lang_reflect_ArtMethod_; ArtMethod* ArtMethod::FromReflectedMethod(const ScopedObjectAccessAlreadyRunnable& soa, jobject jlr_method) { - ArtField* f = - soa.DecodeField(WellKnownClasses::java_lang_reflect_AbstractMethod_artMethod); - mirror::ArtMethod* method = f->GetObject(soa.Decode<mirror::Object*>(jlr_method))->AsArtMethod(); - DCHECK(method != nullptr); - return method; + auto* abstract_method = soa.Decode<mirror::AbstractMethod*>(jlr_method); + DCHECK(abstract_method != nullptr); + return abstract_method->GetArtMethod(); } - void ArtMethod::VisitRoots(RootVisitor* visitor) { java_lang_reflect_ArtMethod_.VisitRootIfNonNull(visitor, RootInfo(kRootStickyClass)); } @@ -547,5 +545,31 @@ void ArtMethod::UnregisterNative() { RegisterNative(GetJniDlsymLookupStub(), false); } +bool ArtMethod::EqualParameters(Handle<mirror::ObjectArray<mirror::Class>> params) { + auto* dex_cache = GetDexCache(); + auto* dex_file = dex_cache->GetDexFile(); + const auto& method_id = dex_file->GetMethodId(GetDexMethodIndex()); + const auto& proto_id = dex_file->GetMethodPrototype(method_id); + const DexFile::TypeList* proto_params = dex_file->GetProtoParameters(proto_id); + auto count = proto_params != nullptr ? proto_params->Size() : 0u; + auto param_len = params.Get() != nullptr ? params->GetLength() : 0u; + if (param_len != count) { + return false; + } + auto* cl = Runtime::Current()->GetClassLinker(); + for (size_t i = 0; i < count; ++i) { + auto type_idx = proto_params->GetTypeItem(i).type_idx_; + auto* type = cl->ResolveType(type_idx, this); + if (type == nullptr) { + Thread::Current()->AssertPendingException(); + return false; + } + if (type != params->GetWithoutChecks(i)) { + return false; + } + } + return true; +} + } // namespace mirror } // namespace art diff --git a/runtime/mirror/art_method.h b/runtime/mirror/art_method.h index 55b8068..b899b25 100644 --- a/runtime/mirror/art_method.h +++ b/runtime/mirror/art_method.h @@ -541,6 +541,10 @@ class MANAGED ArtMethod FINAL : public Object { ALWAYS_INLINE ArtMethod* GetInterfaceMethodIfProxy() SHARED_LOCKS_REQUIRED(Locks::mutator_lock_); + // May cause thread suspension due to class resolution. + bool EqualParameters(Handle<mirror::ObjectArray<mirror::Class>> params) + SHARED_LOCKS_REQUIRED(Locks::mutator_lock_); + static size_t SizeWithoutPointerFields(size_t pointer_size) { size_t total = sizeof(ArtMethod) - sizeof(PtrSizedFields); #ifdef ART_METHOD_HAS_PADDING_FIELD_ON_64_BIT diff --git a/runtime/mirror/class.cc b/runtime/mirror/class.cc index 2afb4af..1739019 100644 --- a/runtime/mirror/class.cc +++ b/runtime/mirror/class.cc @@ -25,6 +25,7 @@ #include "dex_file-inl.h" #include "gc/accounting/card_table-inl.h" #include "handle_scope-inl.h" +#include "method.h" #include "object_array-inl.h" #include "object-inl.h" #include "runtime.h" @@ -876,5 +877,26 @@ bool Class::ProxyDescriptorEquals(const char* match) { return Runtime::Current()->GetClassLinker()->GetDescriptorForProxy(this) == match; } +mirror::ArtMethod* Class::GetDeclaredConstructor( + Thread* self, Handle<mirror::ObjectArray<mirror::Class>> args) { + auto* direct_methods = GetDirectMethods(); + size_t count = direct_methods != nullptr ? direct_methods->GetLength() : 0u; + for (size_t i = 0; i < count; ++i) { + auto* m = direct_methods->GetWithoutChecks(i); + // Skip <clinit> which is a static constructor, as well as non constructors. + if (m->IsStatic() || !m->IsConstructor()) { + continue; + } + // May cause thread suspension and exceptions. + if (m->EqualParameters(args)) { + return m; + } + if (self->IsExceptionPending()) { + return nullptr; + } + } + return nullptr; +} + } // namespace mirror } // namespace art diff --git a/runtime/mirror/class.h b/runtime/mirror/class.h index 20f2387..5005346 100644 --- a/runtime/mirror/class.h +++ b/runtime/mirror/class.h @@ -47,6 +47,7 @@ namespace mirror { class ArtMethod; class ClassLoader; +class Constructor; class DexCache; class IfTable; @@ -1052,6 +1053,11 @@ class MANAGED Class FINAL : public Object { return OFFSET_OF_OBJECT_MEMBER(Class, dex_cache_strings_); } + // May cause thread suspension due to EqualParameters. + mirror::ArtMethod* GetDeclaredConstructor( + Thread* self, Handle<mirror::ObjectArray<mirror::Class>> args) + SHARED_LOCKS_REQUIRED(Locks::mutator_lock_); + // Used to initialize a class in the allocation code path to ensure it is guarded by a StoreStore // fence. class InitializeClassVisitor { diff --git a/runtime/mirror/field.h b/runtime/mirror/field.h index 9988f84..d927f0c 100644 --- a/runtime/mirror/field.h +++ b/runtime/mirror/field.h @@ -82,15 +82,12 @@ class MANAGED Field : public AccessibleObject { } static void SetClass(Class* klass) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_); - - static void SetArrayClass(Class* klass) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_); - static void ResetClass() SHARED_LOCKS_REQUIRED(Locks::mutator_lock_); + static void SetArrayClass(Class* klass) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_); static void ResetArrayClass() SHARED_LOCKS_REQUIRED(Locks::mutator_lock_); - static void VisitRoots(RootVisitor* visitor) - SHARED_LOCKS_REQUIRED(Locks::mutator_lock_); + static void VisitRoots(RootVisitor* visitor) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_); // Slow, try to use only for PrettyField and such. ArtField* GetArtField() SHARED_LOCKS_REQUIRED(Locks::mutator_lock_); diff --git a/runtime/mirror/method.cc b/runtime/mirror/method.cc new file mode 100644 index 0000000..81530bb --- /dev/null +++ b/runtime/mirror/method.cc @@ -0,0 +1,103 @@ +/* + * Copyright (C) 2015 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#include "method.h" + +#include "mirror/art_method.h" +#include "mirror/object-inl.h" + +namespace art { +namespace mirror { + +GcRoot<Class> Method::static_class_; +GcRoot<Class> Method::array_class_; +GcRoot<Class> Constructor::static_class_; +GcRoot<Class> Constructor::array_class_; + +void Method::SetClass(Class* klass) { + CHECK(static_class_.IsNull()) << static_class_.Read() << " " << klass; + CHECK(klass != nullptr); + static_class_ = GcRoot<Class>(klass); +} + +void Method::ResetClass() { + CHECK(!static_class_.IsNull()); + static_class_ = GcRoot<Class>(nullptr); +} + +void Method::SetArrayClass(Class* klass) { + CHECK(array_class_.IsNull()) << array_class_.Read() << " " << klass; + CHECK(klass != nullptr); + array_class_ = GcRoot<Class>(klass); +} + +void Method::ResetArrayClass() { + CHECK(!array_class_.IsNull()); + array_class_ = GcRoot<Class>(nullptr); +} + +Method* Method::CreateFromArtMethod(Thread* self, mirror::ArtMethod* method) { + DCHECK(!method->IsConstructor()) << PrettyMethod(method); + auto* ret = down_cast<Method*>(StaticClass()->AllocObject(self)); + if (LIKELY(ret != nullptr)) { + static_cast<AbstractMethod*>(ret)->CreateFromArtMethod(method); + } + return ret; +} + +void Method::VisitRoots(RootVisitor* visitor) { + static_class_.VisitRootIfNonNull(visitor, RootInfo(kRootStickyClass)); + array_class_.VisitRootIfNonNull(visitor, RootInfo(kRootStickyClass)); +} + +void Constructor::SetClass(Class* klass) { + CHECK(static_class_.IsNull()) << static_class_.Read() << " " << klass; + CHECK(klass != nullptr); + static_class_ = GcRoot<Class>(klass); +} + +void Constructor::ResetClass() { + CHECK(!static_class_.IsNull()); + static_class_ = GcRoot<Class>(nullptr); +} + +void Constructor::SetArrayClass(Class* klass) { + CHECK(array_class_.IsNull()) << array_class_.Read() << " " << klass; + CHECK(klass != nullptr); + array_class_ = GcRoot<Class>(klass); +} + +void Constructor::ResetArrayClass() { + CHECK(!array_class_.IsNull()); + array_class_ = GcRoot<Class>(nullptr); +} + +void Constructor::VisitRoots(RootVisitor* visitor) { + static_class_.VisitRootIfNonNull(visitor, RootInfo(kRootStickyClass)); + array_class_.VisitRootIfNonNull(visitor, RootInfo(kRootStickyClass)); +} + +Constructor* Constructor::CreateFromArtMethod(Thread* self, mirror::ArtMethod* method) { + DCHECK(method->IsConstructor()) << PrettyMethod(method); + auto* ret = down_cast<Constructor*>(StaticClass()->AllocObject(self)); + if (LIKELY(ret != nullptr)) { + static_cast<AbstractMethod*>(ret)->CreateFromArtMethod(method); + } + return ret; +} + +} // namespace mirror +} // namespace art diff --git a/runtime/mirror/method.h b/runtime/mirror/method.h new file mode 100644 index 0000000..88100f0 --- /dev/null +++ b/runtime/mirror/method.h @@ -0,0 +1,93 @@ +/* + * Copyright (C) 2015 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +#ifndef ART_RUNTIME_MIRROR_METHOD_H_ +#define ART_RUNTIME_MIRROR_METHOD_H_ + +#include "abstract_method.h" +#include "gc_root.h" + +namespace art { +namespace mirror { + +class Class; + +// C++ mirror of java.lang.reflect.Method. +class MANAGED Method : public AbstractMethod { + public: + static Method* CreateFromArtMethod(Thread* self, mirror::ArtMethod* method) + SHARED_LOCKS_REQUIRED(Locks::mutator_lock_); + + static mirror::Class* StaticClass() SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) { + return static_class_.Read(); + } + + static void SetClass(Class* klass) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_); + + static void ResetClass() SHARED_LOCKS_REQUIRED(Locks::mutator_lock_); + + static mirror::Class* ArrayClass() SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) { + return array_class_.Read(); + } + + static void SetArrayClass(Class* klass) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_); + + static void ResetArrayClass() SHARED_LOCKS_REQUIRED(Locks::mutator_lock_); + + static void VisitRoots(RootVisitor* visitor) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_); + + private: + static GcRoot<Class> static_class_; // java.lang.reflect.Method.class. + static GcRoot<Class> array_class_; // [java.lang.reflect.Method.class. + + DISALLOW_COPY_AND_ASSIGN(Method); +}; + +// C++ mirror of java.lang.reflect.Constructor. +class MANAGED Constructor: public AbstractMethod { + public: + static Constructor* CreateFromArtMethod(Thread* self, mirror::ArtMethod* method) + SHARED_LOCKS_REQUIRED(Locks::mutator_lock_); + + static mirror::Class* StaticClass() SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) { + return static_class_.Read(); + } + + static void SetClass(Class* klass) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_); + + static void ResetClass() SHARED_LOCKS_REQUIRED(Locks::mutator_lock_); + + static mirror::Class* ArrayClass() SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) { + return array_class_.Read(); + } + + static void SetArrayClass(Class* klass) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_); + + static void ResetArrayClass() SHARED_LOCKS_REQUIRED(Locks::mutator_lock_); + + static void VisitRoots(RootVisitor* visitor) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_); + + private: + static GcRoot<Class> static_class_; // java.lang.reflect.Constructor.class. + static GcRoot<Class> array_class_; // [java.lang.reflect.Constructor.class. + + DISALLOW_COPY_AND_ASSIGN(Constructor); +}; + +} // namespace mirror +} // namespace art + +#endif // ART_RUNTIME_MIRROR_METHOD_H_ diff --git a/runtime/native/java_lang_Class.cc b/runtime/native/java_lang_Class.cc index 5ad18f8..51a897d 100644 --- a/runtime/native/java_lang_Class.cc +++ b/runtime/native/java_lang_Class.cc @@ -25,6 +25,7 @@ #include "mirror/class-inl.h" #include "mirror/class_loader.h" #include "mirror/field-inl.h" +#include "mirror/method.h" #include "mirror/object-inl.h" #include "mirror/object_array-inl.h" #include "mirror/string-inl.h" @@ -91,18 +92,6 @@ static jclass Class_classForName(JNIEnv* env, jclass, jstring javaName, jboolean return soa.AddLocalReference<jclass>(c.Get()); } -static jobject Class_findOverriddenMethodIfProxy(JNIEnv* env, jclass, jobject art_method) { - ScopedFastNativeObjectAccess soa(env); - mirror::ArtMethod* method = soa.Decode<mirror::ArtMethod*>(art_method); - mirror::Class* declaring_klass = method->GetDeclaringClass(); - if (!declaring_klass->IsProxyClass()) { - return art_method; - } - uint32_t dex_method_index = method->GetDexMethodIndex(); - mirror::ArtMethod* overriden_method = method->GetDexCacheResolvedMethods()->Get(dex_method_index); - return soa.AddLocalReference<jobject>(overriden_method); -} - static jstring Class_getNameNative(JNIEnv* env, jobject javaThis) { ScopedFastNativeObjectAccess soa(env); StackHandleScope<1> hs(soa.Self()); @@ -252,7 +241,7 @@ static jobject Class_getDeclaredFieldInternal(JNIEnv* env, jobject javaThis, jst static jobject Class_getDeclaredField(JNIEnv* env, jobject javaThis, jstring name) { ScopedFastNativeObjectAccess soa(env); auto* name_string = soa.Decode<mirror::String*>(name); - if (name == nullptr) { + if (name_string == nullptr) { ThrowNullPointerException("name == null"); return nullptr; } @@ -269,17 +258,222 @@ static jobject Class_getDeclaredField(JNIEnv* env, jobject javaThis, jstring nam return soa.AddLocalReference<jobject>(result); } +static jobject Class_getDeclaredConstructorInternal( + JNIEnv* env, jobject javaThis, jobjectArray args) { + ScopedFastNativeObjectAccess soa(env); + auto* klass = DecodeClass(soa, javaThis); + auto* params = soa.Decode<mirror::ObjectArray<mirror::Class>*>(args); + StackHandleScope<1> hs(soa.Self()); + auto* declared_constructor = klass->GetDeclaredConstructor(soa.Self(), hs.NewHandle(params)); + if (declared_constructor != nullptr) { + return soa.AddLocalReference<jobject>( + mirror::Constructor::CreateFromArtMethod(soa.Self(), declared_constructor)); + } + return nullptr; +} + +static ALWAYS_INLINE inline bool MethodMatchesConstructor(mirror::ArtMethod* m, bool public_only) + SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) { + DCHECK(m != nullptr); + return (!public_only || m->IsPublic()) && !m->IsStatic() && m->IsConstructor(); +} + +static jobjectArray Class_getDeclaredConstructorsInternal( + JNIEnv* env, jobject javaThis, jboolean publicOnly) { + ScopedFastNativeObjectAccess soa(env); + auto* klass = DecodeClass(soa, javaThis); + StackHandleScope<2> hs(soa.Self()); + auto h_direct_methods = hs.NewHandle(klass->GetDirectMethods()); + size_t constructor_count = 0; + auto count = h_direct_methods.Get() != nullptr ? h_direct_methods->GetLength() : 0u; + // Two pass approach for speed. + for (size_t i = 0; i < count; ++i) { + constructor_count += MethodMatchesConstructor(h_direct_methods->GetWithoutChecks(i), + publicOnly != JNI_FALSE) ? 1u : 0u; + } + auto h_constructors = hs.NewHandle(mirror::ObjectArray<mirror::Constructor>::Alloc( + soa.Self(), mirror::Constructor::ArrayClass(), constructor_count)); + if (UNLIKELY(h_constructors.Get() == nullptr)) { + soa.Self()->AssertPendingException(); + return nullptr; + } + constructor_count = 0; + for (size_t i = 0; i < count; ++i) { + auto* method = h_direct_methods->GetWithoutChecks(i); + if (MethodMatchesConstructor(method, publicOnly != JNI_FALSE)) { + auto* constructor = mirror::Constructor::CreateFromArtMethod(soa.Self(), method); + if (UNLIKELY(constructor == nullptr)) { + soa.Self()->AssertPendingException(); + return nullptr; + } + h_constructors->SetWithoutChecks<false>(constructor_count++, constructor); + } + } + return soa.AddLocalReference<jobjectArray>(h_constructors.Get()); +} + +static jobject Class_getDeclaredMethodInternal(JNIEnv* env, jobject javaThis, + jobject name, jobjectArray args) { + // Covariant return types permit the class to define multiple + // methods with the same name and parameter types. Prefer to + // return a non-synthetic method in such situations. We may + // still return a synthetic method to handle situations like + // escalated visibility. We never return miranda methods that + // were synthesized by the runtime. + constexpr uint32_t kSkipModifiers = kAccMiranda | kAccSynthetic; + ScopedFastNativeObjectAccess soa(env); + StackHandleScope<5> hs(soa.Self()); + auto h_method_name = hs.NewHandle(soa.Decode<mirror::String*>(name)); + if (UNLIKELY(h_method_name.Get() == nullptr)) { + ThrowNullPointerException("name == null"); + return nullptr; + } + auto h_args = hs.NewHandle(soa.Decode<mirror::ObjectArray<mirror::Class>*>(args)); + auto* klass = DecodeClass(soa, javaThis); + mirror::ArtMethod* result = nullptr; + auto* virtual_methods = klass->GetVirtualMethods(); + if (virtual_methods != nullptr) { + auto h_virtual_methods = hs.NewHandle(virtual_methods); + for (size_t i = 0, count = virtual_methods->GetLength(); i < count; ++i) { + auto* m = h_virtual_methods->GetWithoutChecks(i); + auto* np_method = m->GetInterfaceMethodIfProxy(); + // May cause thread suspension. + mirror::String* np_name = np_method->GetNameAsString(soa.Self()); + if (!np_name->Equals(h_method_name.Get()) || !np_method->EqualParameters(h_args)) { + if (UNLIKELY(soa.Self()->IsExceptionPending())) { + return nullptr; + } + continue; + } + auto modifiers = m->GetAccessFlags(); + if ((modifiers & kSkipModifiers) == 0) { + return soa.AddLocalReference<jobject>(mirror::Method::CreateFromArtMethod(soa.Self(), m)); + } + if ((modifiers & kAccMiranda) == 0) { + result = m; // Remember as potential result if it's not a miranda method. + } + } + } + if (result == nullptr) { + auto* direct_methods = klass->GetDirectMethods(); + if (direct_methods != nullptr) { + auto h_direct_methods = hs.NewHandle(direct_methods); + for (size_t i = 0, count = direct_methods->GetLength(); i < count; ++i) { + auto* m = h_direct_methods->GetWithoutChecks(i); + auto modifiers = m->GetAccessFlags(); + if ((modifiers & kAccConstructor) != 0) { + continue; + } + auto* np_method = m->GetInterfaceMethodIfProxy(); + // May cause thread suspension. + mirror::String* np_name = np_method ->GetNameAsString(soa.Self()); + if (np_name == nullptr) { + soa.Self()->AssertPendingException(); + return nullptr; + } + if (!np_name->Equals(h_method_name.Get()) || !np_method->EqualParameters(h_args)) { + if (UNLIKELY(soa.Self()->IsExceptionPending())) { + return nullptr; + } + continue; + } + if ((modifiers & kSkipModifiers) == 0) { + return soa.AddLocalReference<jobject>(mirror::Method::CreateFromArtMethod( + soa.Self(), m)); + } + // Direct methods cannot be miranda methods, so this potential result must be synthetic. + result = m; + } + } + } + return result != nullptr ? + soa.AddLocalReference<jobject>(mirror::Method::CreateFromArtMethod(soa.Self(), result)) : + nullptr; +} + +jobjectArray Class_getDeclaredMethodsUnchecked(JNIEnv* env, jobject javaThis, + jboolean publicOnly) { + ScopedFastNativeObjectAccess soa(env); + StackHandleScope<5> hs(soa.Self()); + auto* klass = DecodeClass(soa, javaThis); + auto virtual_methods = hs.NewHandle(klass->GetVirtualMethods()); + auto direct_methods = hs.NewHandle(klass->GetDirectMethods()); + size_t num_methods = 0; + if (virtual_methods.Get() != nullptr) { + for (size_t i = 0, count = virtual_methods->GetLength(); i < count; ++i) { + auto* m = virtual_methods->GetWithoutChecks(i); + auto modifiers = m->GetAccessFlags(); + if ((publicOnly == JNI_FALSE || (modifiers & kAccPublic) != 0) && + (modifiers & kAccMiranda) == 0) { + ++num_methods; + } + } + } + if (direct_methods.Get() != nullptr) { + for (size_t i = 0, count = direct_methods->GetLength(); i < count; ++i) { + auto* m = direct_methods->GetWithoutChecks(i); + auto modifiers = m->GetAccessFlags(); + // Add non-constructor direct/static methods. + if ((publicOnly == JNI_FALSE || (modifiers & kAccPublic) != 0) && + (modifiers & kAccConstructor) == 0) { + ++num_methods; + } + } + } + auto ret = hs.NewHandle(mirror::ObjectArray<mirror::Method>::Alloc( + soa.Self(), mirror::Method::ArrayClass(), num_methods)); + num_methods = 0; + if (virtual_methods.Get() != nullptr) { + for (size_t i = 0, count = virtual_methods->GetLength(); i < count; ++i) { + auto* m = virtual_methods->GetWithoutChecks(i); + auto modifiers = m->GetAccessFlags(); + if ((publicOnly == JNI_FALSE || (modifiers & kAccPublic) != 0) && + (modifiers & kAccMiranda) == 0) { + auto* method = mirror::Method::CreateFromArtMethod(soa.Self(), m); + if (method == nullptr) { + soa.Self()->AssertPendingException(); + return nullptr; + } + ret->SetWithoutChecks<false>(num_methods++, method); + } + } + } + if (direct_methods.Get() != nullptr) { + for (size_t i = 0, count = direct_methods->GetLength(); i < count; ++i) { + auto* m = direct_methods->GetWithoutChecks(i); + auto modifiers = m->GetAccessFlags(); + // Add non-constructor direct/static methods. + if ((publicOnly == JNI_FALSE || (modifiers & kAccPublic) != 0) && + (modifiers & kAccConstructor) == 0) { + auto* method = mirror::Method::CreateFromArtMethod(soa.Self(), m); + if (method == nullptr) { + soa.Self()->AssertPendingException(); + return nullptr; + } + ret->SetWithoutChecks<false>(num_methods++, method); + } + } + } + return soa.AddLocalReference<jobjectArray>(ret.Get()); +} + static JNINativeMethod gMethods[] = { - NATIVE_METHOD(Class, classForName, "!(Ljava/lang/String;ZLjava/lang/ClassLoader;)Ljava/lang/Class;"), - NATIVE_METHOD(Class, findOverriddenMethodIfProxy, - "!(Ljava/lang/reflect/ArtMethod;)Ljava/lang/reflect/ArtMethod;"), + NATIVE_METHOD(Class, classForName, + "!(Ljava/lang/String;ZLjava/lang/ClassLoader;)Ljava/lang/Class;"), + NATIVE_METHOD(Class, getDeclaredConstructorInternal, + "!([Ljava/lang/Class;)Ljava/lang/reflect/Constructor;"), + NATIVE_METHOD(Class, getDeclaredConstructorsInternal, "!(Z)[Ljava/lang/reflect/Constructor;"), + NATIVE_METHOD(Class, getDeclaredField, "!(Ljava/lang/String;)Ljava/lang/reflect/Field;"), + NATIVE_METHOD(Class, getDeclaredFieldInternal, "!(Ljava/lang/String;)Ljava/lang/reflect/Field;"), + NATIVE_METHOD(Class, getDeclaredFields, "!()[Ljava/lang/reflect/Field;"), + NATIVE_METHOD(Class, getDeclaredFieldsUnchecked, "!(Z)[Ljava/lang/reflect/Field;"), + NATIVE_METHOD(Class, getDeclaredMethodInternal, + "!(Ljava/lang/String;[Ljava/lang/Class;)Ljava/lang/reflect/Method;"), + NATIVE_METHOD(Class, getDeclaredMethodsUnchecked, + "!(Z)[Ljava/lang/reflect/Method;"), NATIVE_METHOD(Class, getNameNative, "!()Ljava/lang/String;"), NATIVE_METHOD(Class, getProxyInterfaces, "!()[Ljava/lang/Class;"), - NATIVE_METHOD(Class, getDeclaredFields, "!()[Ljava/lang/reflect/Field;"), NATIVE_METHOD(Class, getPublicDeclaredFields, "!()[Ljava/lang/reflect/Field;"), - NATIVE_METHOD(Class, getDeclaredFieldsUnchecked, "!(Z)[Ljava/lang/reflect/Field;"), - NATIVE_METHOD(Class, getDeclaredFieldInternal, "!(Ljava/lang/String;)Ljava/lang/reflect/Field;"), - NATIVE_METHOD(Class, getDeclaredField, "!(Ljava/lang/String;)Ljava/lang/reflect/Field;"), }; void register_java_lang_Class(JNIEnv* env) { diff --git a/runtime/native/java_lang_reflect_Constructor.cc b/runtime/native/java_lang_reflect_Constructor.cc index 5e1a4c5..c33f81a 100644 --- a/runtime/native/java_lang_reflect_Constructor.cc +++ b/runtime/native/java_lang_reflect_Constructor.cc @@ -21,6 +21,7 @@ #include "mirror/art_method.h" #include "mirror/art_method-inl.h" #include "mirror/class-inl.h" +#include "mirror/method.h" #include "mirror/object-inl.h" #include "reflection.h" #include "scoped_fast_native_object_access.h" @@ -28,17 +29,10 @@ namespace art { -/* - * We get here through Constructor.newInstance(). The Constructor object - * would not be available if the constructor weren't public (per the - * definition of Class.getConstructor), so we can skip the method access - * check. We can also safely assume the constructor isn't associated - * with an interface, array, or primitive class. - */ -static jobject Constructor_newInstance(JNIEnv* env, jobject javaMethod, jobjectArray javaArgs, - jboolean accessible) { +static ALWAYS_INLINE inline jobject NewInstanceHelper( + JNIEnv* env, jobject javaMethod, jobjectArray javaArgs, size_t num_frames) { ScopedFastNativeObjectAccess soa(env); - mirror::ArtMethod* m = mirror::ArtMethod::FromReflectedMethod(soa, javaMethod); + mirror::Method* m = soa.Decode<mirror::Method*>(javaMethod); StackHandleScope<1> hs(soa.Self()); Handle<mirror::Class> c(hs.NewHandle(m->GetDeclaringClass())); if (UNLIKELY(c->IsAbstract())) { @@ -67,14 +61,31 @@ static jobject Constructor_newInstance(JNIEnv* env, jobject javaMethod, jobjectA } jobject javaReceiver = soa.AddLocalReference<jobject>(receiver); - InvokeMethod(soa, javaMethod, javaReceiver, javaArgs, (accessible == JNI_TRUE)); + InvokeMethod(soa, javaMethod, javaReceiver, javaArgs, num_frames); // Constructors are ()V methods, so we shouldn't touch the result of InvokeMethod. return javaReceiver; } +/* + * We get here through Constructor.newInstance(). The Constructor object + * would not be available if the constructor weren't public (per the + * definition of Class.getConstructor), so we can skip the method access + * check. We can also safely assume the constructor isn't associated + * with an interface, array, or primitive class. + */ +static jobject Constructor_newInstance(JNIEnv* env, jobject javaMethod, jobjectArray javaArgs) { + return NewInstanceHelper(env, javaMethod, javaArgs, 1); +} + +static jobject Constructor_newInstanceTwoFrames(JNIEnv* env, jobject javaMethod, + jobjectArray javaArgs) { + return NewInstanceHelper(env, javaMethod, javaArgs, 2); +} + static JNINativeMethod gMethods[] = { - NATIVE_METHOD(Constructor, newInstance, "!([Ljava/lang/Object;Z)Ljava/lang/Object;"), + NATIVE_METHOD(Constructor, newInstance, "!([Ljava/lang/Object;)Ljava/lang/Object;"), + NATIVE_METHOD(Constructor, newInstanceTwoFrames, "!([Ljava/lang/Object;)Ljava/lang/Object;"), }; void register_java_lang_reflect_Constructor(JNIEnv* env) { diff --git a/runtime/native/java_lang_reflect_Method.cc b/runtime/native/java_lang_reflect_Method.cc index 9859746..c20d832 100644 --- a/runtime/native/java_lang_reflect_Method.cc +++ b/runtime/native/java_lang_reflect_Method.cc @@ -30,9 +30,9 @@ namespace art { static jobject Method_invoke(JNIEnv* env, jobject javaMethod, jobject javaReceiver, - jobject javaArgs, jboolean accessible) { + jobject javaArgs) { ScopedFastNativeObjectAccess soa(env); - return InvokeMethod(soa, javaMethod, javaReceiver, javaArgs, (accessible == JNI_TRUE)); + return InvokeMethod(soa, javaMethod, javaReceiver, javaArgs); } static jobject Method_getExceptionTypesNative(JNIEnv* env, jobject javaMethod) { @@ -55,7 +55,7 @@ static jobject Method_getExceptionTypesNative(JNIEnv* env, jobject javaMethod) { } static JNINativeMethod gMethods[] = { - NATIVE_METHOD(Method, invoke, "!(Ljava/lang/Object;[Ljava/lang/Object;Z)Ljava/lang/Object;"), + NATIVE_METHOD(Method, invoke, "!(Ljava/lang/Object;[Ljava/lang/Object;)Ljava/lang/Object;"), NATIVE_METHOD(Method, getExceptionTypesNative, "!()[Ljava/lang/Class;"), }; diff --git a/runtime/native/java_lang_reflect_Proxy.cc b/runtime/native/java_lang_reflect_Proxy.cc index baf8b24..4a6ab40 100644 --- a/runtime/native/java_lang_reflect_Proxy.cc +++ b/runtime/native/java_lang_reflect_Proxy.cc @@ -30,13 +30,12 @@ static jclass Proxy_generateProxy(JNIEnv* env, jclass, jstring name, jobjectArra jobject loader, jobjectArray methods, jobjectArray throws) { ScopedFastNativeObjectAccess soa(env); ClassLinker* class_linker = Runtime::Current()->GetClassLinker(); - mirror::Class* result = class_linker->CreateProxyClass(soa, name, interfaces, loader, methods, - throws); - return soa.AddLocalReference<jclass>(result); + return soa.AddLocalReference<jclass>(class_linker->CreateProxyClass( + soa, name, interfaces, loader, methods, throws)); } static JNINativeMethod gMethods[] = { - NATIVE_METHOD(Proxy, generateProxy, "!(Ljava/lang/String;[Ljava/lang/Class;Ljava/lang/ClassLoader;[Ljava/lang/reflect/ArtMethod;[[Ljava/lang/Class;)Ljava/lang/Class;"), + NATIVE_METHOD(Proxy, generateProxy, "!(Ljava/lang/String;[Ljava/lang/Class;Ljava/lang/ClassLoader;[Ljava/lang/reflect/Method;[[Ljava/lang/Class;)Ljava/lang/Class;"), }; void register_java_lang_reflect_Proxy(JNIEnv* env) { diff --git a/runtime/proxy_test.cc b/runtime/proxy_test.cc index 6061f73..b471293 100644 --- a/runtime/proxy_test.cc +++ b/runtime/proxy_test.cc @@ -20,6 +20,7 @@ #include "art_field-inl.h" #include "class_linker-inl.h" #include "common_compiler_test.h" +#include "mirror/method.h" #include "scoped_thread_state_change.h" namespace art { @@ -53,41 +54,34 @@ class ProxyTest : public CommonCompilerTest { mirror::ObjectArray<mirror::ArtMethod>* virtual_methods = interface->GetVirtualMethods(); methods_count += (virtual_methods == nullptr) ? 0 : virtual_methods->GetLength(); } - jclass javaLangReflectArtMethod = - soa.AddLocalReference<jclass>(mirror::ArtMethod::GetJavaLangReflectArtMethod()); - jobjectArray proxyClassMethods = soa.Env()->NewObjectArray(methods_count, - javaLangReflectArtMethod, nullptr); + jobjectArray proxyClassMethods = soa.Env()->NewObjectArray( + methods_count, soa.AddLocalReference<jclass>(mirror::Method::StaticClass()), nullptr); soa.Self()->AssertNoPendingException(); - // Fill the method array - mirror::ArtMethod* equalsMethod = javaLangObject->FindDeclaredVirtualMethod("equals", - "(Ljava/lang/Object;)Z"); - mirror::ArtMethod* hashCodeMethod = javaLangObject->FindDeclaredVirtualMethod("hashCode", - "()I"); - mirror::ArtMethod* toStringMethod = javaLangObject->FindDeclaredVirtualMethod("toString", - "()Ljava/lang/String;"); - CHECK(equalsMethod != nullptr); - CHECK(hashCodeMethod != nullptr); - CHECK(toStringMethod != nullptr); - jsize array_index = 0; - // Adds Object methods. - soa.Env()->SetObjectArrayElement(proxyClassMethods, array_index++, - soa.AddLocalReference<jobject>(equalsMethod)); - soa.Env()->SetObjectArrayElement(proxyClassMethods, array_index++, - soa.AddLocalReference<jobject>(hashCodeMethod)); - soa.Env()->SetObjectArrayElement(proxyClassMethods, array_index++, - soa.AddLocalReference<jobject>(toStringMethod)); - + // Fill the method array + mirror::ArtMethod* method = javaLangObject->FindDeclaredVirtualMethod( + "equals", "(Ljava/lang/Object;)Z"); + CHECK(method != nullptr); + soa.Env()->SetObjectArrayElement( + proxyClassMethods, array_index++, soa.AddLocalReference<jobject>( + mirror::Method::CreateFromArtMethod(soa.Self(), method))); + method = javaLangObject->FindDeclaredVirtualMethod("hashCode", "()I"); + CHECK(method != nullptr); + soa.Env()->SetObjectArrayElement( + proxyClassMethods, array_index++, soa.AddLocalReference<jobject>( + mirror::Method::CreateFromArtMethod(soa.Self(), method))); + method = javaLangObject->FindDeclaredVirtualMethod("toString", "()Ljava/lang/String;"); + CHECK(method != nullptr); + soa.Env()->SetObjectArrayElement( + proxyClassMethods, array_index++, soa.AddLocalReference<jobject>( + mirror::Method::CreateFromArtMethod(soa.Self(), method))); // Now adds all interfaces virtual methods. for (mirror::Class* interface : interfaces) { - mirror::ObjectArray<mirror::ArtMethod>* virtual_methods = interface->GetVirtualMethods(); - if (virtual_methods != nullptr) { - for (int32_t mth_index = 0; mth_index < virtual_methods->GetLength(); ++mth_index) { - mirror::ArtMethod* method = virtual_methods->Get(mth_index); - soa.Env()->SetObjectArrayElement(proxyClassMethods, array_index++, - soa.AddLocalReference<jobject>(method)); - } + for (int32_t i = 0, count = interface->NumVirtualMethods(); i < count; ++i) { + soa.Env()->SetObjectArrayElement( + proxyClassMethods, array_index++, soa.AddLocalReference<jobject>( + mirror::Method::CreateFromArtMethod(soa.Self(), interface->GetVirtualMethod(i)))); } } CHECK_EQ(array_index, methods_count); @@ -96,10 +90,9 @@ class ProxyTest : public CommonCompilerTest { jobjectArray proxyClassThrows = soa.Env()->NewObjectArray(0, javaLangClass, nullptr); soa.Self()->AssertNoPendingException(); - mirror::Class* proxyClass = class_linker_->CreateProxyClass(soa, - soa.Env()->NewStringUTF(className), - proxyClassInterfaces, jclass_loader, - proxyClassMethods, proxyClassThrows); + mirror::Class* proxyClass = class_linker_->CreateProxyClass( + soa, soa.Env()->NewStringUTF(className), proxyClassInterfaces, jclass_loader, + proxyClassMethods, proxyClassThrows); soa.Self()->AssertNoPendingException(); return proxyClass; } diff --git a/runtime/reflection.cc b/runtime/reflection.cc index 3e1315c..e546738 100644 --- a/runtime/reflection.cc +++ b/runtime/reflection.cc @@ -22,6 +22,7 @@ #include "dex_file-inl.h" #include "entrypoints/entrypoint_utils.h" #include "jni_internal.h" +#include "mirror/abstract_method.h" #include "mirror/art_method-inl.h" #include "mirror/class-inl.h" #include "mirror/object_array-inl.h" @@ -537,7 +538,7 @@ void InvokeWithShadowFrame(Thread* self, ShadowFrame* shadow_frame, uint16_t arg } jobject InvokeMethod(const ScopedObjectAccessAlreadyRunnable& soa, jobject javaMethod, - jobject javaReceiver, jobject javaArgs, bool accessible) { + jobject javaReceiver, jobject javaArgs, size_t num_frames) { // We want to make sure that the stack is not within a small distance from the // protected region in case we are calling into a leaf function whose stack // check has been elided. @@ -547,7 +548,9 @@ jobject InvokeMethod(const ScopedObjectAccessAlreadyRunnable& soa, jobject javaM return nullptr; } - mirror::ArtMethod* m = mirror::ArtMethod::FromReflectedMethod(soa, javaMethod); + auto* abstract_method = soa.Decode<mirror::AbstractMethod*>(javaMethod); + const bool accessible = abstract_method->IsAccessible(); + mirror::ArtMethod* m = abstract_method->GetArtMethod(); mirror::Class* declaring_class = m->GetDeclaringClass(); if (UNLIKELY(!declaring_class->IsInitialized())) { @@ -572,8 +575,7 @@ jobject InvokeMethod(const ScopedObjectAccessAlreadyRunnable& soa, jobject javaM } // Get our arrays of arguments and their types, and check they're the same size. - mirror::ObjectArray<mirror::Object>* objects = - soa.Decode<mirror::ObjectArray<mirror::Object>*>(javaArgs); + auto* objects = soa.Decode<mirror::ObjectArray<mirror::Object>*>(javaArgs); const DexFile::TypeList* classes = m->GetParameterTypeList(); uint32_t classes_size = (classes == nullptr) ? 0 : classes->Size(); uint32_t arg_count = (objects != nullptr) ? objects->GetLength() : 0; @@ -586,7 +588,7 @@ jobject InvokeMethod(const ScopedObjectAccessAlreadyRunnable& soa, jobject javaM // If method is not set to be accessible, verify it can be accessed by the caller. mirror::Class* calling_class = nullptr; if (!accessible && !VerifyAccess(soa.Self(), receiver, declaring_class, m->GetAccessFlags(), - &calling_class, 2)) { + &calling_class, num_frames)) { ThrowIllegalAccessException( StringPrintf("Class %s cannot access %s method %s of class %s", calling_class == nullptr ? "null" : PrettyClass(calling_class).c_str(), diff --git a/runtime/reflection.h b/runtime/reflection.h index c2d406a..c63f858 100644 --- a/runtime/reflection.h +++ b/runtime/reflection.h @@ -65,8 +65,9 @@ void InvokeWithShadowFrame(Thread* self, ShadowFrame* shadow_frame, uint16_t arg JValue* result) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_); +// num_frames is number of frames we look up for access check. jobject InvokeMethod(const ScopedObjectAccessAlreadyRunnable& soa, jobject method, jobject receiver, - jobject args, bool accessible) + jobject args, size_t num_frames = 1) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_); ALWAYS_INLINE bool VerifyObjectIsClass(mirror::Object* o, mirror::Class* c) diff --git a/runtime/runtime.cc b/runtime/runtime.cc index 7bebb96..2fc8d20 100644 --- a/runtime/runtime.cc +++ b/runtime/runtime.cc @@ -77,6 +77,7 @@ #include "mirror/class-inl.h" #include "mirror/class_loader.h" #include "mirror/field.h" +#include "mirror/method.h" #include "mirror/stack_trace_element.h" #include "mirror/throwable.h" #include "monitor.h" @@ -1308,7 +1309,9 @@ void Runtime::VisitConstantRoots(RootVisitor* visitor) { // need to be visited once per GC since they never change. mirror::ArtMethod::VisitRoots(visitor); mirror::Class::VisitRoots(visitor); + mirror::Constructor::VisitRoots(visitor); mirror::Reference::VisitRoots(visitor); + mirror::Method::VisitRoots(visitor); mirror::StackTraceElement::VisitRoots(visitor); mirror::String::VisitRoots(visitor); mirror::Throwable::VisitRoots(visitor); diff --git a/runtime/well_known_classes.cc b/runtime/well_known_classes.cc index d389244..f57f9c4 100644 --- a/runtime/well_known_classes.cc +++ b/runtime/well_known_classes.cc @@ -212,7 +212,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_Proxy_invoke = CacheMethod(env, java_lang_reflect_Proxy, true, "invoke", "(Ljava/lang/reflect/Proxy;Ljava/lang/reflect/ArtMethod;[Ljava/lang/Object;)Ljava/lang/Object;"); + 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_init = CacheMethod(env, java_lang_Thread, false, "<init>", "(Ljava/lang/ThreadGroup;Ljava/lang/String;IZ)V"); java_lang_Thread_run = CacheMethod(env, java_lang_Thread, false, "run", "()V"); java_lang_Thread__UncaughtExceptionHandler_uncaughtException = CacheMethod(env, java_lang_Thread__UncaughtExceptionHandler, false, "uncaughtException", "(Ljava/lang/Thread;Ljava/lang/Throwable;)V"); |