Revert "Revert "Basic structural redefinition support""

This reverts commit 5a2301d897294ff4ee6de71f459dc2566dc3fa1a.

Bug: 134162467

Reason for revert: Relanding as unclear if issue is due to topic.

Change-Id: Ib1d1cf2e9132e30c9649b760ae9ae2d8ceacf843
diff --git a/runtime/mirror/class-refvisitor-inl.h b/runtime/mirror/class-refvisitor-inl.h
index 263b774..8c85387 100644
--- a/runtime/mirror/class-refvisitor-inl.h
+++ b/runtime/mirror/class-refvisitor-inl.h
@@ -53,20 +53,14 @@
 
 template<ReadBarrierOption kReadBarrierOption, class Visitor>
 void Class::VisitNativeRoots(Visitor& visitor, PointerSize pointer_size) {
-  for (ArtField& field : GetSFieldsUnchecked()) {
-    // Visit roots first in case the declaring class gets moved.
-    field.VisitRoots(visitor);
+  VisitFields<kReadBarrierOption>([&](ArtField* field) REQUIRES_SHARED(art::Locks::mutator_lock_) {
+    field->VisitRoots(visitor);
     if (kIsDebugBuild && IsResolved()) {
-      CHECK_EQ(field.GetDeclaringClass<kReadBarrierOption>(), this) << GetStatus();
+      CHECK_EQ(field->GetDeclaringClass<kReadBarrierOption>(), this)
+          << GetStatus() << field->GetDeclaringClass()->PrettyClass() << " != " << PrettyClass();
     }
-  }
-  for (ArtField& field : GetIFieldsUnchecked()) {
-    // Visit roots first in case the declaring class gets moved.
-    field.VisitRoots(visitor);
-    if (kIsDebugBuild && IsResolved()) {
-      CHECK_EQ(field.GetDeclaringClass<kReadBarrierOption>(), this) << GetStatus();
-    }
-  }
+  });
+  // Don't use VisitMethods because we don't want to hit the class-ext methods twice.
   for (ArtMethod& method : GetMethods(pointer_size)) {
     method.VisitRoots<kReadBarrierOption>(visitor, pointer_size);
   }
@@ -76,6 +70,27 @@
   }
 }
 
+template<ReadBarrierOption kReadBarrierOption, class Visitor>
+void Class::VisitMethods(Visitor visitor, PointerSize pointer_size) {
+  for (ArtMethod& method : GetMethods(pointer_size)) {
+    visitor(&method);
+  }
+  ObjPtr<ClassExt> ext(GetExtData<kDefaultVerifyFlags, kReadBarrierOption>());
+  if (!ext.IsNull()) {
+    ext->VisitMethods<kReadBarrierOption, Visitor>(visitor, pointer_size);
+  }
+}
+
+template<ReadBarrierOption kReadBarrierOption, class Visitor>
+void Class::VisitFields(Visitor visitor) {
+  for (ArtField& sfield : GetSFieldsUnchecked()) {
+    visitor(&sfield);
+  }
+  for (ArtField& ifield : GetIFieldsUnchecked()) {
+    visitor(&ifield);
+  }
+}
+
 }  // namespace mirror
 }  // namespace art
 
diff --git a/runtime/mirror/class.cc b/runtime/mirror/class.cc
index 7dff9df..455f98d 100644
--- a/runtime/mirror/class.cc
+++ b/runtime/mirror/class.cc
@@ -1539,6 +1539,12 @@
 
 std::string Class::PrettyClass() {
   std::string result;
+  if (IsObsoleteObject()) {
+    result += "(Obsolete)";
+  }
+  if (IsRetired()) {
+    result += "(Retired)";
+  }
   result += "java.lang.Class<";
   result += PrettyDescriptor();
   result += ">";
diff --git a/runtime/mirror/class.h b/runtime/mirror/class.h
index 960f49c..6ed20ed 100644
--- a/runtime/mirror/class.h
+++ b/runtime/mirror/class.h
@@ -313,6 +313,17 @@
     }
   }
 
