557 lines
		
	
	
		
			22 KiB
		
	
	
	
		
			C++
		
	
	
	
			
		
		
	
	
			557 lines
		
	
	
		
			22 KiB
		
	
	
	
		
			C++
		
	
	
	
| /*
 | |
|  * Copyright (C) 2008 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 "java_lang_reflect_Field.h"
 | |
| 
 | |
| #include "android-base/stringprintf.h"
 | |
| #include "nativehelper/jni_macros.h"
 | |
| 
 | |
| #include "art_field-inl.h"
 | |
| #include "base/utils.h"
 | |
| #include "class_linker-inl.h"
 | |
| #include "class_linker.h"
 | |
| #include "common_throws.h"
 | |
| #include "dex/dex_file-inl.h"
 | |
| #include "dex/dex_file_annotations.h"
 | |
| #include "gc/reference_processor.h"
 | |
| #include "jni/jni_internal.h"
 | |
| #include "jvalue-inl.h"
 | |
| #include "mirror/class-inl.h"
 | |
| #include "mirror/field-inl.h"
 | |
| #include "mirror/object_array-alloc-inl.h"
 | |
| #include "native_util.h"
 | |
| #include "reflection-inl.h"
 | |
| #include "scoped_fast_native_object_access-inl.h"
 | |
| #include "well_known_classes.h"
 | |
| 
 | |
| namespace art {
 | |
| 
 | |
| using android::base::StringPrintf;
 | |
| 
 | |
| template<bool kIsSet>
 | |
| ALWAYS_INLINE inline static bool VerifyFieldAccess(Thread* self,
 | |
|                                                    ObjPtr<mirror::Field> field,
 | |
|                                                    ObjPtr<mirror::Object> obj)
 | |
|     REQUIRES_SHARED(Locks::mutator_lock_) {
 | |
|   if (kIsSet && field->IsFinal()) {
 | |
|     ThrowIllegalAccessException(
 | |
|             StringPrintf("Cannot set %s field %s of class %s",
 | |
|                 PrettyJavaAccessFlags(field->GetAccessFlags()).c_str(),
 | |
|                 ArtField::PrettyField(field->GetArtField()).c_str(),
 | |
|                 field->GetDeclaringClass() == nullptr ? "null" :
 | |
|                     field->GetDeclaringClass()->PrettyClass().c_str()).c_str());
 | |
|     return false;
 | |
|   }
 | |
|   ObjPtr<mirror::Class> calling_class;
 | |
|   if (!VerifyAccess(self,
 | |
|                     obj,
 | |
|                     field->GetDeclaringClass(),
 | |
|                     field->GetAccessFlags(),
 | |
|                     &calling_class,
 | |
|                     1)) {
 | |
|     ThrowIllegalAccessException(
 | |
|             StringPrintf("Class %s cannot access %s field %s of class %s",
 | |
|                 calling_class == nullptr ? "null" : calling_class->PrettyClass().c_str(),
 | |
|                 PrettyJavaAccessFlags(field->GetAccessFlags()).c_str(),
 | |
|                 ArtField::PrettyField(field->GetArtField()).c_str(),
 | |
|                 field->GetDeclaringClass() == nullptr ? "null" :
 | |
|                     field->GetDeclaringClass()->PrettyClass().c_str()).c_str());
 | |
|     return false;
 | |
|   }
 | |
|   return true;
 | |
| }
 | |
| 
 | |
| template<bool kAllowReferences>
 | |
| ALWAYS_INLINE inline static bool GetFieldValue(const ScopedFastNativeObjectAccess& soa,
 | |
|                                                ObjPtr<mirror::Object> o,
 | |
|                                                ObjPtr<mirror::Field> f,
 | |
|                                                Primitive::Type field_type,
 | |
|                                                JValue* value)
 | |
|     REQUIRES_SHARED(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(is_volatile ? o->GetFieldBooleanVolatile(offset) : o->GetFieldBoolean(offset));
 | |
|       return true;
 | |
|     case Primitive::kPrimByte:
 | |
|       value->SetB(is_volatile ? o->GetFieldByteVolatile(offset) : o->GetFieldByte(offset));
 | |
|       return true;
 | |
|     case Primitive::kPrimChar:
 | |
|       value->SetC(is_volatile ? o->GetFieldCharVolatile(offset) : o->GetFieldChar(offset));
 | |
|       return true;
 | |
|     case Primitive::kPrimInt:
 | |
|     case Primitive::kPrimFloat:
 | |
|       value->SetI(is_volatile ? o->GetField32Volatile(offset) : o->GetField32(offset));
 | |
|       return true;
 | |
|     case Primitive::kPrimLong:
 | |
|     case Primitive::kPrimDouble:
 | |
|       value->SetJ(is_volatile ? o->GetField64Volatile(offset) : o->GetField64(offset));
 | |
|       return true;
 | |
|     case Primitive::kPrimShort:
 | |
|       value->SetS(is_volatile ? o->GetFieldShortVolatile(offset) : o->GetFieldShort(offset));
 | |
|       return true;
 | |
|     case Primitive::kPrimNot:
 | |
|       if (kAllowReferences) {
 | |
|         // We need to ensure that a Reference-type object's referent is fetched
 | |
|         // via GetReferent and not directly using a read-barrier (See b/174433134)
 | |
|         const uint32_t class_flags = o->GetClass()->GetClassFlags();
 | |
|         if (UNLIKELY((class_flags & mirror::kClassFlagReference) != 0 &&
 | |
|                      mirror::Reference::ReferentOffset() == offset)) {
 | |
|           // PhantomReference's get() always returns null.
 | |
|           value->SetL((class_flags & mirror::kClassFlagPhantomReference) != 0
 | |
|                           ? nullptr
 | |
|                           : Runtime::Current()->GetHeap()->GetReferenceProcessor()->GetReferent(
 | |
|                                   soa.Self(), o->AsReference()));
 | |
|         } else {
 | |
|           value->SetL(is_volatile ? o->GetFieldObjectVolatile<mirror::Object>(offset) :
 | |
|                       o->GetFieldObject<mirror::Object>(offset));
 | |
|         }
 | |
|         return true;
 | |
|       }
 | |
|       // Else break to report an error.
 | |
|       break;
 | |
|     case Primitive::kPrimVoid:
 | |
|       // Never okay.
 | |
|       break;
 | |
|   }
 | |
|   ThrowIllegalArgumentException(
 | |
|       StringPrintf("Not a primitive field: %s",
 | |
|                    ArtField::PrettyField(f->GetArtField()).c_str()).c_str());
 | |
|   return false;
 | |
| }
 | |
| 
 | |
| ALWAYS_INLINE inline static bool CheckReceiver(const ScopedFastNativeObjectAccess& soa,
 | |
|                                                jobject j_rcvr,
 | |
|                                                ObjPtr<mirror::Field>* f,
 | |
|                                                ObjPtr<mirror::Object>* class_or_rcvr)
 | |
|     REQUIRES_SHARED(Locks::mutator_lock_) {
 | |
|   soa.Self()->AssertThreadSuspensionIsAllowable();
 | |
|   ObjPtr<mirror::Class> declaring_class = (*f)->GetDeclaringClass();
 | |
|   if ((*f)->IsStatic()) {
 | |
|     if (UNLIKELY(!declaring_class->IsVisiblyInitialized())) {
 | |
|       Thread* self = soa.Self();
 | |
|       StackHandleScope<2> hs(self);
 | |
|       HandleWrapperObjPtr<mirror::Field> h_f(hs.NewHandleWrapper(f));
 | |
|       HandleWrapperObjPtr<mirror::Class> h_klass(hs.NewHandleWrapper(&declaring_class));
 | |
|       if (UNLIKELY(!Runtime::Current()->GetClassLinker()->EnsureInitialized(
 | |
|                         self, h_klass, /*can_init_fields=*/ true, /*can_init_parents=*/ true))) {
 | |
|         DCHECK(self->IsExceptionPending());
 | |
|         return false;
 | |
|       }
 | |
