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
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 @@
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_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 @@
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 @@
}
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 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 @@
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) {