diff options
Diffstat (limited to 'runtime/native/java_lang_Class.cc')
-rw-r--r-- | runtime/native/java_lang_Class.cc | 169 |
1 files changed, 168 insertions, 1 deletions
diff --git a/runtime/native/java_lang_Class.cc b/runtime/native/java_lang_Class.cc index 60d14e9c7a..3cb6b367f0 100644 --- a/runtime/native/java_lang_Class.cc +++ b/runtime/native/java_lang_Class.cc @@ -17,21 +17,28 @@ #include "java_lang_Class.h" #include "class_linker.h" +#include "common_throws.h" #include "dex_file-inl.h" #include "jni_internal.h" #include "nth_caller_visitor.h" +#include "mirror/art_field-inl.h" #include "mirror/class-inl.h" #include "mirror/class_loader.h" +#include "mirror/field.h" #include "mirror/object-inl.h" +#include "mirror/object_array-inl.h" +#include "mirror/string-inl.h" #include "scoped_thread_state_change.h" #include "scoped_fast_native_object_access.h" #include "ScopedLocalRef.h" #include "ScopedUtfChars.h" +#include "utf.h" #include "well_known_classes.h" namespace art { -static mirror::Class* DecodeClass(const ScopedFastNativeObjectAccess& soa, jobject java_class) +ALWAYS_INLINE static inline mirror::Class* DecodeClass( + const ScopedFastNativeObjectAccess& soa, jobject java_class) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) { mirror::Class* c = soa.Decode<mirror::Class*>(java_class); DCHECK(c != NULL); @@ -97,10 +104,170 @@ static jobjectArray Class_getProxyInterfaces(JNIEnv* env, jobject javaThis) { return soa.AddLocalReference<jobjectArray>(c->GetInterfaces()->Clone(soa.Self())); } +static mirror::ObjectArray<mirror::Field>* GetDeclaredFields( + Thread* self, mirror::Class* klass, bool public_only, bool force_resolve) + SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) { + StackHandleScope<3> hs(self); + auto h_ifields = hs.NewHandle(klass->GetIFields()); + auto h_sfields = hs.NewHandle(klass->GetSFields()); + const int32_t num_ifields = h_ifields.Get() != nullptr ? h_ifields->GetLength() : 0; + const int32_t num_sfields = h_sfields.Get() != nullptr ? h_sfields->GetLength() : 0; + int32_t array_size = num_ifields + num_sfields; + if (public_only) { + // Lets go subtract all the non public fields. + for (int32_t i = 0; i < num_ifields; ++i) { + if (!h_ifields->GetWithoutChecks(i)->IsPublic()) { + --array_size; + } + } + for (int32_t i = 0; i < num_sfields; ++i) { + if (!h_sfields->GetWithoutChecks(i)->IsPublic()) { + --array_size; + } + } + } + int32_t array_idx = 0; + auto object_array = hs.NewHandle(mirror::ObjectArray<mirror::Field>::Alloc( + self, mirror::Field::ArrayClass(), array_size)); + if (object_array.Get() == nullptr) { + return nullptr; + } + for (int32_t i = 0; i < num_ifields; ++i) { + auto* art_field = h_ifields->GetWithoutChecks(i); + if (!public_only || art_field->IsPublic()) { + auto* field = mirror::Field::CreateFromArtField(self, art_field, force_resolve); + if (field == nullptr) { + if (kIsDebugBuild) { + self->AssertPendingException(); + } + // Maybe null due to OOME or type resolving exception. + return nullptr; + } + object_array->SetWithoutChecks<false>(array_idx++, field); + } + } + for (int32_t i = 0; i < num_sfields; ++i) { + auto* art_field = h_sfields->GetWithoutChecks(i); + if (!public_only || art_field->IsPublic()) { + auto* field = mirror::Field::CreateFromArtField(self, art_field, force_resolve); + if (field == nullptr) { + if (kIsDebugBuild) { + self->AssertPendingException(); + } + return nullptr; + } + object_array->SetWithoutChecks<false>(array_idx++, field); + } + } + CHECK_EQ(array_idx, array_size); + return object_array.Get(); +} + +static jobjectArray Class_getDeclaredFieldsUnchecked(JNIEnv* env, jobject javaThis, + jboolean publicOnly) { + ScopedFastNativeObjectAccess soa(env); + return soa.AddLocalReference<jobjectArray>( + GetDeclaredFields(soa.Self(), DecodeClass(soa, javaThis), publicOnly != JNI_FALSE, false)); +} + +static jobjectArray Class_getDeclaredFields(JNIEnv* env, jobject javaThis) { + ScopedFastNativeObjectAccess soa(env); + return soa.AddLocalReference<jobjectArray>( + GetDeclaredFields(soa.Self(), DecodeClass(soa, javaThis), false, true)); +} + +static jobjectArray Class_getPublicDeclaredFields(JNIEnv* env, jobject javaThis) { + ScopedFastNativeObjectAccess soa(env); + return soa.AddLocalReference<jobjectArray>( + GetDeclaredFields(soa.Self(), DecodeClass(soa, javaThis), true, true)); +} + +// Performs a binary search through an array of fields, TODO: Is this fast enough if we don't use +// the dex cache for lookups? I think CompareModifiedUtf8ToUtf16AsCodePointValues should be fairly +// fast. +ALWAYS_INLINE static inline mirror::ArtField* FindFieldByName( + Thread* self ATTRIBUTE_UNUSED, mirror::String* name, + mirror::ObjectArray<mirror::ArtField>* fields) + SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) { + uint32_t low = 0; + uint32_t high = fields->GetLength(); + const uint16_t* const data = name->GetCharArray()->GetData() + name->GetOffset(); + const size_t length = name->GetLength(); + while (low < high) { + auto mid = (low + high) / 2; + mirror::ArtField* const field = fields->GetWithoutChecks(mid); + int result = CompareModifiedUtf8ToUtf16AsCodePointValues(field->GetName(), data, length); + // Alternate approach, only a few % faster at the cost of more allocations. + // int result = field->GetStringName(self, true)->CompareTo(name); + if (result < 0) { + low = mid + 1; + } else if (result > 0) { + high = mid; + } else { + return field; + } + } + if (kIsDebugBuild) { + for (int32_t i = 0; i < fields->GetLength(); ++i) { + CHECK_NE(fields->GetWithoutChecks(i)->GetName(), name->ToModifiedUtf8()); + } + } + return nullptr; +} + +ALWAYS_INLINE static inline mirror::Field* GetDeclaredField( + Thread* self, mirror::Class* c, mirror::String* name) + SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) { + auto* instance_fields = c->GetIFields(); + if (instance_fields != nullptr) { + auto* art_field = FindFieldByName(self, name, instance_fields); + if (art_field != nullptr) { + return mirror::Field::CreateFromArtField(self, art_field, true); + } + } + auto* static_fields = c->GetSFields(); + if (static_fields != nullptr) { + auto* art_field = FindFieldByName(self, name, static_fields); + if (art_field != nullptr) { + return mirror::Field::CreateFromArtField(self, art_field, true); + } + } + return nullptr; +} + +static jobject Class_getDeclaredFieldInternal(JNIEnv* env, jobject javaThis, jstring name) { + ScopedFastNativeObjectAccess soa(env); + auto* name_string = soa.Decode<mirror::String*>(name); + return soa.AddLocalReference<jobject>( + GetDeclaredField(soa.Self(), DecodeClass(soa, javaThis), name_string)); +} + +static jobject Class_getDeclaredField(JNIEnv* env, jobject javaThis, jstring name) { + ScopedFastNativeObjectAccess soa(env); + auto* name_string = soa.Decode<mirror::String*>(name); + if (name == nullptr) { + ThrowNullPointerException("name == null"); + return nullptr; + } + auto* klass = DecodeClass(soa, javaThis); + mirror::Field* result = GetDeclaredField(soa.Self(), klass, name_string); + if (result == nullptr) { + std::string name_str = name_string->ToModifiedUtf8(); + soa.Self()->ThrowNewException("Ljava/lang/NoSuchFieldException;", name_str.c_str()); + return nullptr; + } + return soa.AddLocalReference<jobject>(result); +} + static JNINativeMethod gMethods[] = { NATIVE_METHOD(Class, classForName, "!(Ljava/lang/String;ZLjava/lang/ClassLoader;)Ljava/lang/Class;"), 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) { |