+  bool IsObsoleteObject() REQUIRES_SHARED(Locks::mutator_lock_) {
+    return (GetAccessFlags() & kAccObsoleteObject) != 0;
+  }
+
+  void SetObsoleteObject() REQUIRES_SHARED(Locks::mutator_lock_) {
+    uint32_t flags = GetField32(OFFSET_OF_OBJECT_MEMBER(Class, access_flags_));
+    if ((flags & kAccObsoleteObject) == 0) {
+      SetAccessFlags(flags | kAccObsoleteObject);
+    }
+  }
+
   template<VerifyObjectFlags kVerifyFlags = kDefaultVerifyFlags>
   bool IsTypeOfReferenceClass() REQUIRES_SHARED(Locks::mutator_lock_) {
     return (GetClassFlags<kVerifyFlags>() & kClassFlagReference) != 0;
@@ -1110,6 +1121,15 @@
   void VisitNativeRoots(Visitor& visitor, PointerSize pointer_size)
       REQUIRES_SHARED(Locks::mutator_lock_);
 
+  // Visit ArtMethods directly owned by this class.
+  template<ReadBarrierOption kReadBarrierOption = kWithReadBarrier, class Visitor>
+  void VisitMethods(Visitor visitor, PointerSize pointer_size)
+      REQUIRES_SHARED(Locks::mutator_lock_);
+
+  // Visit ArtFields directly owned by this class.
+  template<ReadBarrierOption kReadBarrierOption = kWithReadBarrier, class Visitor>
+  void VisitFields(Visitor visitor) REQUIRES_SHARED(Locks::mutator_lock_);
+
   // Get one of the primitive classes.
   static ObjPtr<mirror::Class> GetPrimitiveClass(ObjPtr<mirror::String> name)
       REQUIRES_SHARED(Locks::mutator_lock_);
diff --git a/runtime/mirror/class_ext-inl.h b/runtime/mirror/class_ext-inl.h
index ead02ee..fd81a2a 100644
--- a/runtime/mirror/class_ext-inl.h
+++ b/runtime/mirror/class_ext-inl.h
@@ -21,8 +21,11 @@
 
 #include "array-inl.h"
 #include "art_method-inl.h"
+#include "base/enums.h"
 #include "handle_scope.h"
+#include "mirror/object.h"
 #include "object-inl.h"
+#include "verify_object.h"
 
 namespace art {
 namespace mirror {
@@ -89,6 +92,12 @@
 }
 
 template <VerifyObjectFlags kVerifyFlags, ReadBarrierOption kReadBarrierOption>
+inline ObjPtr<Class> ClassExt::GetObsoleteClass() {
+  return GetFieldObject<Class, kVerifyFlags, kReadBarrierOption>(
+      OFFSET_OF_OBJECT_MEMBER(ClassExt, obsolete_class_));
+}
+
+template <VerifyObjectFlags kVerifyFlags, ReadBarrierOption kReadBarrierOption>
 inline ObjPtr<PointerArray> ClassExt::GetJMethodIDs() {
   return GetFieldObject<PointerArray, kVerifyFlags, kReadBarrierOption>(
       OFFSET_OF_OBJECT_MEMBER(ClassExt, jmethod_ids_));
@@ -116,15 +125,58 @@
 
 template<ReadBarrierOption kReadBarrierOption, class Visitor>
 void ClassExt::VisitNativeRoots(Visitor& visitor, PointerSize pointer_size) {
+  VisitMethods<kReadBarrierOption>([&](ArtMethod* method) {
+    method->VisitRoots<kReadBarrierOption>(visitor, pointer_size);
+  }, pointer_size);
+}
+
+template<ReadBarrierOption kReadBarrierOption, class Visitor>
+void ClassExt::VisitMethods(Visitor visitor, PointerSize pointer_size) {
   ObjPtr<PointerArray> arr(GetObsoleteMethods<kDefaultVerifyFlags, kReadBarrierOption>());
-  if (arr.IsNull()) {
-    return;
+  if (!arr.IsNull()) {
+    int32_t len = arr->GetLength();
+    for (int32_t i = 0; i < len; i++) {
+      ArtMethod* method = arr->GetElementPtrSize<ArtMethod*>(i, pointer_size);
+      if (method != nullptr) {
+        visitor(method);
+      }
+    }
   }
-  int32_t len = arr->GetLength();
-  for (int32_t i = 0; i < len; i++) {
-    ArtMethod* method = arr->GetElementPtrSize<ArtMethod*, kDefaultVerifyFlags>(i, pointer_size);
-    if (method != nullptr) {
-      method->VisitRoots<kReadBarrierOption>(visitor, pointer_size);
+}
+
+template<ReadBarrierOption kReadBarrierOption, class Visitor>
+void ClassExt::VisitJMethodIDs(Visitor v) {
+  ObjPtr<PointerArray> marr(GetJMethodIDs<kDefaultVerifyFlags, kReadBarrierOption>());
+  if (!marr.IsNull()) {
+    int32_t len = marr->GetLength();
+    for (int32_t i = 0; i < len; i++) {
+      jmethodID id = marr->GetElementPtrSize<jmethodID>(i, kRuntimePointerSize);
+      if (id != nullptr) {
+        v(id, i);
+      }
+    }
+  }
+}
+template<ReadBarrierOption kReadBarrierOption, class Visitor>
+void ClassExt::VisitJFieldIDs(Visitor v) {
+  ObjPtr<PointerArray> sarr(GetStaticJFieldIDs<kDefaultVerifyFlags, kReadBarrierOption>());
+  if (!sarr.IsNull()) {
+    int32_t len = sarr->GetLength();
+    for (int32_t i = 0; i < len; i++) {
+      jfieldID id = sarr->GetElementPtrSize<jfieldID>(i, kRuntimePointerSize);
+      if (id != nullptr) {
+        v(id, i, true);
+      }
+    }
+  }
+  ObjPtr<PointerArray> iarr(GetInstanceJFieldIDs<kDefaultVerifyFlags, kReadBarrierOption>());
+  if (!iarr.IsNull()) {
+    int32_t len = iarr->GetLength();
+    for (int32_t i = 0; i < len; i++) {
+      jfieldID id = iarr->GetElementPtrSize<jfieldID>(i, kRuntimePointerSize);
+      if (id != nullptr) {
+        v(id, i, false);
+      }
     }
   }
 }
diff --git a/runtime/mirror/class_ext.cc b/runtime/mirror/class_ext.cc
index 4c6cb4d..27dcea8 100644
--- a/runtime/mirror/class_ext.cc
+++ b/runtime/mirror/class_ext.cc
@@ -25,6 +25,8 @@
 #include "class_root.h"
 #include "dex/dex_file-inl.h"
 #include "gc/accounting/card_table-inl.h"
+#include "mirror/object.h"
+#include "mirror/object_array.h"
 #include "object-inl.h"
 #include "object_array-alloc-inl.h"
 #include "object_array-inl.h"
@@ -101,6 +103,10 @@
   return true;
 }
 
+void ClassExt::SetObsoleteClass(ObjPtr<Class> klass) {
+  SetFieldObject<false>(OFFSET_OF_OBJECT_MEMBER(ClassExt, obsolete_class_), klass);
+}
+
 ObjPtr<ClassExt> ClassExt::Alloc(Thread* self) {
   return ObjPtr<ClassExt>::DownCast(GetClassRoot<ClassExt>()->AllocObject(self));
 }
diff --git a/runtime/mirror/class_ext.h b/runtime/mirror/class_ext.h
index 6fb225f..eb4047b 100644
--- a/runtime/mirror/class_ext.h
+++ b/runtime/mirror/class_ext.h
@@ -106,8 +106,26 @@
   inline void VisitNativeRoots(Visitor& visitor, PointerSize pointer_size)
       REQUIRES_SHARED(Locks::mutator_lock_);
 
+  template<ReadBarrierOption kReadBarrierOption = kWithReadBarrier, class Visitor>
+  inline void VisitMethods(Visitor visitor, PointerSize pointer_size)
+      REQUIRES_SHARED(Locks::mutator_lock_);
+
   static ObjPtr<ClassExt> Alloc(Thread* self) REQUIRES_SHARED(Locks::mutator_lock_);
 
+  // TODO Save the obsolete class, if we have one.
+  // TODO We need this so jit-cleanup can work. the obsolete class might get cleaned up early
+  // otherwise. We should remove the need for this.
+  template<VerifyObjectFlags kVerifyFlags = kDefaultVerifyFlags,
+           ReadBarrierOption kReadBarrierOption = kWithReadBarrier>
+  ObjPtr<Class> GetObsoleteClass() REQUIRES_SHARED(Locks::mutator_lock_);
+  void SetObsoleteClass(ObjPtr<Class> classes) REQUIRES_SHARED(Locks::mutator_lock_);
+
+  template<ReadBarrierOption kReadBarrierOption = kWithReadBarrier, typename Visitor>
+  inline void VisitJFieldIDs(Visitor v) REQUIRES_SHARED(Locks::mutator_lock_);
+
+  template<ReadBarrierOption kReadBarrierOption = kWithReadBarrier, typename Visitor>
+  inline void VisitJMethodIDs(Visitor v) REQUIRES_SHARED(Locks::mutator_lock_);
+
  private:
   template<VerifyObjectFlags kVerifyFlags = kDefaultVerifyFlags,
            ReadBarrierOption kReadBarrierOption = kWithReadBarrier>
@@ -123,6 +141,9 @@
   // the classes methods_ array or '0' if no id has been assigned to that method yet.
   HeapReference<PointerArray> jmethod_ids_;
 
+  // If set this is the Class object that was being used before a structural redefinition occurred.
+  HeapReference<Class> obsolete_class_;
+
   HeapReference<ObjectArray<DexCache>> obsolete_dex_caches_;
 
   HeapReference<PointerArray> obsolete_methods_;
@@ -137,8 +158,8 @@
   HeapReference<Object> verify_error_;
 
   // Native pointer to DexFile and ClassDef index of this class before it was JVMTI-redefined.
-  int32_t pre_redefine_class_def_index_;
   int64_t pre_redefine_dex_file_ptr_;
+  int32_t pre_redefine_class_def_index_;
 
   friend struct art::ClassExtOffsets;  // for verifying offset information
   DISALLOW_IMPLICIT_CONSTRUCTORS(ClassExt);
diff --git a/runtime/mirror/executable-inl.h b/runtime/mirror/executable-inl.h
index 6d4b46a..ce35d6e 100644
--- a/runtime/mirror/executable-inl.h
+++ b/runtime/mirror/executable-inl.h
@@ -20,6 +20,7 @@
 #include "executable.h"
 
 #include "object-inl.h"
+#include "verify_object.h"
 
 namespace art {
 namespace mirror {
@@ -36,6 +37,17 @@
   return GetFieldObject<mirror::Class>(DeclaringClassOffset());
 }
 
+template<typename Visitor, VerifyObjectFlags kVerifiyFlags>
+inline void Executable::VisitTarget(Visitor&& v) {
+  ArtMethod* orig = GetArtMethod<kVerifiyFlags>();
+  ArtMethod* new_target = v(orig);
+  if (orig != new_target) {
+    SetArtMethod(new_target);
+    SetDexMethodIndex(new_target->GetDexMethodIndex());
+    SetDeclaringClass(new_target->GetDeclaringClass());
+  }
+}
+
 }  // namespace mirror
 }  // namespace art
 
diff --git a/runtime/mirror/executable.h b/runtime/mirror/executable.h
index a99c3ec..8eca206 100644
--- a/runtime/mirror/executable.h
+++ b/runtime/mirror/executable.h
@@ -41,6 +41,10 @@
     return reinterpret_cast64<ArtMethod*>(GetField64<kVerifyFlags>(ArtMethodOffset()));
   }
 
+  template <typename Visitor,
+            VerifyObjectFlags kVerifyFlags = kDefaultVerifyFlags>
+  inline void VisitTarget(Visitor&& v) REQUIRES(Locks::mutator_lock_);
+
   template <bool kTransactionActive = false,
             bool kCheckTransaction = true,
             VerifyObjectFlags kVerifyFlags = kDefaultVerifyFlags>
@@ -61,6 +65,21 @@
   uint32_t access_flags_;
   uint32_t dex_method_index_;
 
+  template<bool kTransactionActive = false>
+  void SetDeclaringClass(ObjPtr<mirror::Class> klass) REQUIRES_SHARED(Locks::mutator_lock_) {
+    SetFieldObject<kTransactionActive>(DeclaringClassOffset(), klass);
+  }
+
+  template<bool kTransactionActive = false>
+  void SetAccessFlags(uint32_t flags) REQUIRES_SHARED(Locks::mutator_lock_) {
+    SetField32<kTransactionActive>(AccessFlagsOffset(), flags);
+  }
+
+  template<bool kTransactionActive = false>
+  void SetDexMethodIndex(uint32_t idx) REQUIRES_SHARED(Locks::mutator_lock_) {
+    SetField32<kTransactionActive>(DexMethodIndexOffset(), idx);
+  }
+
   static MemberOffset DeclaringClassOffset() {
     return MemberOffset(OFFSETOF_MEMBER(Executable, declaring_class_));
   }
diff --git a/runtime/mirror/field-inl.h b/runtime/mirror/field-inl.h
index ac11be1..6e82d6d 100644
--- a/runtime/mirror/field-inl.h
+++ b/runtime/mirror/field-inl.h
@@ -104,6 +104,18 @@
   SetFieldObject<kTransactionActive>(OFFSET_OF_OBJECT_MEMBER(Field, type_), type);
 }
 
+template<typename Visitor>
+inline void Field::VisitTarget(Visitor&& v) {
+  ArtField* orig = GetArtField(/*use_dex_cache*/false);
+  ArtField* new_value = v(orig);
+  if (orig != new_value) {
+    SetDexFieldIndex<false>(new_value->GetDexFieldIndex());
+    SetOffset<false>(new_value->GetOffset().Int32Value());
+    SetDeclaringClass<false>(new_value->GetDeclaringClass());
+  }
+  DCHECK_EQ(new_value, GetArtField(/*use_dex_cache*/false));
+}
+
 }  // namespace mirror
 }  // namespace art
 
