/*
 * 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;
  }
}

ALWAYS_INLINE inline static bool ThrowIAEIfRecordFinalField(ObjPtr<mirror::Field> field)
    REQUIRES_SHARED(Locks::mutator_lock_) {
  if (!(field->IsFinal())) {
    return false;
  }
  ObjPtr<mirror::Class> declaring_class = field->GetDeclaringClass();
  DCHECK(declaring_class != nullptr);
  if (!(declaring_class->IsRecordClass())) {
    return false;
  }

  ThrowIllegalAccessException(
          StringPrintf("Cannot set %s field %s of record class %s",
              PrettyJavaAccessFlags(field->GetAccessFlags()).c_str(),
              ArtField::PrettyField(field->GetArtField()).c_str(),
              declaring_class->PrettyClass().c_str()).c_str());

  return true;
}

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;
  }
  if (ThrowIAEIfRecordFinalField(f)) {
    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;
  }
  if (ThrowIAEIfRecordFinalField(f)) {
    DCHECK(soa.Self()->IsExceptionPending());
    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 =
        WellKnownClasses::ToClass(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
