diff options
29 files changed, 796 insertions, 216 deletions
diff --git a/oatdump/oatdump.cc b/oatdump/oatdump.cc index 7bde4710a0..322d3aa8f1 100644 --- a/oatdump/oatdump.cc +++ b/oatdump/oatdump.cc @@ -1597,7 +1597,7 @@ class ImageDumper { os << StringPrintf("null %s\n", PrettyDescriptor(field->GetTypeDescriptor()).c_str()); } else { // Grab the field type without causing resolution. - mirror::Class* field_type = field->GetType(false); + mirror::Class* field_type = field->GetType<false>(); if (field_type != nullptr) { PrettyObjectValue(os, field_type, value); } else { diff --git a/runtime/Android.mk b/runtime/Android.mk index 5548d949d9..dde5407e12 100644 --- a/runtime/Android.mk +++ b/runtime/Android.mk @@ -103,6 +103,7 @@ LIBART_COMMON_SRC_FILES := \ mirror/array.cc \ mirror/class.cc \ mirror/dex_cache.cc \ + mirror/field.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 7521266605..a89196d830 100644 --- a/runtime/class_linker.cc +++ b/runtime/class_linker.cc @@ -56,6 +56,7 @@ #include "mirror/class-inl.h" #include "mirror/class_loader.h" #include "mirror/dex_cache-inl.h" +#include "mirror/field.h" #include "mirror/iftable-inl.h" #include "mirror/object-inl.h" #include "mirror/object_array-inl.h" @@ -313,7 +314,7 @@ void ClassLinker::InitWithoutImage(std::vector<std::unique_ptr<const DexFile>> b java_lang_String->SetObjectSize(mirror::String::InstanceSize()); mirror::Class::SetStatus(java_lang_String, mirror::Class::kStatusResolved, self); - // Setup Reference. + // Setup java.lang.ref.Reference. Handle<mirror::Class> java_lang_ref_Reference(hs.NewHandle( AllocClass(self, java_lang_Class.Get(), mirror::Reference::ClassSize()))); mirror::Reference::SetClass(java_lang_ref_Reference.Get()); @@ -321,7 +322,7 @@ void ClassLinker::InitWithoutImage(std::vector<std::unique_ptr<const DexFile>> b mirror::Class::SetStatus(java_lang_ref_Reference, mirror::Class::kStatusResolved, self); // Create storage for root classes, save away our work so far (requires descriptors). - class_roots_ = GcRoot<mirror::ObjectArray<mirror::Class> >( + class_roots_ = GcRoot<mirror::ObjectArray<mirror::Class>>( mirror::ObjectArray<mirror::Class>::Alloc(self, object_array_class.Get(), kClassRootsMax)); CHECK(!class_roots_.IsNull()); @@ -531,6 +532,19 @@ void ClassLinker::InitWithoutImage(std::vector<std::unique_ptr<const DexFile>> b mirror::Class* java_lang_reflect_Proxy = FindSystemClass(self, "Ljava/lang/reflect/Proxy;"); SetClassRoot(kJavaLangReflectProxy, java_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); + + // 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); + // 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); @@ -818,9 +832,10 @@ void ClassLinker::InitFromImage() { VLOG(startup) << "ClassLinker::InitFromImage entering"; CHECK(!init_done_); - Thread* self = Thread::Current(); - gc::Heap* heap = Runtime::Current()->GetHeap(); - gc::space::ImageSpace* space = heap->GetImageSpace(); + Runtime* const runtime = Runtime::Current(); + Thread* const self = Thread::Current(); + gc::Heap* const heap = runtime->GetHeap(); + gc::space::ImageSpace* const space = heap->GetImageSpace(); dex_cache_image_class_lookup_required_ = true; CHECK(space != nullptr); OatFile& oat_file = GetImageOatFile(space); @@ -875,7 +890,7 @@ void ClassLinker::InitFromImage() { // bitmap walk. mirror::ArtMethod::SetClass(GetClassRoot(kJavaLangReflectArtMethod)); size_t art_method_object_size = mirror::ArtMethod::GetJavaLangReflectArtMethod()->GetObjectSize(); - if (!Runtime::Current()->IsAotCompiler()) { + if (!runtime->IsAotCompiler()) { // Aot compiler supports having an image with a different pointer size than the runtime. This // happens on the host for compile 32 bit tests since we use a 64 bit libart compiler. We may // also use 32 bit dex2oat on a system with 64 bit apps. @@ -890,7 +905,6 @@ void ClassLinker::InitFromImage() { } // Set entry point to interpreter if in InterpretOnly mode. - Runtime* runtime = Runtime::Current(); if (!runtime->IsAotCompiler() && runtime->GetInstrumentation()->InterpretOnly()) { heap->VisitObjects(InitFromImageInterpretOnlyCallback, this); } @@ -903,6 +917,8 @@ void ClassLinker::InitFromImage() { array_iftable_ = GcRoot<mirror::IfTable>(GetClassRoot(kObjectArrayClass)->GetIfTable()); DCHECK_EQ(array_iftable_.Read(), GetClassRoot(kBooleanArrayClass)->GetIfTable()); // String class root was set above + mirror::Field::SetClass(GetClassRoot(kJavaLangReflectField)); + mirror::Field::SetArrayClass(GetClassRoot(kJavaLangReflectFieldArrayClass)); mirror::Reference::SetClass(GetClassRoot(kJavaLangRefReference)); mirror::ArtField::SetClass(GetClassRoot(kJavaLangReflectArtField)); mirror::BooleanArray::SetArrayClass(GetClassRoot(kBooleanArrayClass)); @@ -1088,6 +1104,8 @@ ClassLinker::~ClassLinker() { mirror::Reference::ResetClass(); mirror::ArtField::ResetClass(); mirror::ArtMethod::ResetClass(); + mirror::Field::ResetClass(); + mirror::Field::ResetArrayClass(); mirror::BooleanArray::ResetArrayClass(); mirror::ByteArray::ResetArrayClass(); mirror::CharArray::ResetArrayClass(); @@ -5189,10 +5207,12 @@ const char* ClassLinker::GetClassRootDescriptor(ClassRoot class_root) { "Ljava/lang/ref/Reference;", "Ljava/lang/reflect/ArtField;", "Ljava/lang/reflect/ArtMethod;", + "Ljava/lang/reflect/Field;", "Ljava/lang/reflect/Proxy;", "[Ljava/lang/String;", "[Ljava/lang/reflect/ArtField;", "[Ljava/lang/reflect/ArtMethod;", + "[Ljava/lang/reflect/Field;", "Ljava/lang/ClassLoader;", "Ljava/lang/Throwable;", "Ljava/lang/ClassNotFoundException;", @@ -5311,14 +5331,11 @@ jobject ClassLinker::CreatePathClassLoader(Thread* self, std::vector<const DexFi Handle<mirror::ArtField> h_dex_elements_field = hs.NewHandle(soa.DecodeField(WellKnownClasses::dalvik_system_DexPathList_dexElements)); - mirror::Class* dex_elements_class = h_dex_elements_field->GetType(true); + mirror::Class* dex_elements_class = h_dex_elements_field->GetType<true>(); DCHECK(dex_elements_class != nullptr); DCHECK(dex_elements_class->IsArrayClass()); - Handle<mirror::ObjectArray<mirror::Object>> h_dex_elements = - hs.NewHandle(reinterpret_cast<mirror::ObjectArray<mirror::Object>*>( - mirror::Array::Alloc<true>(self, dex_elements_class, dex_files.size(), - dex_elements_class->GetComponentSizeShift(), - Runtime::Current()->GetHeap()->GetCurrentAllocator()))); + Handle<mirror::ObjectArray<mirror::Object>> h_dex_elements(hs.NewHandle( + mirror::ObjectArray<mirror::Object>::Alloc(self, dex_elements_class, dex_files.size()))); Handle<mirror::Class> h_dex_element_class = hs.NewHandle(dex_elements_class->GetComponentType()); @@ -5329,7 +5346,7 @@ jobject ClassLinker::CreatePathClassLoader(Thread* self, std::vector<const DexFi Handle<mirror::ArtField> h_cookie_field = hs.NewHandle(soa.DecodeField(WellKnownClasses::dalvik_system_DexFile_cookie)); - DCHECK_EQ(h_cookie_field->GetDeclaringClass(), h_element_file_field->GetType(false)); + DCHECK_EQ(h_cookie_field->GetDeclaringClass(), h_element_file_field->GetType<false>()); // Fill the elements array. int32_t index = 0; diff --git a/runtime/class_linker.h b/runtime/class_linker.h index 88a250140a..ec984cb703 100644 --- a/runtime/class_linker.h +++ b/runtime/class_linker.h @@ -72,10 +72,12 @@ class ClassLinker { kJavaLangRefReference, kJavaLangReflectArtField, kJavaLangReflectArtMethod, + kJavaLangReflectField, kJavaLangReflectProxy, kJavaLangStringArrayClass, kJavaLangReflectArtFieldArrayClass, kJavaLangReflectArtMethodArrayClass, + kJavaLangReflectFieldArrayClass, kJavaLangClassLoader, kJavaLangThrowable, kJavaLangClassNotFoundException, diff --git a/runtime/class_linker_test.cc b/runtime/class_linker_test.cc index a895a494a1..3e727e7408 100644 --- a/runtime/class_linker_test.cc +++ b/runtime/class_linker_test.cc @@ -24,11 +24,13 @@ #include "dex_file.h" #include "entrypoints/entrypoint_utils-inl.h" #include "gc/heap.h" +#include "mirror/accessible_object.h" #include "mirror/art_field-inl.h" #include "mirror/art_method.h" #include "mirror/art_method-inl.h" #include "mirror/class-inl.h" #include "mirror/dex_cache.h" +#include "mirror/field.h" #include "mirror/object-inl.h" #include "mirror/object_array-inl.h" #include "mirror/proxy.h" @@ -177,7 +179,7 @@ class ClassLinkerTest : public CommonRuntimeTest { EXPECT_TRUE(field->GetClass() != nullptr); EXPECT_EQ(klass, field->GetDeclaringClass()); EXPECT_TRUE(field->GetName() != nullptr); - EXPECT_TRUE(field->GetType(true) != nullptr); + EXPECT_TRUE(field->GetType<true>() != nullptr); } void AssertClass(const std::string& descriptor, Handle<mirror::Class> klass) @@ -283,7 +285,7 @@ class ClassLinkerTest : public CommonRuntimeTest { for (size_t i = 0; i < klass->NumInstanceFields(); i++) { mirror::ArtField* field = klass->GetInstanceField(i); fhandle.Assign(field); - mirror::Class* field_type = fhandle->GetType(true); + mirror::Class* field_type = fhandle->GetType<true>(); ASSERT_TRUE(field_type != nullptr); if (!field->IsPrimitiveType()) { ASSERT_TRUE(!field_type->IsPrimitive()); @@ -394,7 +396,12 @@ struct CheckOffsets { // Art method have a different size due to the padding field. if (!klass->IsArtMethodClass() && !klass->IsClassClass() && !is_static) { - size_t expected_size = is_static ? klass->GetClassSize(): klass->GetObjectSize(); + // Currently only required for AccessibleObject since of the padding fields. The class linker + // says AccessibleObject is 9 bytes but sizeof(AccessibleObject) is 12 bytes due to padding. + // The RoundUp is to get around this case. + static constexpr size_t kPackAlignment = 4; + size_t expected_size = RoundUp(is_static ? klass->GetClassSize(): klass->GetObjectSize(), + kPackAlignment); if (sizeof(T) != expected_size) { LOG(ERROR) << "Class size mismatch:" << " class=" << class_descriptor @@ -596,6 +603,22 @@ struct FinalizerReferenceOffsets : public CheckOffsets<mirror::FinalizerReferenc }; }; +struct AccessibleObjectOffsets : public CheckOffsets<mirror::AccessibleObject> { + AccessibleObjectOffsets() : CheckOffsets<mirror::AccessibleObject>(false, "Ljava/lang/reflect/AccessibleObject;") { + offsets.push_back(CheckOffset(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")); + }; +}; + // C++ fields must exactly match the fields in the Java classes. If this fails, // reorder the fields in the C++ class. Managed class fields are ordered by // ClassLinker::LinkFields. @@ -613,6 +636,8 @@ TEST_F(ClassLinkerTest, ValidateFieldOrderOfJavaCppUnionClasses) { EXPECT_TRUE(DexCacheOffsets().Check()); EXPECT_TRUE(ReferenceOffsets().Check()); EXPECT_TRUE(FinalizerReferenceOffsets().Check()); + EXPECT_TRUE(AccessibleObjectOffsets().Check()); + EXPECT_TRUE(FieldOffsets().Check()); } TEST_F(ClassLinkerTest, FindClassNonexistent) { diff --git a/runtime/debugger.cc b/runtime/debugger.cc index a1ae236397..5ea018737a 100644 --- a/runtime/debugger.cc +++ b/runtime/debugger.cc @@ -1798,7 +1798,7 @@ static JDWP::JdwpError SetFieldValueImpl(JDWP::ObjectId object_id, JDWP::FieldId HandleWrapper<mirror::Object> h_v(hs.NewHandleWrapper(&v)); HandleWrapper<mirror::ArtField> h_f(hs.NewHandleWrapper(&f)); HandleWrapper<mirror::Object> h_o(hs.NewHandleWrapper(&o)); - field_type = h_f->GetType(true); + field_type = h_f->GetType<true>(); } if (!field_type->IsAssignableFrom(v->GetClass())) { return JDWP::ERR_INVALID_OBJECT; diff --git a/runtime/interpreter/interpreter_common.cc b/runtime/interpreter/interpreter_common.cc index a3ab026ba8..a3104525b6 100644 --- a/runtime/interpreter/interpreter_common.cc +++ b/runtime/interpreter/interpreter_common.cc @@ -285,7 +285,7 @@ bool DoFieldPut(Thread* self, const ShadowFrame& shadow_frame, const Instruction HandleWrapper<mirror::ArtField> h_f(hs.NewHandleWrapper(&f)); HandleWrapper<mirror::Object> h_reg(hs.NewHandleWrapper(®)); HandleWrapper<mirror::Object> h_obj(hs.NewHandleWrapper(&obj)); - field_class = h_f->GetType(true); + field_class = h_f->GetType<true>(); } if (!reg->VerifierInstanceOf(field_class)) { // This should never happen. diff --git a/runtime/interpreter/unstarted_runtime.cc b/runtime/interpreter/unstarted_runtime.cc index 98dfdbd2ea..1b08e80495 100644 --- a/runtime/interpreter/unstarted_runtime.cc +++ b/runtime/interpreter/unstarted_runtime.cc @@ -29,6 +29,7 @@ #include "mirror/array-inl.h" #include "mirror/art_method-inl.h" #include "mirror/class.h" +#include "mirror/field-inl.h" #include "mirror/object-inl.h" #include "mirror/object_array-inl.h" #include "mirror/string-inl.h" @@ -219,19 +220,11 @@ static void UnstartedClassGetDeclaredField( PrettyDescriptor(klass).c_str()); return; } - // TODO: getDeclaredField calls GetType once the field is found to ensure a - // NoClassDefFoundError is thrown if the field's type cannot be resolved. - mirror::Class* jlr_Field = self->DecodeJObject( - WellKnownClasses::java_lang_reflect_Field)->AsClass(); - StackHandleScope<1> hs(self); - Handle<mirror::Object> field(hs.NewHandle(jlr_Field->AllocNonMovableObject(self))); - CHECK(field.Get() != nullptr); - mirror::ArtMethod* c = jlr_Field->FindDeclaredDirectMethod("<init>", - "(Ljava/lang/reflect/ArtField;)V"); - uint32_t args[1]; - args[0] = StackReference<mirror::Object>::FromMirrorPtr(found).AsVRegValue(); - EnterInterpreterFromInvoke(self, c, field.Get(), args, nullptr); - result->SetL(field.Get()); + if (Runtime::Current()->IsActiveTransaction()) { + result->SetL(mirror::Field::CreateFromArtField<true>(self, found, true)); + } else { + result->SetL(mirror::Field::CreateFromArtField<false>(self, found, true)); + } } static void UnstartedVmClassLoaderFindLoadedClass( diff --git a/runtime/jni_internal.cc b/runtime/jni_internal.cc index 9a71ba4ca7..5e38470584 100644 --- a/runtime/jni_internal.cc +++ b/runtime/jni_internal.cc @@ -41,6 +41,7 @@ #include "mirror/art_method-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" @@ -346,7 +347,13 @@ class JNI { static jfieldID FromReflectedField(JNIEnv* env, jobject jlr_field) { CHECK_NON_NULL_ARGUMENT(jlr_field); ScopedObjectAccess soa(env); - return soa.EncodeField(mirror::ArtField::FromReflectedField(soa, jlr_field)); + mirror::Object* obj_field = soa.Decode<mirror::Object*>(jlr_field); + if (obj_field->GetClass() != mirror::Field::StaticClass()) { + // Not even a java.lang.reflect.Field, return nullptr. + return nullptr; + } + auto* field = static_cast<mirror::Field*>(obj_field); + return soa.EncodeField(field->GetArtField()); } static jobject ToReflectedMethod(JNIEnv* env, jclass, jmethodID mid, jboolean) { @@ -373,14 +380,7 @@ class JNI { CHECK_NON_NULL_ARGUMENT(fid); ScopedObjectAccess soa(env); mirror::ArtField* f = soa.DecodeField(fid); - ScopedLocalRef<jobject> art_field(env, soa.AddLocalReference<jobject>(f)); - jobject reflect_field = env->AllocObject(WellKnownClasses::java_lang_reflect_Field); - if (env->ExceptionCheck()) { - return nullptr; - } - SetObjectField(env, reflect_field, - WellKnownClasses::java_lang_reflect_Field_artField, art_field.get()); - return reflect_field; + return soa.AddLocalReference<jobject>(mirror::Field::CreateFromArtField(soa.Self(), f, true)); } static jclass GetObjectClass(JNIEnv* env, jobject java_object) { diff --git a/runtime/mirror/accessible_object.h b/runtime/mirror/accessible_object.h new file mode 100644 index 0000000000..6d4c0f6fb3 --- /dev/null +++ b/runtime/mirror/accessible_object.h @@ -0,0 +1,60 @@ +/* + * 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_ACCESSIBLE_OBJECT_H_ +#define ART_RUNTIME_MIRROR_ACCESSIBLE_OBJECT_H_ + +#include "class.h" +#include "gc_root.h" +#include "object.h" +#include "object_callbacks.h" +#include "read_barrier_option.h" +#include "thread.h" + +namespace art { + +namespace mirror { + +// C++ mirror of java.lang.reflect.AccessibleObject +class MANAGED AccessibleObject : public Object { + public: + static MemberOffset FlagOffset() { + return OFFSET_OF_OBJECT_MEMBER(AccessibleObject, flag_); + } + + template<bool kTransactionActive> + void SetAccessible(bool value) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) { + UNUSED(padding_); + return SetFieldBoolean<kTransactionActive>(FlagOffset(), value ? 1u : 0u); + } + + bool IsAccessible() SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) { + return GetFieldBoolean(FlagOffset()); + } + + private: + uint8_t flag_; + // Padding required for now since "packed" will cause reflect.Field fields to not be aligned + // otherwise. + uint8_t padding_[3]; + + DISALLOW_IMPLICIT_CONSTRUCTORS(AccessibleObject); +}; + +} // namespace mirror +} // namespace art + +#endif // ART_RUNTIME_MIRROR_ACCESSIBLE_OBJECT_H_ diff --git a/runtime/mirror/art_field-inl.h b/runtime/mirror/art_field-inl.h index 2b406bdd91..986852f200 100644 --- a/runtime/mirror/art_field-inl.h +++ b/runtime/mirror/art_field-inl.h @@ -34,7 +34,7 @@ namespace art { namespace mirror { inline uint32_t ArtField::ClassSize() { - uint32_t vtable_entries = Object::kVTableLength + 6; + uint32_t vtable_entries = Object::kVTableLength; return Class::ComputeClassSize(true, vtable_entries, 0, 0, 0, 0, 0); } @@ -290,16 +290,19 @@ inline bool ArtField::IsPrimitiveType() SHARED_LOCKS_REQUIRED(Locks::mutator_loc return GetTypeAsPrimitiveType() != Primitive::kPrimNot; } -inline Class* ArtField::GetType(bool resolve) { - uint32_t field_index = GetDexFieldIndex(); - if (UNLIKELY(GetDeclaringClass()->IsProxyClass())) { +template <bool kResolve> +inline Class* ArtField::GetType() { + const uint32_t field_index = GetDexFieldIndex(); + auto* declaring_class = GetDeclaringClass(); + if (UNLIKELY(declaring_class->IsProxyClass())) { return Runtime::Current()->GetClassLinker()->FindSystemClass(Thread::Current(), GetTypeDescriptor()); } - const DexFile* dex_file = GetDexFile(); + auto* dex_cache = declaring_class->GetDexCache(); + const DexFile* const dex_file = dex_cache->GetDexFile(); const DexFile::FieldId& field_id = dex_file->GetFieldId(field_index); - mirror::Class* type = GetDexCache()->GetResolvedType(field_id.type_idx_); - if (resolve && (type == nullptr)) { + mirror::Class* type = dex_cache->GetResolvedType(field_id.type_idx_); + if (kResolve && UNLIKELY(type == nullptr)) { type = Runtime::Current()->GetClassLinker()->ResolveType(field_id.type_idx_, this); CHECK(type != nullptr || Thread::Current()->IsExceptionPending()); } @@ -318,12 +321,19 @@ inline const DexFile* ArtField::GetDexFile() SHARED_LOCKS_REQUIRED(Locks::mutato return GetDexCache()->GetDexFile(); } -inline ArtField* ArtField::FromReflectedField(const ScopedObjectAccessAlreadyRunnable& soa, - jobject jlr_field) { - mirror::ArtField* f = soa.DecodeField(WellKnownClasses::java_lang_reflect_Field_artField); - mirror::ArtField* field = f->GetObject(soa.Decode<mirror::Object*>(jlr_field))->AsArtField(); - DCHECK(field != nullptr); - return field; +inline String* ArtField::GetStringName(Thread* self, bool resolve) { + auto dex_field_index = GetDexFieldIndex(); + CHECK_NE(dex_field_index, DexFile::kDexNoIndex); + auto* dex_cache = GetDexCache(); + const auto* dex_file = dex_cache->GetDexFile(); + const auto& field_id = dex_file->GetFieldId(dex_field_index); + auto* name = dex_cache->GetResolvedString(field_id.name_idx_); + if (resolve && name == nullptr) { + StackHandleScope<1> hs(self); + name = Runtime::Current()->GetClassLinker()->ResolveString( + *dex_file, field_id.name_idx_, hs.NewHandle(dex_cache)); + } + return name; } } // namespace mirror diff --git a/runtime/mirror/art_field.h b/runtime/mirror/art_field.h index a1d8844664..d640165aef 100644 --- a/runtime/mirror/art_field.h +++ b/runtime/mirror/art_field.h @@ -47,10 +47,6 @@ class MANAGED ArtField FINAL : public Object { return sizeof(ArtField); } - ALWAYS_INLINE static ArtField* FromReflectedField(const ScopedObjectAccessAlreadyRunnable& soa, - jobject jlr_field) - SHARED_LOCKS_REQUIRED(Locks::mutator_lock_); - Class* GetDeclaringClass() SHARED_LOCKS_REQUIRED(Locks::mutator_lock_); void SetDeclaringClass(Class *new_declaring_class) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_); @@ -155,13 +151,17 @@ class MANAGED ArtField FINAL : public Object { const char* GetName() SHARED_LOCKS_REQUIRED(Locks::mutator_lock_); + // Resolves / returns the name from the dex cache. + String* GetStringName(Thread* self, bool resolve) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_); + const char* GetTypeDescriptor() SHARED_LOCKS_REQUIRED(Locks::mutator_lock_); Primitive::Type GetTypeAsPrimitiveType() SHARED_LOCKS_REQUIRED(Locks::mutator_lock_); bool IsPrimitiveType() SHARED_LOCKS_REQUIRED(Locks::mutator_lock_); - Class* GetType(bool resolve) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_); + template <bool kResolve> + Class* GetType() SHARED_LOCKS_REQUIRED(Locks::mutator_lock_); size_t FieldSize() SHARED_LOCKS_REQUIRED(Locks::mutator_lock_); diff --git a/runtime/mirror/field-inl.h b/runtime/mirror/field-inl.h new file mode 100644 index 0000000000..24ebc481a7 --- /dev/null +++ b/runtime/mirror/field-inl.h @@ -0,0 +1,79 @@ +/* + * 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_FIELD_INL_H_ +#define ART_RUNTIME_MIRROR_FIELD_INL_H_ + +#include "field.h" + +#include "art_field-inl.h" +#include "runtime-inl.h" + +namespace art { + +namespace mirror { + +template <bool kTransactionActive> +inline mirror::Field* Field::CreateFromArtField(Thread* self, mirror::ArtField* field, + bool force_resolve) { + CHECK(!kMovingFields); + // Try to resolve type before allocating since this is a thread suspension point. + mirror::Class* type = field->GetType<true>(); + + if (type == nullptr) { + if (force_resolve) { + if (kIsDebugBuild) { + self->AssertPendingException(); + } + return nullptr; + } else { + // Can't resolve, clear the exception if it isn't OOME and continue with a null type. + mirror::Throwable* exception = self->GetException(); + if (exception->GetClass()->DescriptorEquals("Ljava/lang/OutOfMemoryError;")) { + return nullptr; + } + self->ClearException(); + } + } + StackHandleScope<1> hs(self); + auto ret = hs.NewHandle(static_cast<Field*>(StaticClass()->AllocObject(self))); + if (ret.Get() == nullptr) { + if (kIsDebugBuild) { + self->AssertPendingException(); + } + return nullptr; + } + auto dex_field_index = field->GetDexFieldIndex(); + auto* resolved_field = field->GetDexCache()->GetResolvedField(dex_field_index); + if (resolved_field != nullptr) { + DCHECK_EQ(resolved_field, field); + } else { + // We rely on the field being resolved so that we can back to the ArtField + // (i.e. FromReflectedMethod). + field->GetDexCache()->SetResolvedField(dex_field_index, field); + } + ret->SetType<kTransactionActive>(type); + ret->SetDeclaringClass<kTransactionActive>(field->GetDeclaringClass()); + ret->SetAccessFlags<kTransactionActive>(field->GetAccessFlags()); + ret->SetDexFieldIndex<kTransactionActive>(dex_field_index); + ret->SetOffset<kTransactionActive>(field->GetOffset().Int32Value()); + return ret.Get(); +} + +} // namespace mirror +} // namespace art + +#endif // ART_RUNTIME_MIRROR_FIELD_INL_H_ diff --git a/runtime/mirror/field.cc b/runtime/mirror/field.cc new file mode 100644 index 0000000000..1724682f79 --- /dev/null +++ b/runtime/mirror/field.cc @@ -0,0 +1,64 @@ +/* + * 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 "field-inl.h" + +#include "dex_cache-inl.h" +#include "object_array-inl.h" +#include "object-inl.h" + +namespace art { +namespace mirror { + +GcRoot<Class> Field::static_class_; +GcRoot<Class> Field::array_class_; + +void Field::SetClass(Class* klass) { + CHECK(static_class_.IsNull()) << static_class_.Read() << " " << klass; + CHECK(klass != nullptr); + static_class_ = GcRoot<Class>(klass); +} + +void Field::ResetClass() { + CHECK(!static_class_.IsNull()); + static_class_ = GcRoot<Class>(nullptr); +} + +void Field::SetArrayClass(Class* klass) { + CHECK(array_class_.IsNull()) << array_class_.Read() << " " << klass; + CHECK(klass != nullptr); + array_class_ = GcRoot<Class>(klass); +} + +void Field::ResetArrayClass() { + CHECK(!array_class_.IsNull()); + array_class_ = GcRoot<Class>(nullptr); +} + +void Field::VisitRoots(RootCallback* callback, void* arg) { + static_class_.VisitRootIfNonNull(callback, arg, RootInfo(kRootStickyClass)); + array_class_.VisitRootIfNonNull(callback, arg, RootInfo(kRootStickyClass)); +} + +ArtField* Field::GetArtField() { + mirror::DexCache* const dex_cache = GetDeclaringClass()->GetDexCache(); + mirror::ArtField* const art_field = dex_cache->GetResolvedField(GetDexFieldIndex()); + CHECK(art_field != nullptr); + return art_field; +} + +} // namespace mirror +} // namespace art diff --git a/runtime/mirror/field.h b/runtime/mirror/field.h new file mode 100644 index 0000000000..f54340a6a4 --- /dev/null +++ b/runtime/mirror/field.h @@ -0,0 +1,145 @@ +/* + * 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_FIELD_H_ +#define ART_RUNTIME_MIRROR_FIELD_H_ + +#include "accessible_object.h" +#include "gc_root.h" +#include "object.h" +#include "object_callbacks.h" +#include "read_barrier_option.h" + +namespace art { + +struct FieldOffsets; + +namespace mirror { + +class ArtField; +class Class; +class String; + +// C++ mirror of java.lang.reflect.Field. +class MANAGED Field : public AccessibleObject { + public: + static mirror::Class* StaticClass() SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) { + return static_class_.Read(); + } + + static mirror::Class* ArrayClass() SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) { + return array_class_.Read(); + } + + ALWAYS_INLINE uint32_t GetDexFieldIndex() SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) { + return GetField32(OFFSET_OF_OBJECT_MEMBER(Field, dex_field_index_)); + } + + mirror::Class* GetDeclaringClass() SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) { + return GetFieldObject<Class>(OFFSET_OF_OBJECT_MEMBER(Field, declaring_class_)); + } + + uint32_t GetAccessFlags() SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) { + return GetField32(OFFSET_OF_OBJECT_MEMBER(Field, access_flags_)); + } + + bool IsStatic() SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) { + return (GetAccessFlags() & kAccStatic) != 0; + } + + bool IsFinal() SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) { + return (GetAccessFlags() & kAccFinal) != 0; + } + + bool IsVolatile() SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) { + return (GetAccessFlags() & kAccVolatile) != 0; + } + + ALWAYS_INLINE Primitive::Type GetTypeAsPrimitiveType() + SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) { + return GetType()->GetPrimitiveType(); + } + + mirror::Class* GetType() SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) { + return GetFieldObject<mirror::Class>(OFFSET_OF_OBJECT_MEMBER(Field, type_)); + } + + int32_t GetOffset() SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) { + return GetField32(OFFSET_OF_OBJECT_MEMBER(Field, offset_)); + } + + 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 ResetArrayClass() SHARED_LOCKS_REQUIRED(Locks::mutator_lock_); + + static void VisitRoots(RootCallback* callback, void* arg) + SHARED_LOCKS_REQUIRED(Locks::mutator_lock_); + + // Slow, try to use only for PrettyField and such. + mirror::ArtField* GetArtField() SHARED_LOCKS_REQUIRED(Locks::mutator_lock_); + + template <bool kTransactionActive = false> + static mirror::Field* CreateFromArtField(Thread* self, mirror::ArtField* field, + bool force_resolve) + SHARED_LOCKS_REQUIRED(Locks::mutator_lock_); + + private: + HeapReference<mirror::Class> declaring_class_; + HeapReference<mirror::Class> type_; + int32_t access_flags_; + int32_t dex_field_index_; + int32_t offset_; + + template<bool kTransactionActive> + void SetDeclaringClass(mirror::Class* c) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) { + SetFieldObject<kTransactionActive>(OFFSET_OF_OBJECT_MEMBER(Field, declaring_class_), c); + } + + template<bool kTransactionActive> + void SetType(mirror::Class* type) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) { + SetFieldObject<kTransactionActive>(OFFSET_OF_OBJECT_MEMBER(Field, type_), type); + } + + template<bool kTransactionActive> + void SetAccessFlags(uint32_t flags) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) { + SetField32<kTransactionActive>(OFFSET_OF_OBJECT_MEMBER(Field, access_flags_), flags); + } + + template<bool kTransactionActive> + void SetDexFieldIndex(uint32_t idx) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) { + SetField32<kTransactionActive>(OFFSET_OF_OBJECT_MEMBER(Field, dex_field_index_), idx); + } + + template<bool kTransactionActive> + void SetOffset(uint32_t offset) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) { + SetField32<kTransactionActive>(OFFSET_OF_OBJECT_MEMBER(Field, offset_), offset); + } + + static GcRoot<Class> static_class_; // java.lang.reflect.Field.class. + static GcRoot<Class> array_class_; // array of java.lang.reflect.Field. + + friend struct art::FieldOffsets; // for verifying offset information + DISALLOW_IMPLICIT_CONSTRUCTORS(Field); +}; + +} // namespace mirror +} // namespace art + +#endif // ART_RUNTIME_MIRROR_FIELD_H_ diff --git a/runtime/mirror/object.cc b/runtime/mirror/object.cc index bbbdf98be8..57ac46fec6 100644 --- a/runtime/mirror/object.cc +++ b/runtime/mirror/object.cc @@ -214,7 +214,7 @@ void Object::CheckFieldAssignmentImpl(MemberOffset field_offset, Object* new_val if (field->GetOffset().Int32Value() == field_offset.Int32Value()) { CHECK_NE(field->GetTypeAsPrimitiveType(), Primitive::kPrimNot); // TODO: resolve the field type for moving GC. - mirror::Class* field_type = field->GetType(!kMovingCollector); + mirror::Class* field_type = field->GetType<!kMovingCollector>(); if (field_type != nullptr) { CHECK(field_type->IsAssignableFrom(new_value->GetClass())); } @@ -236,7 +236,7 @@ void Object::CheckFieldAssignmentImpl(MemberOffset field_offset, Object* new_val if (field->GetOffset().Int32Value() == field_offset.Int32Value()) { CHECK_NE(field->GetTypeAsPrimitiveType(), Primitive::kPrimNot); // TODO: resolve the field type for moving GC. - mirror::Class* field_type = field->GetType(!kMovingCollector); + mirror::Class* field_type = field->GetType<!kMovingCollector>(); if (field_type != nullptr) { CHECK(field_type->IsAssignableFrom(new_value->GetClass())); } diff --git a/runtime/mirror/object.h b/runtime/mirror/object.h index 780c5aef42..b730670796 100644 --- a/runtime/mirror/object.h +++ b/runtime/mirror/object.h @@ -100,7 +100,7 @@ class MANAGED LOCKABLE Object { template<VerifyObjectFlags kVerifyFlags = kDefaultVerifyFlags> bool VerifierInstanceOf(Class* klass) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_); template<VerifyObjectFlags kVerifyFlags = kDefaultVerifyFlags> - bool InstanceOf(Class* klass) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_); + ALWAYS_INLINE bool InstanceOf(Class* klass) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_); template<VerifyObjectFlags kVerifyFlags = kDefaultVerifyFlags, ReadBarrierOption kReadBarrierOption = kWithReadBarrier> diff --git a/runtime/mirror/reference.h b/runtime/mirror/reference.h index 7345448ed7..69ef69c662 100644 --- a/runtime/mirror/reference.h +++ b/runtime/mirror/reference.h @@ -99,7 +99,7 @@ class MANAGED Reference : public Object { return java_lang_ref_Reference_.Read<kReadBarrierOption>(); } static void SetClass(Class* klass); - static void ResetClass(void); + static void ResetClass(); static void VisitRoots(RootCallback* callback, void* arg); private: 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) { diff --git a/runtime/native/java_lang_reflect_Field.cc b/runtime/native/java_lang_reflect_Field.cc index 9c5bde9c1e..0fe78b3281 100644 --- a/runtime/native/java_lang_reflect_Field.cc +++ b/runtime/native/java_lang_reflect_Field.cc @@ -21,23 +21,23 @@ #include "common_throws.h" #include "dex_file-inl.h" #include "jni_internal.h" -#include "mirror/art_field-inl.h" #include "mirror/art_method-inl.h" #include "mirror/class-inl.h" +#include "mirror/field.h" #include "reflection-inl.h" #include "scoped_fast_native_object_access.h" namespace art { template<bool kIsSet> -ALWAYS_INLINE inline static bool VerifyFieldAccess(Thread* self, mirror::ArtField* field, +ALWAYS_INLINE inline static bool VerifyFieldAccess(Thread* self, mirror::Field* field, mirror::Object* obj) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) { if (kIsSet && field->IsFinal()) { ThrowIllegalAccessException( StringPrintf("Cannot set %s field %s of class %s", PrettyJavaAccessFlags(field->GetAccessFlags()).c_str(), - PrettyField(field).c_str(), + PrettyField(field->GetArtField()).c_str(), field->GetDeclaringClass() == nullptr ? "null" : PrettyClass(field->GetDeclaringClass()).c_str()).c_str()); return false; @@ -49,7 +49,7 @@ ALWAYS_INLINE inline static bool VerifyFieldAccess(Thread* self, mirror::ArtFiel StringPrintf("Class %s cannot access %s field %s of class %s", calling_class == nullptr ? "null" : PrettyClass(calling_class).c_str(), PrettyJavaAccessFlags(field->GetAccessFlags()).c_str(), - PrettyField(field).c_str(), + PrettyField(field->GetArtField()).c_str(), field->GetDeclaringClass() == nullptr ? "null" : PrettyClass(field->GetDeclaringClass()).c_str()).c_str()); return false; @@ -58,38 +58,37 @@ ALWAYS_INLINE inline static bool VerifyFieldAccess(Thread* self, mirror::ArtFiel } template<bool kAllowReferences> -ALWAYS_INLINE inline static bool GetFieldValue(mirror::Object* o, mirror::ArtField* f, +ALWAYS_INLINE inline static bool GetFieldValue(mirror::Object* o, mirror::Field* f, Primitive::Type field_type, JValue* value) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) { DCHECK_EQ(value->GetJ(), INT64_C(0)); + MemberOffset offset(f->GetOffset()); + const bool is_volatile = f->IsVolatile(); switch (field_type) { case Primitive::kPrimBoolean: - value->SetZ(f->GetBoolean(o)); + value->SetZ(is_volatile ? o->GetFieldBooleanVolatile(offset) : o->GetFieldBoolean(offset)); return true; case Primitive::kPrimByte: - value->SetB(f->GetByte(o)); + value->SetB(is_volatile ? o->GetFieldByteVolatile(offset) : o->GetFieldByte(offset)); return true; case Primitive::kPrimChar: - value->SetC(f->GetChar(o)); - return true; - case Primitive::kPrimDouble: - value->SetD(f->GetDouble(o)); - return true; - case Primitive::kPrimFloat: - value->SetF(f->GetFloat(o)); + value->SetC(is_volatile ? o->GetFieldCharVolatile(offset) : o->GetFieldChar(offset)); return true; case Primitive::kPrimInt: - value->SetI(f->GetInt(o)); + case Primitive::kPrimFloat: + value->SetI(is_volatile ? o->GetField32Volatile(offset) : o->GetField32(offset)); return true; case Primitive::kPrimLong: - value->SetJ(f->GetLong(o)); + case Primitive::kPrimDouble: + value->SetJ(is_volatile ? o->GetField64Volatile(offset) : o->GetField64(offset)); return true; case Primitive::kPrimShort: - value->SetS(f->GetShort(o)); + value->SetS(is_volatile ? o->GetFieldShortVolatile(offset) : o->GetFieldShort(offset)); return true; case Primitive::kPrimNot: if (kAllowReferences) { - value->SetL(f->GetObject(o)); + value->SetL(is_volatile ? o->GetFieldObjectVolatile<mirror::Object>(offset) : + o->GetFieldObject<mirror::Object>(offset)); return true; } // Else break to report an error. @@ -98,23 +97,23 @@ ALWAYS_INLINE inline static bool GetFieldValue(mirror::Object* o, mirror::ArtFie // Never okay. break; } - ThrowIllegalArgumentException(StringPrintf("Not a primitive field: %s", - PrettyField(f).c_str()).c_str()); + ThrowIllegalArgumentException( + StringPrintf("Not a primitive field: %s", PrettyField(f->GetArtField()).c_str()).c_str()); return false; } ALWAYS_INLINE inline static bool CheckReceiver(const ScopedFastNativeObjectAccess& soa, - jobject j_rcvr, mirror::ArtField** f, + jobject j_rcvr, mirror::Field** f, mirror::Object** class_or_rcvr) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) { soa.Self()->AssertThreadSuspensionIsAllowable(); mirror::Class* declaringClass = (*f)->GetDeclaringClass(); if ((*f)->IsStatic()) { if (UNLIKELY(!declaringClass->IsInitialized())) { - ClassLinker* class_linker = Runtime::Current()->GetClassLinker(); StackHandleScope<2> hs(soa.Self()); - HandleWrapper<mirror::ArtField> h_f(hs.NewHandleWrapper(f)); + HandleWrapper<mirror::Field> h_f(hs.NewHandleWrapper(f)); HandleWrapper<mirror::Class> h_klass(hs.NewHandleWrapper(&declaringClass)); + ClassLinker* const class_linker = Runtime::Current()->GetClassLinker(); if (UNLIKELY(!class_linker->EnsureInitialized(soa.Self(), h_klass, true, true))) { DCHECK(soa.Self()->IsExceptionPending()); return false; @@ -131,16 +130,16 @@ ALWAYS_INLINE inline static bool CheckReceiver(const ScopedFastNativeObjectAcces return true; } -static jobject Field_get(JNIEnv* env, jobject javaField, jobject javaObj, jboolean accessible) { +static jobject Field_get(JNIEnv* env, jobject javaField, jobject javaObj) { ScopedFastNativeObjectAccess soa(env); - mirror::ArtField* f = mirror::ArtField::FromReflectedField(soa, javaField); + mirror::Field* f = soa.Decode<mirror::Field*>(javaField); mirror::Object* o = nullptr; if (!CheckReceiver(soa, javaObj, &f, &o)) { DCHECK(soa.Self()->IsExceptionPending()); return nullptr; } // If field is not set to be accessible, verify it can be accessed by the caller. - if ((accessible == JNI_FALSE) && !VerifyFieldAccess<false>(soa.Self(), f, o)) { + if (!f->IsAccessible() && !VerifyFieldAccess<false>(soa.Self(), f, o)) { DCHECK(soa.Self()->IsExceptionPending()); return nullptr; } @@ -157,9 +156,9 @@ static jobject Field_get(JNIEnv* env, jobject javaField, jobject javaObj, jboole template<Primitive::Type kPrimitiveType> ALWAYS_INLINE inline static JValue GetPrimitiveField(JNIEnv* env, jobject javaField, - jobject javaObj, jboolean accessible) { + jobject javaObj) { ScopedFastNativeObjectAccess soa(env); - mirror::ArtField* f = mirror::ArtField::FromReflectedField(soa, javaField); + mirror::Field* f = soa.Decode<mirror::Field*>(javaField); mirror::Object* o = nullptr; if (!CheckReceiver(soa, javaObj, &f, &o)) { DCHECK(soa.Self()->IsExceptionPending()); @@ -167,7 +166,7 @@ ALWAYS_INLINE inline static JValue GetPrimitiveField(JNIEnv* env, jobject javaFi } // If field is not set to be accessible, verify it can be accessed by the caller. - if (accessible == JNI_FALSE && !VerifyFieldAccess<false>(soa.Self(), f, o)) { + if (!f->IsAccessible() && !VerifyFieldAccess<false>(soa.Self(), f, o)) { DCHECK(soa.Self()->IsExceptionPending()); return JValue(); } @@ -198,72 +197,97 @@ ALWAYS_INLINE inline static JValue GetPrimitiveField(JNIEnv* env, jobject javaFi return wide_value; } -static jboolean Field_getBoolean(JNIEnv* env, jobject javaField, jobject javaObj, - jboolean accessible) { - return GetPrimitiveField<Primitive::kPrimBoolean>(env, javaField, javaObj, accessible).GetZ(); +static jboolean Field_getBoolean(JNIEnv* env, jobject javaField, jobject javaObj) { + return GetPrimitiveField<Primitive::kPrimBoolean>(env, javaField, javaObj).GetZ(); } -static jbyte Field_getByte(JNIEnv* env, jobject javaField, jobject javaObj, jboolean accessible) { - return GetPrimitiveField<Primitive::kPrimByte>(env, javaField, javaObj, accessible).GetB(); +static jbyte Field_getByte(JNIEnv* env, jobject javaField, jobject javaObj) { + return GetPrimitiveField<Primitive::kPrimByte>(env, javaField, javaObj).GetB(); } -static jchar Field_getChar(JNIEnv* env, jobject javaField, jobject javaObj, jboolean accessible) { - return GetPrimitiveField<Primitive::kPrimChar>(env, javaField, javaObj, accessible).GetC(); +static jchar Field_getChar(JNIEnv* env, jobject javaField, jobject javaObj) { + return GetPrimitiveField<Primitive::kPrimChar>(env, javaField, javaObj).GetC(); } -static jdouble Field_getDouble(JNIEnv* env, jobject javaField, jobject javaObj, - jboolean accessible) { - return GetPrimitiveField<Primitive::kPrimDouble>(env, javaField, javaObj, accessible).GetD(); +static jdouble Field_getDouble(JNIEnv* env, jobject javaField, jobject javaObj) { + return GetPrimitiveField<Primitive::kPrimDouble>(env, javaField, javaObj).GetD(); } -static jfloat Field_getFloat(JNIEnv* env, jobject javaField, jobject javaObj, jboolean accessible) { - return GetPrimitiveField<Primitive::kPrimFloat>(env, javaField, javaObj, accessible).GetF(); +static jfloat Field_getFloat(JNIEnv* env, jobject javaField, jobject javaObj) { + return GetPrimitiveField<Primitive::kPrimFloat>(env, javaField, javaObj).GetF(); } -static jint Field_getInt(JNIEnv* env, jobject javaField, jobject javaObj, jboolean accessible) { - return GetPrimitiveField<Primitive::kPrimInt>(env, javaField, javaObj, accessible).GetI(); +static jint Field_getInt(JNIEnv* env, jobject javaField, jobject javaObj) { + return GetPrimitiveField<Primitive::kPrimInt>(env, javaField, javaObj).GetI(); } -static jlong Field_getLong(JNIEnv* env, jobject javaField, jobject javaObj, jboolean accessible) { - return GetPrimitiveField<Primitive::kPrimLong>(env, javaField, javaObj, accessible).GetJ(); +static jlong Field_getLong(JNIEnv* env, jobject javaField, jobject javaObj) { + return GetPrimitiveField<Primitive::kPrimLong>(env, javaField, javaObj).GetJ(); } -static jshort Field_getShort(JNIEnv* env, jobject javaField, jobject javaObj, jboolean accessible) { - return GetPrimitiveField<Primitive::kPrimShort>(env, javaField, javaObj, accessible).GetS(); +static jshort Field_getShort(JNIEnv* env, jobject javaField, jobject javaObj) { + return GetPrimitiveField<Primitive::kPrimShort>(env, javaField, javaObj).GetS(); } -static void SetFieldValue(mirror::Object* o, mirror::ArtField* f, Primitive::Type field_type, - bool allow_references, const JValue& new_value) +ALWAYS_INLINE inline static void SetFieldValue(mirror::Object* o, mirror::Field* f, + Primitive::Type field_type, bool allow_references, + const JValue& new_value) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) { DCHECK(f->GetDeclaringClass()->IsInitialized()); + MemberOffset offset(f->GetOffset()); + const bool is_volatile = f->IsVolatile(); switch (field_type) { case Primitive::kPrimBoolean: - f->SetBoolean<false>(o, new_value.GetZ()); + if (is_volatile) { + o->SetFieldBooleanVolatile<false>(offset, new_value.GetZ()); + } else { + o->SetFieldBoolean<false>(offset, new_value.GetZ()); + } break; case Primitive::kPrimByte: - f->SetByte<false>(o, new_value.GetB()); + if (is_volatile) { + o->SetFieldBooleanVolatile<false>(offset, new_value.GetB()); + } else { + o->SetFieldBoolean<false>(offset, new_value.GetB()); + } break; case Primitive::kPrimChar: - f->SetChar<false>(o, new_value.GetC()); - break; - case Primitive::kPrimDouble: - f->SetDouble<false>(o, new_value.GetD()); - break; - case Primitive::kPrimFloat: - f->SetFloat<false>(o, new_value.GetF()); + if (is_volatile) { + o->SetFieldBooleanVolatile<false>(offset, new_value.GetC()); + } else { + o->SetFieldBoolean<false>(offset, new_value.GetC()); + } break; case Primitive::kPrimInt: - f->SetInt<false>(o, new_value.GetI()); + case Primitive::kPrimFloat: + if (is_volatile) { + o->SetField32Volatile<false>(offset, new_value.GetI()); + } else { + o->SetField32<false>(offset, new_value.GetI()); + } break; case Primitive::kPrimLong: - f->SetLong<false>(o, new_value.GetJ()); + case Primitive::kPrimDouble: + if (is_volatile) { + o->SetField64Volatile<false>(offset, new_value.GetJ()); + } else { + o->SetField64<false>(offset, new_value.GetJ()); + } break; case Primitive::kPrimShort: - f->SetShort<false>(o, new_value.GetS()); + if (is_volatile) { + o->SetFieldShortVolatile<false>(offset, new_value.GetZ()); + } else { + o->SetFieldShort<false>(offset, new_value.GetZ()); + } break; case Primitive::kPrimNot: if (allow_references) { - f->SetObject<false>(o, new_value.GetL()); + if (is_volatile) { + o->SetFieldObjectVolatile<false>(offset, new_value.GetL()); + } else { + o->SetFieldObject<false>(offset, new_value.GetL()); + } break; } // Else fall through to report an error. @@ -271,15 +295,14 @@ static void SetFieldValue(mirror::Object* o, mirror::ArtField* f, Primitive::Typ case Primitive::kPrimVoid: // Never okay. ThrowIllegalArgumentException(StringPrintf("Not a primitive field: %s", - PrettyField(f).c_str()).c_str()); + PrettyField(f->GetArtField()).c_str()).c_str()); return; } } -static void Field_set(JNIEnv* env, jobject javaField, jobject javaObj, jobject javaValue, - jboolean accessible) { +static void Field_set(JNIEnv* env, jobject javaField, jobject javaObj, jobject javaValue) { ScopedFastNativeObjectAccess soa(env); - mirror::ArtField* f = mirror::ArtField::FromReflectedField(soa, javaField); + mirror::Field* f = soa.Decode<mirror::Field*>(javaField); // Check that the receiver is non-null and an instance of the field's declaring class. mirror::Object* o = nullptr; if (!CheckReceiver(soa, javaObj, &f, &o)) { @@ -287,18 +310,11 @@ static void Field_set(JNIEnv* env, jobject javaField, jobject javaObj, jobject j return; } mirror::Class* field_type; - const char* field_type_desciptor = f->GetTypeDescriptor(); + const char* field_type_desciptor = f->GetArtField()->GetTypeDescriptor(); Primitive::Type field_prim_type = Primitive::GetType(field_type_desciptor[0]); if (field_prim_type == Primitive::kPrimNot) { - StackHandleScope<2> hs(soa.Self()); - HandleWrapper<mirror::Object> h_o(hs.NewHandleWrapper(&o)); - HandleWrapper<mirror::ArtField> h_f(hs.NewHandleWrapper(&f)); - // May cause resolution. - field_type = h_f->GetType(true); - if (field_type == nullptr) { - DCHECK(soa.Self()->IsExceptionPending()); - return; - } + field_type = f->GetType(); + DCHECK(field_type != nullptr); } else { field_type = Runtime::Current()->GetClassLinker()->FindPrimitiveClass(field_type_desciptor[0]); } @@ -306,12 +322,12 @@ static void Field_set(JNIEnv* env, jobject javaField, jobject javaObj, jobject j // Unbox the value, if necessary. mirror::Object* boxed_value = soa.Decode<mirror::Object*>(javaValue); JValue unboxed_value; - if (!UnboxPrimitiveForField(boxed_value, field_type, f, &unboxed_value)) { + if (!UnboxPrimitiveForField(boxed_value, field_type, f->GetArtField(), &unboxed_value)) { DCHECK(soa.Self()->IsExceptionPending()); return; } // If field is not set to be accessible, verify it can be accessed by the caller. - if ((accessible == JNI_FALSE) && !VerifyFieldAccess<true>(soa.Self(), f, o)) { + if (!f->IsAccessible() && !VerifyFieldAccess<true>(soa.Self(), f, o)) { DCHECK(soa.Self()->IsExceptionPending()); return; } @@ -320,9 +336,9 @@ static void Field_set(JNIEnv* env, jobject javaField, jobject javaObj, jobject j template<Primitive::Type kPrimitiveType> static void SetPrimitiveField(JNIEnv* env, jobject javaField, jobject javaObj, - const JValue& new_value, jboolean accessible) { + const JValue& new_value) { ScopedFastNativeObjectAccess soa(env); - mirror::ArtField* f = mirror::ArtField::FromReflectedField(soa, javaField); + mirror::Field* f = soa.Decode<mirror::Field*>(javaField); mirror::Object* o = nullptr; if (!CheckReceiver(soa, javaObj, &f, &o)) { return; @@ -330,7 +346,7 @@ static void SetPrimitiveField(JNIEnv* env, jobject javaField, jobject javaObj, Primitive::Type field_type = f->GetTypeAsPrimitiveType(); if (UNLIKELY(field_type == Primitive::kPrimNot)) { ThrowIllegalArgumentException(StringPrintf("Not a primitive field: %s", - PrettyField(f).c_str()).c_str()); + PrettyField(f->GetArtField()).c_str()).c_str()); return; } @@ -342,7 +358,7 @@ static void SetPrimitiveField(JNIEnv* env, jobject javaField, jobject javaObj, } // If field is not set to be accessible, verify it can be accessed by the caller. - if ((accessible == JNI_FALSE) && !VerifyFieldAccess<true>(soa.Self(), f, o)) { + if (!f->IsAccessible() && !VerifyFieldAccess<true>(soa.Self(), f, o)) { DCHECK(soa.Self()->IsExceptionPending()); return; } @@ -351,81 +367,73 @@ static void SetPrimitiveField(JNIEnv* env, jobject javaField, jobject javaObj, SetFieldValue(o, f, field_type, false, wide_value); } -static void Field_setBoolean(JNIEnv* env, jobject javaField, jobject javaObj, jboolean z, - jboolean accessible) { +static void Field_setBoolean(JNIEnv* env, jobject javaField, jobject javaObj, jboolean z) { JValue value; value.SetZ(z); - SetPrimitiveField<Primitive::kPrimBoolean>(env, javaField, javaObj, value, accessible); + SetPrimitiveField<Primitive::kPrimBoolean>(env, javaField, javaObj, value); } -static void Field_setByte(JNIEnv* env, jobject javaField, jobject javaObj, jbyte b, - jboolean accessible) { +static void Field_setByte(JNIEnv* env, jobject javaField, jobject javaObj, jbyte b) { JValue value; value.SetB(b); - SetPrimitiveField<Primitive::kPrimByte>(env, javaField, javaObj, value, accessible); + SetPrimitiveField<Primitive::kPrimByte>(env, javaField, javaObj, value); } -static void Field_setChar(JNIEnv* env, jobject javaField, jobject javaObj, jchar c, - jboolean accessible) { +static void Field_setChar(JNIEnv* env, jobject javaField, jobject javaObj, jchar c) { JValue value; value.SetC(c); - SetPrimitiveField<Primitive::kPrimChar>(env, javaField, javaObj, value, accessible); + SetPrimitiveField<Primitive::kPrimChar>(env, javaField, javaObj, value); } -static void Field_setDouble(JNIEnv* env, jobject javaField, jobject javaObj, jdouble d, - jboolean accessible) { +static void Field_setDouble(JNIEnv* env, jobject javaField, jobject javaObj, jdouble d) { JValue value; value.SetD(d); - SetPrimitiveField<Primitive::kPrimDouble>(env, javaField, javaObj, value, accessible); + SetPrimitiveField<Primitive::kPrimDouble>(env, javaField, javaObj, value); } -static void Field_setFloat(JNIEnv* env, jobject javaField, jobject javaObj, jfloat f, - jboolean accessible) { +static void Field_setFloat(JNIEnv* env, jobject javaField, jobject javaObj, jfloat f) { JValue value; value.SetF(f); - SetPrimitiveField<Primitive::kPrimFloat>(env, javaField, javaObj, value, accessible); + SetPrimitiveField<Primitive::kPrimFloat>(env, javaField, javaObj, value); } -static void Field_setInt(JNIEnv* env, jobject javaField, jobject javaObj, jint i, - jboolean accessible) { +static void Field_setInt(JNIEnv* env, jobject javaField, jobject javaObj, jint i) { JValue value; value.SetI(i); - SetPrimitiveField<Primitive::kPrimInt>(env, javaField, javaObj, value, accessible); + SetPrimitiveField<Primitive::kPrimInt>(env, javaField, javaObj, value); } -static void Field_setLong(JNIEnv* env, jobject javaField, jobject javaObj, jlong j, - jboolean accessible) { +static void Field_setLong(JNIEnv* env, jobject javaField, jobject javaObj, jlong j) { JValue value; value.SetJ(j); - SetPrimitiveField<Primitive::kPrimLong>(env, javaField, javaObj, value, accessible); + SetPrimitiveField<Primitive::kPrimLong>(env, javaField, javaObj, value); } -static void Field_setShort(JNIEnv* env, jobject javaField, jobject javaObj, jshort s, - jboolean accessible) { +static void Field_setShort(JNIEnv* env, jobject javaField, jobject javaObj, jshort s) { JValue value; value.SetS(s); - SetPrimitiveField<Primitive::kPrimShort>(env, javaField, javaObj, value, accessible); + SetPrimitiveField<Primitive::kPrimShort>(env, javaField, javaObj, value); } static JNINativeMethod gMethods[] = { - NATIVE_METHOD(Field, get, "!(Ljava/lang/Object;Z)Ljava/lang/Object;"), - NATIVE_METHOD(Field, getBoolean, "!(Ljava/lang/Object;Z)Z"), - NATIVE_METHOD(Field, getByte, "!(Ljava/lang/Object;Z)B"), - NATIVE_METHOD(Field, getChar, "!(Ljava/lang/Object;Z)C"), - NATIVE_METHOD(Field, getDouble, "!(Ljava/lang/Object;Z)D"), - NATIVE_METHOD(Field, getFloat, "!(Ljava/lang/Object;Z)F"), - NATIVE_METHOD(Field, getInt, "!(Ljava/lang/Object;Z)I"), - NATIVE_METHOD(Field, getLong, "!(Ljava/lang/Object;Z)J"), - NATIVE_METHOD(Field, getShort, "!(Ljava/lang/Object;Z)S"), - NATIVE_METHOD(Field, set, "!(Ljava/lang/Object;Ljava/lang/Object;Z)V"), - NATIVE_METHOD(Field, setBoolean, "!(Ljava/lang/Object;ZZ)V"), - NATIVE_METHOD(Field, setByte, "!(Ljava/lang/Object;BZ)V"), - NATIVE_METHOD(Field, setChar, "!(Ljava/lang/Object;CZ)V"), - NATIVE_METHOD(Field, setDouble, "!(Ljava/lang/Object;DZ)V"), - NATIVE_METHOD(Field, setFloat, "!(Ljava/lang/Object;FZ)V"), - NATIVE_METHOD(Field, setInt, "!(Ljava/lang/Object;IZ)V"), - NATIVE_METHOD(Field, setLong, "!(Ljava/lang/Object;JZ)V"), - NATIVE_METHOD(Field, setShort, "!(Ljava/lang/Object;SZ)V"), + NATIVE_METHOD(Field, get, "!(Ljava/lang/Object;)Ljava/lang/Object;"), + NATIVE_METHOD(Field, getBoolean, "!(Ljava/lang/Object;)Z"), + NATIVE_METHOD(Field, getByte, "!(Ljava/lang/Object;)B"), + NATIVE_METHOD(Field, getChar, "!(Ljava/lang/Object;)C"), + NATIVE_METHOD(Field, getDouble, "!(Ljava/lang/Object;)D"), + NATIVE_METHOD(Field, getFloat, "!(Ljava/lang/Object;)F"), + NATIVE_METHOD(Field, getInt, "!(Ljava/lang/Object;)I"), + NATIVE_METHOD(Field, getLong, "!(Ljava/lang/Object;)J"), + NATIVE_METHOD(Field, getShort, "!(Ljava/lang/Object;)S"), + NATIVE_METHOD(Field, set, "!(Ljava/lang/Object;Ljava/lang/Object;)V"), + NATIVE_METHOD(Field, setBoolean, "!(Ljava/lang/Object;Z)V"), + NATIVE_METHOD(Field, setByte, "!(Ljava/lang/Object;B)V"), + NATIVE_METHOD(Field, setChar, "!(Ljava/lang/Object;C)V"), + NATIVE_METHOD(Field, setDouble, "!(Ljava/lang/Object;D)V"), + NATIVE_METHOD(Field, setFloat, "!(Ljava/lang/Object;F)V"), + NATIVE_METHOD(Field, setInt, "!(Ljava/lang/Object;I)V"), + NATIVE_METHOD(Field, setLong, "!(Ljava/lang/Object;J)V"), + NATIVE_METHOD(Field, setShort, "!(Ljava/lang/Object;S)V"), }; void register_java_lang_reflect_Field(JNIEnv* env) { diff --git a/runtime/proxy_test.cc b/runtime/proxy_test.cc index 3260992fba..cb97049c5b 100644 --- a/runtime/proxy_test.cc +++ b/runtime/proxy_test.cc @@ -185,7 +185,7 @@ TEST_F(ProxyTest, ProxyFieldHelper) { MutableHandle<mirror::ArtField> fhandle = hs.NewHandle(static_fields->Get(0)); EXPECT_EQ("interfaces", std::string(fhandle->GetName())); EXPECT_EQ("[Ljava/lang/Class;", std::string(fhandle->GetTypeDescriptor())); - EXPECT_EQ(interfacesFieldClass.Get(), fhandle->GetType(true)); + EXPECT_EQ(interfacesFieldClass.Get(), fhandle->GetType<true>()); std::string temp; EXPECT_EQ("L$Proxy1234;", std::string(fhandle->GetDeclaringClass()->GetDescriptor(&temp))); EXPECT_FALSE(fhandle->IsPrimitiveType()); @@ -194,7 +194,7 @@ TEST_F(ProxyTest, ProxyFieldHelper) { fhandle.Assign(static_fields->Get(1)); EXPECT_EQ("throws", std::string(fhandle->GetName())); EXPECT_EQ("[[Ljava/lang/Class;", std::string(fhandle->GetTypeDescriptor())); - EXPECT_EQ(throwsFieldClass.Get(), fhandle->GetType(true)); + EXPECT_EQ(throwsFieldClass.Get(), fhandle->GetType<true>()); EXPECT_EQ("L$Proxy1234;", std::string(fhandle->GetDeclaringClass()->GetDescriptor(&temp))); EXPECT_FALSE(fhandle->IsPrimitiveType()); } diff --git a/runtime/reflection-inl.h b/runtime/reflection-inl.h index f21c1a0eb4..f54d4ca123 100644 --- a/runtime/reflection-inl.h +++ b/runtime/reflection-inl.h @@ -22,6 +22,7 @@ #include "base/stringprintf.h" #include "common_throws.h" #include "jvalue.h" +#include "mirror/object-inl.h" #include "primitive.h" #include "utils.h" @@ -99,6 +100,17 @@ inline bool ConvertPrimitiveValue(bool unbox_for_result, return false; } +inline bool VerifyObjectIsClass(mirror::Object* o, mirror::Class* c) { + if (UNLIKELY(o == nullptr)) { + ThrowNullPointerException("null receiver"); + return false; + } else if (UNLIKELY(!o->InstanceOf(c))) { + InvalidReceiverError(o, c); + return false; + } + return true; +} + } // namespace art #endif // ART_RUNTIME_REFLECTION_INL_H_ diff --git a/runtime/reflection.cc b/runtime/reflection.cc index a54a39d5d6..d845e402e7 100644 --- a/runtime/reflection.cc +++ b/runtime/reflection.cc @@ -24,7 +24,6 @@ #include "mirror/art_field-inl.h" #include "mirror/art_method-inl.h" #include "mirror/class-inl.h" -#include "mirror/class.h" #include "mirror/object_array-inl.h" #include "mirror/object_array.h" #include "nth_caller_visitor.h" @@ -628,21 +627,6 @@ jobject InvokeMethod(const ScopedObjectAccessAlreadyRunnable& soa, jobject javaM return soa.AddLocalReference<jobject>(BoxPrimitive(Primitive::GetType(shorty[0]), result)); } -bool VerifyObjectIsClass(mirror::Object* o, mirror::Class* c) { - if (o == nullptr) { - ThrowNullPointerException("null receiver"); - return false; - } else if (!o->InstanceOf(c)) { - std::string expected_class_name(PrettyDescriptor(c)); - std::string actual_class_name(PrettyTypeOf(o)); - ThrowIllegalArgumentException(StringPrintf("Expected receiver of type %s, but got %s", - expected_class_name.c_str(), - actual_class_name.c_str()).c_str()); - return false; - } - return true; -} - mirror::Object* BoxPrimitive(Primitive::Type src_class, const JValue& value) { if (src_class == Primitive::kPrimNot) { return value.GetL(); @@ -840,4 +824,12 @@ bool VerifyAccess(Thread* self, mirror::Object* obj, mirror::Class* declaring_cl return declaring_class->IsInSamePackage(caller_class); } +void InvalidReceiverError(mirror::Object* o, mirror::Class* c) { + std::string expected_class_name(PrettyDescriptor(c)); + std::string actual_class_name(PrettyTypeOf(o)); + ThrowIllegalArgumentException(StringPrintf("Expected receiver of type %s, but got %s", + expected_class_name.c_str(), + actual_class_name.c_str()).c_str()); +} + } // namespace art diff --git a/runtime/reflection.h b/runtime/reflection.h index 857d63b07c..6bef664ca4 100644 --- a/runtime/reflection.h +++ b/runtime/reflection.h @@ -69,13 +69,16 @@ jobject InvokeMethod(const ScopedObjectAccessAlreadyRunnable& soa, jobject metho jobject args, bool accessible) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_); -bool VerifyObjectIsClass(mirror::Object* o, mirror::Class* c) +ALWAYS_INLINE bool VerifyObjectIsClass(mirror::Object* o, mirror::Class* c) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_); bool VerifyAccess(Thread* self, mirror::Object* obj, mirror::Class* declaring_class, uint32_t access_flags, mirror::Class** calling_class) SHARED_LOCKS_REQUIRED(Locks::mutator_lock_); +void InvalidReceiverError(mirror::Object* o, mirror::Class* c) + SHARED_LOCKS_REQUIRED(Locks::mutator_lock_); + } // namespace art #endif // ART_RUNTIME_REFLECTION_H_ diff --git a/runtime/runtime.cc b/runtime/runtime.cc index c462153ed3..d7dd6d0c36 100644 --- a/runtime/runtime.cc +++ b/runtime/runtime.cc @@ -75,6 +75,7 @@ #include "mirror/art_method-inl.h" #include "mirror/class-inl.h" #include "mirror/class_loader.h" +#include "mirror/field.h" #include "mirror/stack_trace_element.h" #include "mirror/throwable.h" #include "monitor.h" @@ -1291,6 +1292,7 @@ void Runtime::VisitConstantRoots(RootCallback* callback, void* arg) { mirror::StackTraceElement::VisitRoots(callback, arg); mirror::String::VisitRoots(callback, arg); mirror::Throwable::VisitRoots(callback, arg); + mirror::Field::VisitRoots(callback, arg); // Visit all the primitive array types classes. mirror::PrimitiveArray<uint8_t>::VisitRoots(callback, arg); // BooleanArray mirror::PrimitiveArray<int8_t>::VisitRoots(callback, arg); // ByteArray diff --git a/runtime/verifier/method_verifier.cc b/runtime/verifier/method_verifier.cc index 988fc0ed0a..1d04192528 100644 --- a/runtime/verifier/method_verifier.cc +++ b/runtime/verifier/method_verifier.cc @@ -3919,7 +3919,7 @@ void MethodVerifier::VerifyISFieldAccess(const Instruction* inst, const RegType& { StackHandleScope<1> hs(self_); HandleWrapper<mirror::ArtField> h_field(hs.NewHandleWrapper(&field)); - field_type_class = h_field->GetType(can_load_classes_); + field_type_class = can_load_classes_ ? h_field->GetType<true>() : h_field->GetType<false>(); } if (field_type_class != nullptr) { field_type = ®_types_.FromClass(field->GetTypeDescriptor(), field_type_class, @@ -4035,7 +4035,7 @@ void MethodVerifier::VerifyQuickFieldAccess(const Instruction* inst, const RegTy { StackHandleScope<1> hs(Thread::Current()); HandleWrapper<mirror::ArtField> h_field(hs.NewHandleWrapper(&field)); - field_type_class = h_field->GetType(can_load_classes_); + field_type_class = can_load_classes_ ? h_field->GetType<true>() : h_field->GetType<false>(); } if (field_type_class != nullptr) { diff --git a/runtime/well_known_classes.cc b/runtime/well_known_classes.cc index 00b4cefb76..d389244f47 100644 --- a/runtime/well_known_classes.cc +++ b/runtime/well_known_classes.cc @@ -109,7 +109,6 @@ jfieldID WellKnownClasses::java_lang_Throwable_stackTrace; jfieldID WellKnownClasses::java_lang_Throwable_stackState; jfieldID WellKnownClasses::java_lang_Throwable_suppressedExceptions; jfieldID WellKnownClasses::java_lang_reflect_AbstractMethod_artMethod; -jfieldID WellKnownClasses::java_lang_reflect_Field_artField; jfieldID WellKnownClasses::java_lang_reflect_Proxy_h; jfieldID WellKnownClasses::java_nio_DirectByteBuffer_capacity; jfieldID WellKnownClasses::java_nio_DirectByteBuffer_effectiveDirectAddress; @@ -244,7 +243,6 @@ void WellKnownClasses::Init(JNIEnv* env) { java_lang_Throwable_stackState = CacheField(env, java_lang_Throwable, false, "stackState", "Ljava/lang/Object;"); java_lang_Throwable_suppressedExceptions = CacheField(env, java_lang_Throwable, false, "suppressedExceptions", "Ljava/util/List;"); java_lang_reflect_AbstractMethod_artMethod = CacheField(env, java_lang_reflect_AbstractMethod, false, "artMethod", "Ljava/lang/reflect/ArtMethod;"); - java_lang_reflect_Field_artField = CacheField(env, java_lang_reflect_Field, false, "artField", "Ljava/lang/reflect/ArtField;"); java_lang_reflect_Proxy_h = CacheField(env, java_lang_reflect_Proxy, false, "h", "Ljava/lang/reflect/InvocationHandler;"); java_nio_DirectByteBuffer_capacity = CacheField(env, java_nio_DirectByteBuffer, false, "capacity", "I"); java_nio_DirectByteBuffer_effectiveDirectAddress = CacheField(env, java_nio_DirectByteBuffer, false, "effectiveDirectAddress", "J"); diff --git a/runtime/well_known_classes.h b/runtime/well_known_classes.h index 1a4f0f8b85..2df1c0e6b0 100644 --- a/runtime/well_known_classes.h +++ b/runtime/well_known_classes.h @@ -103,7 +103,6 @@ struct WellKnownClasses { static jfieldID dalvik_system_DexPathList__Element_dexFile; static jfieldID dalvik_system_PathClassLoader_pathList; static jfieldID java_lang_reflect_AbstractMethod_artMethod; - static jfieldID java_lang_reflect_Field_artField; static jfieldID java_lang_reflect_Proxy_h; static jfieldID java_lang_Thread_daemon; static jfieldID java_lang_Thread_group; diff --git a/test/046-reflect/src/Main.java b/test/046-reflect/src/Main.java index 3fe3881a8d..5c6ca135b7 100644 --- a/test/046-reflect/src/Main.java +++ b/test/046-reflect/src/Main.java @@ -696,22 +696,25 @@ public class Main { private static void checkGetDeclaredConstructor() { try { Method.class.getDeclaredConstructor().setAccessible(true); - System.out.print("Didn't get an exception from method getDeclaredConstructor"); + System.out.print("Didn't get an exception from Method.class.getDeclaredConstructor().setAccessible"); + } catch (SecurityException e) { } catch (NoSuchMethodException e) { } catch (Exception e) { System.out.print(e); } try { Field.class.getDeclaredConstructor().setAccessible(true); - System.out.print("Didn't get an exception from field getDeclaredConstructor"); + System.out.print("Didn't get an exception from Field.class.getDeclaredConstructor().setAccessible"); + } catch (SecurityException e) { } catch (NoSuchMethodException e) { } catch (Exception e) { System.out.print(e); } try { Class.class.getDeclaredConstructor().setAccessible(true); - System.out.print("Didn't get an exception from class getDeclaredConstructor()"); + System.out.print("Didn't get an exception from Class.class.getDeclaredConstructor().setAccessible"); } catch (SecurityException e) { + } catch (NoSuchMethodException e) { } catch (Exception e) { System.out.print(e); } |