diff --git a/runtime/mirror/field.cc b/runtime/mirror/field.cc
index f4d1e73..9a40006 100644
--- a/runtime/mirror/field.cc
+++ b/runtime/mirror/field.cc
@@ -24,7 +24,7 @@
 namespace art {
 namespace mirror {
 
-ArtField* Field::GetArtField() {
+ArtField* Field::GetArtField(bool use_dex_cache) {
   ObjPtr<mirror::Class> declaring_class = GetDeclaringClass();
   if (UNLIKELY(declaring_class->IsProxyClass())) {
     DCHECK(IsStatic());
@@ -38,7 +38,9 @@
     }
   }
   const ObjPtr<mirror::DexCache> dex_cache = declaring_class->GetDexCache();
-  ArtField* art_field = dex_cache->GetResolvedField(GetDexFieldIndex(), kRuntimePointerSize);
+  ArtField* art_field = use_dex_cache
+                            ? dex_cache->GetResolvedField(GetDexFieldIndex(), kRuntimePointerSize)
+                            : nullptr;
   if (UNLIKELY(art_field == nullptr)) {
     if (IsStatic()) {
       art_field = declaring_class->FindDeclaredStaticField(dex_cache, GetDexFieldIndex());
@@ -46,7 +48,9 @@
       art_field = declaring_class->FindInstanceField(dex_cache, GetDexFieldIndex());
     }
     CHECK(art_field != nullptr);
-    dex_cache->SetResolvedField(GetDexFieldIndex(), art_field, kRuntimePointerSize);
+    if (use_dex_cache) {
+      dex_cache->SetResolvedField(GetDexFieldIndex(), art_field, kRuntimePointerSize);
+    }
   }
   CHECK_EQ(declaring_class, art_field->GetDeclaringClass());
   return art_field;
diff --git a/runtime/mirror/field.h b/runtime/mirror/field.h
index 6ba8dc6..89c86e3 100644
--- a/runtime/mirror/field.h
+++ b/runtime/mirror/field.h
@@ -68,8 +68,10 @@
     return GetField32(OFFSET_OF_OBJECT_MEMBER(Field, offset_));
   }
 
-  // Slow, try to use only for PrettyField and such.
-  ArtField* GetArtField() REQUIRES_SHARED(Locks::mutator_lock_);
+  // Slow, try to use only for PrettyField and such. Set use-dex-cache to false to not utilize the
+  // dex-cache when finding the art-field. This is useful for cases where the dex-cache might be
+  // temporarally invalid.
+  ArtField* GetArtField(bool use_dex_cache = true) REQUIRES_SHARED(Locks::mutator_lock_);
 
   template <PointerSize kPointerSize, bool kTransactionActive = false>
   static ObjPtr<mirror::Field> CreateFromArtField(Thread* self,
@@ -77,6 +79,12 @@
                                                   bool force_resolve)
       REQUIRES_SHARED(Locks::mutator_lock_) REQUIRES(!Roles::uninterruptible_);
 
+
+  // Used to modify the target of this Field object, if required for structural redefinition or some
+  // other purpose.
+  template<typename Visitor>
+  inline void VisitTarget(Visitor&& v) REQUIRES(Locks::mutator_lock_);
+
  private:
   // Padding required for matching alignment with the Java peer.
   uint8_t padding_[2];
diff --git a/runtime/mirror/method_handle_impl-inl.h b/runtime/mirror/method_handle_impl-inl.h
index 932b434..0085642 100644
--- a/runtime/mirror/method_handle_impl-inl.h
+++ b/runtime/mirror/method_handle_impl-inl.h
@@ -39,6 +39,20 @@
       GetTargetMethod()->GetDeclaringClass() : GetTargetField()->GetDeclaringClass();
 }
 
+template<typename Visitor>
+inline void MethodHandle::VisitTarget(Visitor&& v) {
+  void* target = GetTargetField();
+  void* result;
+  if (GetHandleKind() < kFirstAccessorKind) {
+    result = v(GetTargetMethod());
+  } else {
+    result = v(GetTargetField());
+  }
+  if (result != target) {
+    SetField64<false>(ArtFieldOrMethodOffset(), reinterpret_cast<uintptr_t>(result));
+  }
+}
+
 }  // namespace mirror
 }  // namespace art
 
