Support field VarHandle objects in boot image.

Test: Build with WIP changes to implement AtomicInteger with
      VarHandle. Build succeeds.
Test: m test-art-host-gtest
Test: testrunner.py --host --optimizing
Bug: 191765508
Change-Id: I084ab7b3cd082570a090f3470fdfb792b80f4505
diff --git a/dex2oat/linker/image_writer.cc b/dex2oat/linker/image_writer.cc
index 38855cb..d7c2d65 100644
--- a/dex2oat/linker/image_writer.cc
+++ b/dex2oat/linker/image_writer.cc
@@ -72,6 +72,7 @@
 #include "mirror/object_array-alloc-inl.h"
 #include "mirror/object_array-inl.h"
 #include "mirror/string-inl.h"
+#include "mirror/var_handle.h"
 #include "nterp_helpers.h"
 #include "oat.h"
 #include "oat_file.h"
@@ -3077,6 +3078,19 @@
   }
 }
 
+ArtField* ImageWriter::NativeLocationInImage(ArtField* src_field) {
+  // Fields are not individually stored in the native relocation map. Use the field array.
+  ObjPtr<mirror::Class> declaring_class = src_field->GetDeclaringClass();
+  LengthPrefixedArray<ArtField>* src_fields =
+      src_field->IsStatic() ? declaring_class->GetSFieldsPtr() : declaring_class->GetIFieldsPtr();
+  DCHECK(src_fields != nullptr);
+  LengthPrefixedArray<ArtField>* dst_fields = NativeLocationInImage(src_fields);
+  DCHECK(dst_fields != nullptr);
+  size_t field_offset =
+      reinterpret_cast<uint8_t*>(src_field) - reinterpret_cast<uint8_t*>(src_fields);
+  return reinterpret_cast<ArtField*>(reinterpret_cast<uint8_t*>(dst_fields) + field_offset);
+}
+
 class ImageWriter::NativeLocationVisitor {
  public:
   explicit NativeLocationVisitor(ImageWriter* image_writer)
@@ -3147,17 +3161,24 @@
     ObjPtr<mirror::Class> klass = orig->GetClass();
     if (klass == GetClassRoot<mirror::Method>(class_roots) ||
         klass == GetClassRoot<mirror::Constructor>(class_roots)) {
-      // Need to go update the ArtMethod.
+      // Need to update the ArtMethod.
       auto* dest = down_cast<mirror::Executable*>(copy);
       auto* src = down_cast<mirror::Executable*>(orig);
       ArtMethod* src_method = src->GetArtMethod();
       CopyAndFixupPointer(dest, mirror::Executable::ArtMethodOffset(), src_method);
+    } else if (klass == GetClassRoot<mirror::FieldVarHandle>(class_roots) ||
+               klass == GetClassRoot<mirror::StaticFieldVarHandle>(class_roots)) {
+      // Need to update the ArtField.
+      auto* dest = down_cast<mirror::FieldVarHandle*>(copy);
+      auto* src = down_cast<mirror::FieldVarHandle*>(orig);
+      ArtField* src_field = src->GetArtField();
+      CopyAndFixupPointer(dest, mirror::FieldVarHandle::ArtFieldOffset(), src_field);
     } else if (klass == GetClassRoot<mirror::DexCache>(class_roots)) {
       down_cast<mirror::DexCache*>(copy)->ResetNativeFields();
     } else if (klass->IsClassLoaderClass()) {
       mirror::ClassLoader* copy_loader = down_cast<mirror::ClassLoader*>(copy);
       // If src is a ClassLoader, set the class table to null so that it gets recreated by the
-      // ClassLoader.
+      // ClassLinker.
       copy_loader->SetClassTable(nullptr);
       // Also set allocator to null to be safe. The allocator is created when we create the class
       // table. We also never expect to unload things in the image since they are held live as
@@ -3525,30 +3546,36 @@
   dest->Assign(GetImageAddress(src.Ptr()));
 }
 
-void ImageWriter::CopyAndFixupPointer(void** target, void* value, PointerSize pointer_size) {
-  void* new_value = NativeLocationInImage(value);
+template <typename ValueType>
+void ImageWriter::CopyAndFixupPointer(
+    void** target, ValueType src_value, PointerSize pointer_size) {
+  DCHECK(src_value != nullptr);
+  void* new_value = NativeLocationInImage(src_value);
+  DCHECK(new_value != nullptr);
   if (pointer_size == PointerSize::k32) {
     *reinterpret_cast<uint32_t*>(target) = reinterpret_cast32<uint32_t>(new_value);
   } else {
     *reinterpret_cast<uint64_t*>(target) = reinterpret_cast64<uint64_t>(new_value);
   }
-  DCHECK(value != nullptr);
 }
 
-void ImageWriter::CopyAndFixupPointer(void** target, void* value)
+template <typename ValueType>
+void ImageWriter::CopyAndFixupPointer(void** target, ValueType src_value)
     REQUIRES_SHARED(Locks::mutator_lock_) {
-  CopyAndFixupPointer(target, value, target_ptr_size_);
+  CopyAndFixupPointer(target, src_value, target_ptr_size_);
 }
 
+template <typename ValueType>
 void ImageWriter::CopyAndFixupPointer(
-    void* object, MemberOffset offset, void* value, PointerSize pointer_size) {
+    void* object, MemberOffset offset, ValueType src_value, PointerSize pointer_size) {
   void** target =
       reinterpret_cast<void**>(reinterpret_cast<uint8_t*>(object) + offset.Uint32Value());
-  return CopyAndFixupPointer(target, value, pointer_size);
+  return CopyAndFixupPointer(target, src_value, pointer_size);
 }
 
-void ImageWriter::CopyAndFixupPointer(void* object, MemberOffset offset, void* value) {
-  return CopyAndFixupPointer(object, offset, value, target_ptr_size_);
+template <typename ValueType>
+void ImageWriter::CopyAndFixupPointer(void* object, MemberOffset offset, ValueType src_value) {
+  return CopyAndFixupPointer(object, offset, src_value, target_ptr_size_);
 }
 
 }  // namespace linker
diff --git a/dex2oat/linker/image_writer.h b/dex2oat/linker/image_writer.h
index 1321ced..1a0d4c8 100644
--- a/dex2oat/linker/image_writer.h
+++ b/dex2oat/linker/image_writer.h
@@ -566,6 +566,7 @@
   // Location of where the object will be when the image is loaded at runtime.
   template <typename T>
   T* NativeLocationInImage(T* obj) REQUIRES_SHARED(Locks::mutator_lock_);
+  ArtField* NativeLocationInImage(ArtField* src_field) REQUIRES_SHARED(Locks::mutator_lock_);
 
   // Return true if `dex_cache` belongs to the image we're writing.
   // For a boot image, this is true for all dex caches.
@@ -603,15 +604,19 @@
   void CopyAndFixupReference(DestType* dest, ObjPtr<mirror::Object> src)
       REQUIRES_SHARED(Locks::mutator_lock_);
 
-  // Copy a native pointer and record image relocation.
-  void CopyAndFixupPointer(void** target, void* value, PointerSize pointer_size)
+  // Translate a native pointer to the destination value and store in the target location.
+  template <typename ValueType>
+  void CopyAndFixupPointer(void** target, ValueType src_value, PointerSize pointer_size)
       REQUIRES_SHARED(Locks::mutator_lock_);
-  void CopyAndFixupPointer(void** target, void* value)
+  template <typename ValueType>
+  void CopyAndFixupPointer(void** target, ValueType src_value)
       REQUIRES_SHARED(Locks::mutator_lock_);
+  template <typename ValueType>
   void CopyAndFixupPointer(
-      void* object, MemberOffset offset, void* value, PointerSize pointer_size)
+      void* object, MemberOffset offset, ValueType src_value, PointerSize pointer_size)
       REQUIRES_SHARED(Locks::mutator_lock_);
-  void CopyAndFixupPointer(void* object, MemberOffset offset, void* value)
+  template <typename ValueType>
+  void CopyAndFixupPointer(void* object, MemberOffset offset, ValueType src_value)
       REQUIRES_SHARED(Locks::mutator_lock_);
 
   /*
diff --git a/runtime/gc/space/image_space.cc b/runtime/gc/space/image_space.cc
index d70b1cf..c1410ce 100644
--- a/runtime/gc/space/image_space.cc
+++ b/runtime/gc/space/image_space.cc
@@ -55,6 +55,7 @@
 #include "mirror/executable-inl.h"
 #include "mirror/object-inl.h"
 #include "mirror/object-refvisitor-inl.h"
+#include "mirror/var_handle.h"
 #include "oat.h"
 #include "oat_file.h"
 #include "profile/profile_compilation_info.h"
@@ -1201,6 +1202,9 @@
       return true;
     }
     ScopedDebugDisallowReadBarriers sddrb(Thread::Current());
+    // TODO: Assert that the app image does not contain any Method, Constructor,
+    // FieldVarHandle or StaticFieldVarHandle. These require extra relocation
+    // for the `ArtMethod*` and `ArtField*` pointers they contain.
 
     using ForwardObject = ForwardAddress<RelocationRange, RelocationRange>;
     ForwardObject forward_object(boot_image, app_image_objects);
@@ -2530,6 +2534,8 @@
     ObjPtr<mirror::Class> class_class;
     ObjPtr<mirror::Class> method_class;
     ObjPtr<mirror::Class> constructor_class;
+    ObjPtr<mirror::Class> field_var_handle_class;
+    ObjPtr<mirror::Class> static_field_var_handle_class;
     {
       ObjPtr<mirror::ObjectArray<mirror::Object>> image_roots =
           simple_relocate_visitor(first_header.GetImageRoots<kWithoutReadBarrier>().Ptr());
@@ -2549,6 +2555,10 @@
         class_class = GetClassRoot<mirror::Class, kWithoutReadBarrier>(class_roots);
         method_class = GetClassRoot<mirror::Method, kWithoutReadBarrier>(class_roots);
         constructor_class = GetClassRoot<mirror::Constructor, kWithoutReadBarrier>(class_roots);
+        field_var_handle_class =
+            GetClassRoot<mirror::FieldVarHandle, kWithoutReadBarrier>(class_roots);
+        static_field_var_handle_class =
+            GetClassRoot<mirror::StaticFieldVarHandle, kWithoutReadBarrier>(class_roots);
       } else {
         DCHECK(!patched_objects->Test(class_roots.Ptr()));
         class_class = simple_relocate_visitor(
@@ -2557,6 +2567,10 @@
             GetClassRoot<mirror::Method, kWithoutReadBarrier>(class_roots).Ptr());
         constructor_class = simple_relocate_visitor(
             GetClassRoot<mirror::Constructor, kWithoutReadBarrier>(class_roots).Ptr());
+        field_var_handle_class = simple_relocate_visitor(
+            GetClassRoot<mirror::FieldVarHandle, kWithoutReadBarrier>(class_roots).Ptr());
+        static_field_var_handle_class = simple_relocate_visitor(
+            GetClassRoot<mirror::StaticFieldVarHandle, kWithoutReadBarrier>(class_roots).Ptr());
       }
     }
 
@@ -2667,6 +2681,13 @@
             as_executable->SetArtMethod</*kTransactionActive=*/ false,
                                         /*kCheckTransaction=*/ true,
                                         kVerifyNone>(patched_method);
+          } else if (klass == field_var_handle_class || klass == static_field_var_handle_class) {
+            // Patch the ArtField* in the mirror::FieldVarHandle subobject.
+            ObjPtr<mirror::FieldVarHandle> as_field_var_handle =
+                ObjPtr<mirror::FieldVarHandle>::DownCast(object);
+            ArtField* unpatched_field = as_field_var_handle->GetArtField<kVerifyNone>();
+            ArtField* patched_field = main_relocate_visitor(unpatched_field);
+            as_field_var_handle->SetArtField<kVerifyNone>(patched_field);
           }
         }
         pos += RoundUp(object->SizeOf<kVerifyNone>(), kObjectAlignment);
