diff options
| author | 2015-03-29 22:30:55 +0000 | |
|---|---|---|
| committer | 2015-03-29 22:30:56 +0000 | |
| commit | f381645a336f7092ab6f5900c0a2cf183a9dbdf7 (patch) | |
| tree | aff5d6d53d6d2b65995aa204839f88ee66400989 /runtime/native/java_lang_Class.cc | |
| parent | 68e22f3b982ff9ccbdfb3b65b7cfc16fcae907ba (diff) | |
| parent | daaf3265806eb2eadb2e03302bd68022fab5ca28 (diff) | |
Merge "Add AccessibleObject and Field to mirror"
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) {  |