|       DCHECK(h_klass->IsInitializing());
 | |
|     }
 | |
|     *class_or_rcvr = declaring_class;
 | |
|     return true;
 | |
|   }
 | |
|   *class_or_rcvr = soa.Decode<mirror::Object>(j_rcvr);
 | |
|   if (!VerifyObjectIsClass(*class_or_rcvr, declaring_class)) {
 | |
|     DCHECK(soa.Self()->IsExceptionPending());
 | |
|     return false;
 | |
|   }
 | |
|   return true;
 | |
| }
 | |
| 
 | |
| static jobject Field_get(JNIEnv* env, jobject javaField, jobject javaObj) {
 | |
|   ScopedFastNativeObjectAccess soa(env);
 | |
|   ObjPtr<mirror::Field> f = soa.Decode<mirror::Field>(javaField);
 | |
|   ObjPtr<mirror::Object> o;
 | |
|   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 (!f->IsAccessible() && !VerifyFieldAccess<false>(soa.Self(), f, o)) {
 | |
|     DCHECK(soa.Self()->IsExceptionPending());
 | |
|     return nullptr;
 | |
|   }
 | |
|   // We now don't expect suspension unless an exception is thrown.
 | |
|   // Get the field's value, boxing if necessary.
 | |
|   Primitive::Type field_type = f->GetTypeAsPrimitiveType();
 | |
|   JValue value;
 | |
|   if (!GetFieldValue<true>(soa, o, f, field_type, &value)) {
 | |
|     DCHECK(soa.Self()->IsExceptionPending());
 | |
|     return nullptr;
 | |
|   }
 | |
|   return soa.AddLocalReference<jobject>(BoxPrimitive(field_type, value));
 | |
| }
 | |