diff --git a/runtime/mirror/var_handle.cc b/runtime/mirror/var_handle.cc
index c071e23..8f17c58 100644
--- a/runtime/mirror/var_handle.cc
+++ b/runtime/mirror/var_handle.cc
@@ -1646,16 +1646,12 @@
   UNREACHABLE();
 }
 
-ArtField* FieldVarHandle::GetField() {
-  return reinterpret_cast64<ArtField*>(GetField64(ArtFieldOffset()));
-}
-
 bool FieldVarHandle::Access(AccessMode access_mode,
                             ShadowFrame* shadow_frame,
                             const InstructionOperands* const operands,
                             JValue* result) {
   ShadowFrameGetter getter(*shadow_frame, operands);
-  ArtField* field = GetField();
+  ArtField* field = GetArtField();
   ObjPtr<Object> obj;
   if (field->IsStatic()) {
     DCHECK_LE(operands->GetNumberOfOperands(),
@@ -1998,22 +1994,20 @@
 }
 
 void FieldVarHandle::VisitTarget(ReflectiveValueVisitor* v) {
-  ArtField* orig = GetField();
+  ArtField* orig = GetArtField();
   ArtField* new_value =
       v->VisitField(orig, HeapReflectiveSourceInfo(kSourceJavaLangInvokeFieldVarHandle, this));
   if (orig != new_value) {
-    SetField64</*kTransactionActive*/ false>(ArtFieldOffset(),
-                                             reinterpret_cast<uintptr_t>(new_value));
+    SetArtField(new_value);
   }
 }
 
 void StaticFieldVarHandle::VisitTarget(ReflectiveValueVisitor* v) {
-  ArtField* orig = GetField();
+  ArtField* orig = GetArtField();
   ArtField* new_value =
       v->VisitField(orig, HeapReflectiveSourceInfo(kSourceJavaLangInvokeFieldVarHandle, this));
   if (orig != new_value) {
-    SetField64</*kTransactionActive*/ false>(ArtFieldOffset(),
-                                             reinterpret_cast<uintptr_t>(new_value));
+    SetArtField(new_value);
     SetFieldObject<false>(DeclaringClassOffset(), new_value->GetDeclaringClass());
   }
 }
diff --git a/runtime/mirror/var_handle.h b/runtime/mirror/var_handle.h
index 3747b3e..864a53b 100644
--- a/runtime/mirror/var_handle.h
+++ b/runtime/mirror/var_handle.h
@@ -218,7 +218,17 @@
               JValue* result)
       REQUIRES_SHARED(Locks::mutator_lock_);
 
-  ArtField* GetField() REQUIRES_SHARED(Locks::mutator_lock_);
+  template <VerifyObjectFlags kVerifyFlags = kDefaultVerifyFlags>
+  ArtField* GetArtField() REQUIRES_SHARED(Locks::mutator_lock_) {
+    return reinterpret_cast64<ArtField*>(GetField64<kVerifyFlags>(ArtFieldOffset()));
+  }
+
+  template <VerifyObjectFlags kVerifyFlags = kDefaultVerifyFlags>
+  void SetArtField(ArtField* art_field) REQUIRES_SHARED(Locks::mutator_lock_) {
+    SetField64</*kTransactionActive*/ false,
+               /*kCheckTransaction=*/ true,
+               kVerifyFlags>(ArtFieldOffset(), reinterpret_cast64<uint64_t>(art_field));
+  }
 
   // Used for updating var-handles to obsolete fields.
   void VisitTarget(ReflectiveValueVisitor* v) REQUIRES(Locks::mutator_lock_);
diff --git a/runtime/mirror/var_handle_test.cc b/runtime/mirror/var_handle_test.cc
index c32c702..9c1a2e7 100644
--- a/runtime/mirror/var_handle_test.cc
+++ b/runtime/mirror/var_handle_test.cc
@@ -285,7 +285,7 @@
   StackHandleScope<6> hs(self);
   Handle<mirror::FieldVarHandle> fvh(hs.NewHandle(CreateFieldVarHandle(self, value, mask)));
   EXPECT_FALSE(fvh.IsNull());
-  EXPECT_EQ(value, fvh->GetField());
+  EXPECT_EQ(value, fvh->GetArtField());
 
   // Check access modes
   EXPECT_TRUE(fvh->IsAccessModeSupported(VarHandle::AccessMode::kGet));
@@ -488,7 +488,7 @@
   StackHandleScope<6> hs(self);
   Handle<mirror::FieldVarHandle> fvh(hs.NewHandle(CreateFieldVarHandle(self, value, mask)));
   EXPECT_FALSE(fvh.IsNull());
-  EXPECT_EQ(value, fvh->GetField());
+  EXPECT_EQ(value, fvh->GetArtField());
 
   // Check access modes
   EXPECT_FALSE(fvh->IsAccessModeSupported(VarHandle::AccessMode::kGet));