diff --git a/runtime/mirror/method_handle_impl.h b/runtime/mirror/method_handle_impl.h
index c973a24..357ec9d 100644
--- a/runtime/mirror/method_handle_impl.h
+++ b/runtime/mirror/method_handle_impl.h
@@ -87,6 +87,11 @@
   // supported.
   static const char* GetReturnTypeDescriptor(const char* invoke_method_name);
 
+  // Used when classes become structurally obsolete to change the MethodHandle to refer to the new
+  // method or field.
+  template<typename Visitor>
+  void VisitTarget(Visitor&& v) REQUIRES(Locks::mutator_lock_);
+
  protected:
   void Initialize(uintptr_t art_field_or_method, Kind kind, Handle<MethodType> method_type)
       REQUIRES_SHARED(Locks::mutator_lock_);
diff --git a/runtime/mirror/var_handle-inl.h b/runtime/mirror/var_handle-inl.h
new file mode 100644
index 0000000..d3f582d
--- /dev/null
+++ b/runtime/mirror/var_handle-inl.h
@@ -0,0 +1,40 @@
+/*
+ * Copyright (C) 2019 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_VAR_HANDLE_INL_H_
+#define ART_RUNTIME_MIRROR_VAR_HANDLE_INL_H_
+
+#include "var_handle.h"
+
+namespace art {
+class ArtField;
+
+namespace mirror {
+
+template<typename Visitor>
+inline void FieldVarHandle::VisitTarget(Visitor&& v) {
+  ArtField* orig = GetField();
+  ArtField* new_value = v(orig);
+  if (orig != new_value) {
+    SetField64</*kTransactionActive*/ false>(ArtFieldOffset(),
+                                             reinterpret_cast<uintptr_t>(new_value));
+  }
+}
+
+}  // namespace mirror
+}  // namespace art
+
+#endif  // ART_RUNTIME_MIRROR_VAR_HANDLE_INL_H_
diff --git a/runtime/mirror/var_handle.h b/runtime/mirror/var_handle.h
index a46b466..ac78d98 100644
--- a/runtime/mirror/var_handle.h
+++ b/runtime/mirror/var_handle.h
@@ -197,6 +197,10 @@
 
   ArtField* GetField() REQUIRES_SHARED(Locks::mutator_lock_);
 
+  // Used for updating var-handles to obsolete fields.
+  template<typename Visitor>
+  inline void VisitTarget(Visitor&& v) REQUIRES(Locks::mutator_lock_);
+
  private:
   static MemberOffset ArtFieldOffset() {
     return MemberOffset(OFFSETOF_MEMBER(FieldVarHandle, art_field_));