| 
 | |
| template<Primitive::Type kPrimitiveType>
 | |
| ALWAYS_INLINE inline static JValue GetPrimitiveField(JNIEnv* env,
 | |
|                                                      jobject javaField,
 | |
|                                                      jobject javaObj) {
 | |
|   ScopedFastNativeObjectAccess soa(env);
 | |
|   ObjPtr<mirror::Field> f = soa.Decode<mirror::Field>(javaField);
 | |
|   ObjPtr<mirror::Object> o;
 | |
|   if (!CheckReceiver(soa, javaObj, &f, &o)) {
 | |
|     DCHECK(soa.Self()->IsExceptionPending());
 | |
|     return JValue();
 | |
|   }
 | |
| 
 | |
|   // If field is not set to be accessible, verify it can be accessed by the caller.
 | |
|   if (!f->IsAccessible() && !VerifyFieldAccess<false>(soa.Self(), f, o)) {
 | |
|     DCHECK(soa.Self()->IsExceptionPending());
 | |
|     return JValue();
 | |
|   }
 | |
| 
 | |
|   // We now don't expect suspension unless an exception is thrown.
 | |
|   // Read the value.
 | |
|   Primitive::Type field_type = f->GetTypeAsPrimitiveType();
 | |
|   JValue field_value;
 | |
|   if (field_type == kPrimitiveType) {
 | |
|     // This if statement should get optimized out since we only pass in valid primitive types.
 | |
|     if (UNLIKELY(!GetFieldValue<false>(soa, o, f, kPrimitiveType, &field_value))) {
 | |
|       DCHECK(soa.Self()->IsExceptionPending());
 | |
|       return JValue();
 | |
|     }
 | |
|     return field_value;
 | |
|   }
 | |
|   if (!GetFieldValue<false>(soa, o, f, field_type, &field_value)) {
 | |
|     DCHECK(soa.Self()->IsExceptionPending());
 | |
|     return JValue();
 | |
|   }
 | |
|   // Widen it if necessary (and possible).
 | |
|   JValue wide_value;
 | |
|   if (!ConvertPrimitiveValue(false, field_type, kPrimitiveType, field_value,
 | |
|                              &wide_value)) {
 | |
|     DCHECK(soa.Self()->IsExceptionPending());
 | |
|     return JValue();
 | |
|   }
 | |
|   return wide_value;
 | |
| }
 | |
| 
 | |
| 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) {
 | |
|   return GetPrimitiveField<Primitive::kPrimByte>(env, javaField, javaObj).GetB();
 | |
| }
 | |
| 
 | |
| 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) {
 | |
|   return GetPrimitiveField<Primitive::kPrimDouble>(env, javaField, javaObj).GetD();
 | |
| }
 | |
