Move getPublicFieldRecursive to native JNI
Benchmark: libcore/benchmarks/src/benchmarks/regression/ReflectionBenchmark.java
Previous benchmarks:
Class_getField 814.26 ns; σ=6.44 ns @ 3 trials
GetInterfaceStaticField 1552.28 ns; σ=38.22 ns @ 10 trials
GetSuperClassField 939.85 ns; σ=2.94 ns @ 3 trials
New benchmarks:
Class_getField 735.97 ns; σ=0.98 ns @ 3 trials
GetInterfaceStaticField 1178.98 ns; σ=6.14 ns @ 3 trials
GetSuperClassField 853.76 ns; σ=16.86 ns @ 10 trials
Bug: 24209213
Change-Id: I08073cb36b007ac33af010dab917a6f1e51107c0
diff --git a/runtime/native/java_lang_Class.cc b/runtime/native/java_lang_Class.cc
index 8fd6849..5da15df 100644
--- a/runtime/native/java_lang_Class.cc
+++ b/runtime/native/java_lang_Class.cc
@@ -229,6 +229,65 @@
return nullptr;
}
+static mirror::Field* GetPublicFieldRecursive(
+ Thread* self, mirror::Class* clazz, mirror::String* name)
+ SHARED_REQUIRES(Locks::mutator_lock_) {
+ DCHECK(clazz != nullptr);
+ DCHECK(name != nullptr);
+ DCHECK(self != nullptr);
+
+ StackHandleScope<1> hs(self);
+ MutableHandle<mirror::Class> h_clazz(hs.NewHandle(clazz));
+
+ // We search the current class, its direct interfaces then its superclass.
+ while (h_clazz.Get() != nullptr) {
+ mirror::Field* result = GetDeclaredField(self, h_clazz.Get(), name);
+ if ((result != nullptr) && (result->GetAccessFlags() & kAccPublic)) {
+ return result;
+ } else if (UNLIKELY(self->IsExceptionPending())) {
+ // Something went wrong. Bail out.
+ return nullptr;
+ }
+
+ uint32_t num_direct_interfaces = h_clazz->NumDirectInterfaces();
+ for (uint32_t i = 0; i < num_direct_interfaces; i++) {
+ mirror::Class *iface = mirror::Class::GetDirectInterface(self, h_clazz, i);
+ if (UNLIKELY(iface == nullptr)) {
+ self->AssertPendingException();
+ return nullptr;
+ }
+ result = GetPublicFieldRecursive(self, iface, name);
+ if (result != nullptr) {
+ DCHECK(result->GetAccessFlags() & kAccPublic);
+ return result;
+ } else if (UNLIKELY(self->IsExceptionPending())) {
+ // Something went wrong. Bail out.
+ return nullptr;
+ }
+ }
+
+ // We don't try the superclass if we are an interface.
+ if (h_clazz->IsInterface()) {
+ break;
+ }
+
+ // Get the next class.
+ h_clazz.Assign(h_clazz->GetSuperClass());
+ }
+ return nullptr;
+}
+
+static jobject Class_getPublicFieldRecursive(JNIEnv* env, jobject javaThis, jstring name) {
+ ScopedFastNativeObjectAccess soa(env);
+ auto* name_string = soa.Decode<mirror::String*>(name);
+ if (UNLIKELY(name_string == nullptr)) {
+ ThrowNullPointerException("name == null");
+ return nullptr;
+ }
+ return soa.AddLocalReference<jobject>(
+ GetPublicFieldRecursive(soa.Self(), DecodeClass(soa, javaThis), name_string));
+}
+
static jobject Class_getDeclaredFieldInternal(JNIEnv* env, jobject javaThis, jstring name) {
ScopedFastNativeObjectAccess soa(env);
auto* name_string = soa.Decode<mirror::String*>(name);
@@ -678,6 +737,7 @@
"!([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, getPublicFieldRecursive, "!(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;"),