| 
 | |
| 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) {
 | |
|   return GetPrimitiveField<Primitive::kPrimInt>(env, javaField, javaObj).GetI();
 | |
| }
 | |
| 
 | |
| 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) {
 | |
|   return GetPrimitiveField<Primitive::kPrimShort>(env, javaField, javaObj).GetS();
 | |
| }
 | |
| 
 | |
| ALWAYS_INLINE inline static void SetFieldValue(ObjPtr<mirror::Object> o,
 | |
|                                                ObjPtr<mirror::Field> f,
 | |
|                                                Primitive::Type field_type,
 | |
|                                                bool allow_references,
 | |
|                                                const JValue& new_value)
 | |
|     REQUIRES_SHARED(Locks::mutator_lock_) {
 | |
|   DCHECK(f->GetDeclaringClass()->IsInitializing());
 | |
|   MemberOffset offset(f->GetOffset());
 | |
|   const bool is_volatile = f->IsVolatile();
 | |
|   switch (field_type) {
 | |
|   case Primitive::kPrimBoolean:
 | |
|     if (is_volatile) {
 | |
|       o->SetFieldBooleanVolatile<false>(offset, new_value.GetZ());
 | |
|     } else {
 | |
|       o->SetFieldBoolean<false>(offset, new_value.GetZ());
 | |
|     }
 | |
|     break;
 | |
|   case Primitive::kPrimByte:
 | |
|     if (is_volatile) {
 | |
|       o->SetFieldBooleanVolatile<false>(offset, new_value.GetB());
 | |
|     } else {
 | |
|       o->SetFieldBoolean<false>(offset, new_value.GetB());
 | |
|     }
 | |
|     break;
 | |
|   case Primitive::kPrimChar:
 | |
|     if (is_volatile) {
 | |
|       o->SetFieldCharVolatile<false>(offset, new_value.GetC());
 | |
|     } else {
 | |
|       o->SetFieldChar<false>(offset, new_value.GetC());
 | |
|     }
 | |
|     break;
 | |
|   case Primitive::kPrimInt:
 | |
|   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:
 | |
|   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:
 | |
|     if (is_volatile) {
 | |
|       o->SetFieldShortVolatile<false>(offset, new_value.GetS());
 | |
|     } else {
 | |
|       o->SetFieldShort<false>(offset, new_value.GetS());
 | |
|     }
 | |
|     break;
 | |
|   case Primitive::kPrimNot:
 | |
|     if (allow_references) {
 | |
|       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.
 | |
|     FALLTHROUGH_INTENDED;
 | |
|   case Primitive::kPrimVoid:
 | |
|     // Never okay.
 | |
|     ThrowIllegalArgumentException(
 | |
|         StringPrintf("Not a primitive field: %s",
 | |
|                      ArtField::PrettyField(f->GetArtField()).c_str()).c_str());
 | |
|     return;
 | |
|   }
 | |
| }
 | |
| 
 | |
| static void Field_set(JNIEnv* env, jobject javaField, jobject javaObj, jobject javaValue) {
 | |
|   ScopedFastNativeObjectAccess soa(env);
 | |
|   ObjPtr<mirror::Field> f = soa.Decode<mirror::Field>(javaField);
 | |
|   // Check that the receiver is non-null and an instance of the field's declaring class.
 | |
|   ObjPtr<mirror::Object> o;
 | |
|   if (!CheckReceiver(soa, javaObj, &f, &o)) {
 | |
|     DCHECK(soa.Self()->IsExceptionPending());
 | |
|     return;
 | |
|   }
 | |
|   ObjPtr<mirror::Class> field_type;
 | |
|   const char* field_type_descriptor = f->GetArtField()->GetTypeDescriptor();
 | |
|   Primitive::Type field_prim_type = Primitive::GetType(field_type_descriptor[0]);
 | |
|   if (field_prim_type == Primitive::kPrimNot) {
 | |
|     field_type = f->GetType();
 | |
|   } else {
 | |
|     field_type =
 | |
|         Runtime::Current()->GetClassLinker()->LookupPrimitiveClass(field_type_descriptor[0]);
 | |
|   }
 | |
|   DCHECK(field_type != nullptr) << field_type_descriptor;
 | |
|   // We now don't expect suspension unless an exception is thrown.
 | |
|   // Unbox the value, if necessary.
 | |
|   ObjPtr<mirror::Object> boxed_value = soa.Decode<mirror::Object>(javaValue);
 | |
|   JValue 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 (!f->IsAccessible() && !VerifyFieldAccess<true>(soa.Self(), f, o)) {
 | |
|     DCHECK(soa.Self()->IsExceptionPending());
 | |
|     return;
 | |
|   }
 | |
|   SetFieldValue(o, f, field_prim_type, true, unboxed_value);
 | |
| }
 | |
| 
 | |
| template<Primitive::Type kPrimitiveType>
 | |
| static void SetPrimitiveField(JNIEnv* env,
 | |
|                               jobject javaField,
 | |
|                               jobject javaObj,
 | |
|                               const JValue& new_value) {
 | |
|   ScopedFastNativeObjectAccess soa(env);
 | |
|   ObjPtr<mirror::Field> f = soa.Decode<mirror::Field>(javaField);
 | |
|   ObjPtr<mirror::Object> o;
 | |
|   if (!CheckReceiver(soa, javaObj, &f, &o)) {
 | |
|     return;
 | |
|   }
 | |
|   Primitive::Type field_type = f->GetTypeAsPrimitiveType();
 | |
|   if (UNLIKELY(field_type == Primitive::kPrimNot)) {
 | |
|     ThrowIllegalArgumentException(
 | |
|         StringPrintf("Not a primitive field: %s",
 | |
|                      ArtField::PrettyField(f->GetArtField()).c_str()).c_str());
 | |
|     return;
 | |
|   }
 | |
| 
 | |
|   // Widen the value if necessary (and possible).
 | |
|   JValue wide_value;
 | |
|   if (!ConvertPrimitiveValue(false, kPrimitiveType, field_type, new_value, &wide_value)) {
 | |
|     DCHECK(soa.Self()->IsExceptionPending());
 | |
|     return;
 | |
|   }
 | |
| 
 | |
|   // If field is not set to be accessible, verify it can be accessed by the caller.
 | |
|   if (!f->IsAccessible() && !VerifyFieldAccess<true>(soa.Self(), f, o)) {
 | |
|     DCHECK(soa.Self()->IsExceptionPending());
 | |
|     return;
 | |
|   }
 | |
| 
 | |
|   // Write the value.
 | |
|   SetFieldValue(o, f, field_type, false, wide_value);
 | |
| }
 | |
| 
 | |
| static void Field_setBoolean(JNIEnv* env, jobject javaField, jobject javaObj, jboolean z) {
 | |
|   JValue value;
 | |
|   value.SetZ(z);
 | |
|   SetPrimitiveField<Primitive::kPrimBoolean>(env, javaField, javaObj, value);
 | |
| }
 | |
| 
 | |
| static void Field_setByte(JNIEnv* env, jobject javaField, jobject javaObj, jbyte b) {
 | |
|   JValue value;
 | |
|   value.SetB(b);
 | |
|   SetPrimitiveField<Primitive::kPrimByte>(env, javaField, javaObj, value);
 | |
| }
 | |
| 
 | |
| static void Field_setChar(JNIEnv* env, jobject javaField, jobject javaObj, jchar c) {
 | |
|   JValue value;
 | |
|   value.SetC(c);
 | |
|   SetPrimitiveField<Primitive::kPrimChar>(env, javaField, javaObj, value);
 | |
| }
 | |
| 
 | |
| static void Field_setDouble(JNIEnv* env, jobject javaField, jobject javaObj, jdouble d) {
 | |
|   JValue value;
 | |
|   value.SetD(d);
 | |
|   SetPrimitiveField<Primitive::kPrimDouble>(env, javaField, javaObj, value);
 | |
| }
 | |
| 
 | |
| static void Field_setFloat(JNIEnv* env, jobject javaField, jobject javaObj, jfloat f) {
 | |
|   JValue value;
 | |
|   value.SetF(f);
 | |
|   SetPrimitiveField<Primitive::kPrimFloat>(env, javaField, javaObj, value);
 | |
| }
 | |
| 
 | |
| static void Field_setInt(JNIEnv* env, jobject javaField, jobject javaObj, jint i) {
 | |
|   JValue value;
 | |
|   value.SetI(i);
 | |
|   SetPrimitiveField<Primitive::kPrimInt>(env, javaField, javaObj, value);
 | |
| }
 | |
| 
 | |
| static void Field_setLong(JNIEnv* env, jobject javaField, jobject javaObj, jlong j) {
 | |
|   JValue value;
 | |
|   value.SetJ(j);
 | |
|   SetPrimitiveField<Primitive::kPrimLong>(env, javaField, javaObj, value);
 | |
| }
 | |
| 
 | |
| static void Field_setShort(JNIEnv* env, jobject javaField, jobject javaObj, jshort s) {
 | |
|   JValue value;
 | |
|   value.SetS(s);
 | |
|   SetPrimitiveField<Primitive::kPrimShort>(env, javaField, javaObj, value);
 | |
| }
 | |
| 
 | |
| static jobject Field_getAnnotationNative(JNIEnv* env, jobject javaField, jclass annotationType) {
 | |
|   ScopedFastNativeObjectAccess soa(env);
 | |
|   StackHandleScope<1> hs(soa.Self());
 | |
|   ArtField* field = soa.Decode<mirror::Field>(javaField)->GetArtField();
 | |
|   if (field->GetDeclaringClass()->IsProxyClass()) {
 | |
|     return nullptr;
 | |
|   }
 | |
|   Handle<mirror::Class> klass(hs.NewHandle(soa.Decode<mirror::Class>(annotationType)));
 | |
|   return soa.AddLocalReference<jobject>(annotations::GetAnnotationForField(field, klass));
 | |
| }
 | |
| 
 | |
| static jlong Field_getArtField(JNIEnv* env, jobject javaField) {
 | |
|   ScopedFastNativeObjectAccess soa(env);
 | |
|   ArtField* field = soa.Decode<mirror::Field>(javaField)->GetArtField();
 | |
|   return reinterpret_cast<jlong>(field);
 | |
| }
 | |
| 
 | |
| static jstring Field_getNameInternal(JNIEnv* env, jobject javaField) {
 | |
|   ScopedFastNativeObjectAccess soa(env);
 | |
|   ArtField* field = soa.Decode<mirror::Field>(javaField)->GetArtField();
 | |
|   return soa.AddLocalReference<jstring>(field->ResolveNameString());
 | |
| }
 | |
| 
 | |
| static jobjectArray Field_getDeclaredAnnotations(JNIEnv* env, jobject javaField) {
 | |
|   ScopedFastNativeObjectAccess soa(env);
 | |
|   ArtField* field = soa.Decode<mirror::Field>(javaField)->GetArtField();
 | |
|   if (field->GetDeclaringClass()->IsProxyClass()) {
 | |
|     // Return an empty array instead of a null pointer.
 | |
|     ObjPtr<mirror::Class> annotation_array_class =
 | |
|         soa.Decode<mirror::Class>(WellKnownClasses::java_lang_annotation_Annotation__array);
 | |
|     ObjPtr<mirror::ObjectArray<mirror::Object>> empty_array =
 | |
|         mirror::ObjectArray<mirror::Object>::Alloc(soa.Self(), annotation_array_class, 0);
 | |
|     return soa.AddLocalReference<jobjectArray>(empty_array);
 | |
|   }
 | |
|   return soa.AddLocalReference<jobjectArray>(annotations::GetAnnotationsForField(field));
 | |
| }
 | |
| 
 | |
| static jobjectArray Field_getSignatureAnnotation(JNIEnv* env, jobject javaField) {
 | |
|   ScopedFastNativeObjectAccess soa(env);
 | |
|   ArtField* field = soa.Decode<mirror::Field>(javaField)->GetArtField();
 | |
|   if (field->GetDeclaringClass()->IsProxyClass()) {
 | |
|     return nullptr;
 | |
|   }
 | |
|   return soa.AddLocalReference<jobjectArray>(annotations::GetSignatureAnnotationForField(field));
 | |
| }
 | |
| 
 | |
| static jboolean Field_isAnnotationPresentNative(JNIEnv* env,
 | |
|                                                 jobject javaField,
 | |
|                                                 jclass annotationType) {
 | |
|   ScopedFastNativeObjectAccess soa(env);
 | |
|   StackHandleScope<1> hs(soa.Self());
 | |
|   ArtField* field = soa.Decode<mirror::Field>(javaField)->GetArtField();
 | |
|   if (field->GetDeclaringClass()->IsProxyClass()) {
 | |
|     return false;
 | |
|   }
 | |
|   Handle<mirror::Class> klass(hs.NewHandle(soa.Decode<mirror::Class>(annotationType)));
 | |
|   return annotations::IsFieldAnnotationPresent(field, klass);
 | |
| }
 | |
| 
 | |
| static JNINativeMethod gMethods[] = {
 | |
|   FAST_NATIVE_METHOD(Field, get,        "(Ljava/lang/Object;)Ljava/lang/Object;"),
 | |
|   FAST_NATIVE_METHOD(Field, getBoolean, "(Ljava/lang/Object;)Z"),
 | |
|   FAST_NATIVE_METHOD(Field, getByte,    "(Ljava/lang/Object;)B"),
 | |
|   FAST_NATIVE_METHOD(Field, getChar,    "(Ljava/lang/Object;)C"),
 | |
|   FAST_NATIVE_METHOD(Field, getAnnotationNative,
 | |
|                 "(Ljava/lang/Class;)Ljava/lang/annotation/Annotation;"),
 | |
|   FAST_NATIVE_METHOD(Field, getArtField, "()J"),
 | |
|   FAST_NATIVE_METHOD(Field, getDeclaredAnnotations, "()[Ljava/lang/annotation/Annotation;"),
 | |
|   FAST_NATIVE_METHOD(Field, getSignatureAnnotation, "()[Ljava/lang/String;"),
 | |
|   FAST_NATIVE_METHOD(Field, getDouble,  "(Ljava/lang/Object;)D"),
 | |
|   FAST_NATIVE_METHOD(Field, getFloat,   "(Ljava/lang/Object;)F"),
 | |
|   FAST_NATIVE_METHOD(Field, getInt,     "(Ljava/lang/Object;)I"),
 | |
|   FAST_NATIVE_METHOD(Field, getLong,    "(Ljava/lang/Object;)J"),
 | |
|   FAST_NATIVE_METHOD(Field, getNameInternal, "()Ljava/lang/String;"),
 | |
|   FAST_NATIVE_METHOD(Field, getShort,   "(Ljava/lang/Object;)S"),
 | |
|   FAST_NATIVE_METHOD(Field, isAnnotationPresentNative, "(Ljava/lang/Class;)Z"),
 | |
|   FAST_NATIVE_METHOD(Field, set,        "(Ljava/lang/Object;Ljava/lang/Object;)V"),
 | |
|   FAST_NATIVE_METHOD(Field, setBoolean, "(Ljava/lang/Object;Z)V"),
 | |
|   FAST_NATIVE_METHOD(Field, setByte,    "(Ljava/lang/Object;B)V"),
 | |
|   FAST_NATIVE_METHOD(Field, setChar,    "(Ljava/lang/Object;C)V"),
 | |
|   FAST_NATIVE_METHOD(Field, setDouble,  "(Ljava/lang/Object;D)V"),
 | |
|   FAST_NATIVE_METHOD(Field, setFloat,   "(Ljava/lang/Object;F)V"),
 | |
|   FAST_NATIVE_METHOD(Field, setInt,     "(Ljava/lang/Object;I)V"),
 | |
|   FAST_NATIVE_METHOD(Field, setLong,    "(Ljava/lang/Object;J)V"),
 | |
|   FAST_NATIVE_METHOD(Field, setShort,   "(Ljava/lang/Object;S)V"),
 | |
| };
 | |
| 
 | |
| void register_java_lang_reflect_Field(JNIEnv* env) {
 | |
|   REGISTER_NATIVE_METHODS("java/lang/reflect/Field");
 | |
| }
 | |
| 
 | |
| }  // namespace art
 |