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/openjdkjvmti/ti_heap.cc b/openjdkjvmti/ti_heap.cc
index 81d1fc7..b0511a9 100644
--- a/openjdkjvmti/ti_heap.cc
+++ b/openjdkjvmti/ti_heap.cc
@@ -1618,11 +1618,10 @@
 
 namespace {
 
-using ArrayPtr = art::ObjPtr<art::mirror::Array>;
+using ObjectPtr = art::ObjPtr<art::mirror::Object>;
 
-static void ReplaceObjectReferences(ArrayPtr old_arr_ptr, ArrayPtr new_arr_ptr)
+static void ReplaceObjectReferences(ObjectPtr old_obj_ptr, ObjectPtr new_obj_ptr)
     REQUIRES(art::Locks::mutator_lock_,
-             art::Locks::user_code_suspension_lock_,
              art::Roles::uninterruptible_) {
   art::Runtime::Current()->GetHeap()->VisitObjectsPaused(
       [&](art::mirror::Object* ref) REQUIRES_SHARED(art::Locks::mutator_lock_) {
@@ -1630,21 +1629,31 @@
         class ResizeReferenceVisitor {
          public:
           using CompressedObj = art::mirror::CompressedReference<art::mirror::Object>;
-          ResizeReferenceVisitor(ArrayPtr old_arr, ArrayPtr new_arr)
-              : old_arr_(old_arr), new_arr_(new_arr) {}
+          ResizeReferenceVisitor(ObjectPtr old_arr, ObjectPtr new_arr)
+              : old_obj_(old_arr), new_obj_(new_arr) {}
 
-          // Ignore class roots. These do not need to be handled for arrays.
-          void VisitRootIfNonNull(CompressedObj* root ATTRIBUTE_UNUSED) const {}
-          void VisitRoot(CompressedObj* root ATTRIBUTE_UNUSED) const {}
+          // Ignore class roots.
+          void VisitRootIfNonNull(CompressedObj* root) const
+              REQUIRES_SHARED(art::Locks::mutator_lock_) {
+            if (root != nullptr) {
+              VisitRoot(root);
+            }
+          }
+          void VisitRoot(CompressedObj* root) const REQUIRES_SHARED(art::Locks::mutator_lock_) {
+            if (root->AsMirrorPtr() == old_obj_) {
+              root->Assign(new_obj_);
+              art::WriteBarrier::ForEveryFieldWrite(new_obj_);
+            }
+          }
 
           void operator()(art::ObjPtr<art::mirror::Object> obj,
                           art::MemberOffset off,
                           bool is_static ATTRIBUTE_UNUSED) const
               REQUIRES_SHARED(art::Locks::mutator_lock_) {
-            if (obj->GetFieldObject<art::mirror::Object>(off) == old_arr_) {
+            if (obj->GetFieldObject<art::mirror::Object>(off) == old_obj_) {
               LOG(DEBUG) << "Updating field at offset " << off.Uint32Value() << " of type "
                          << obj->GetClass()->PrettyClass();
-              obj->SetFieldObject</*transaction*/ false>(off, new_arr_);
+              obj->SetFieldObject</*transaction*/ false>(off, new_obj_);
             }
           }
 
@@ -1656,23 +1665,31 @@
           }
 
          private:
-          ArrayPtr old_arr_;
-          ArrayPtr new_arr_;
+          ObjectPtr old_obj_;
+          ObjectPtr new_obj_;
         };
 
-        ResizeReferenceVisitor rrv(old_arr_ptr, new_arr_ptr);
-        ref->VisitReferences(rrv, rrv);
+        ResizeReferenceVisitor rrv(old_obj_ptr, new_obj_ptr);
+        if (ref->IsClass()) {
+          // Class object native roots are the ArtField and ArtMethod 'declaring_class_' fields
+          // which we don't want to be messing with as it would break ref-visitor assumptions about
+          // what a class looks like. We want to keep the default behavior in other cases (such as
+          // dex-cache) though. Unfortunately there is no way to tell from the visitor where exactly
+          // the root came from.
+          // TODO It might be nice to have the visitors told where the reference came from.
+          ref->VisitReferences</*kVisitNativeRoots*/false>(rrv, rrv);
+        } else {
+          ref->VisitReferences</*kVisitNativeRoots*/true>(rrv, rrv);
+        }
       });
 }
 
-static void ReplaceStrongRoots(art::Thread* self, ArrayPtr old_arr_ptr, ArrayPtr new_arr_ptr)
-    REQUIRES(art::Locks::mutator_lock_,
-             art::Locks::user_code_suspension_lock_,
-             art::Roles::uninterruptible_) {
+static void ReplaceStrongRoots(art::Thread* self, ObjectPtr old_obj_ptr, ObjectPtr new_obj_ptr)
+    REQUIRES(art::Locks::mutator_lock_, art::Roles::uninterruptible_) {
   // replace root references expcept java frames.
   struct ResizeRootVisitor : public art::RootVisitor {
    public:
-    ResizeRootVisitor(ArrayPtr new_val, ArrayPtr old_val)
+    ResizeRootVisitor(ObjectPtr new_val, ObjectPtr old_val)
         : new_val_(new_val), old_val_(old_val) {}
 
     // TODO It's somewhat annoying to have to have this function implemented twice. It might be
@@ -1686,7 +1703,16 @@
           // Java frames might have the JIT doing optimizations (for example loop-unrolling or
           // eliding bounds checks) so we need deopt them once we're done here.
           if (info.GetType() == art::RootType::kRootJavaFrame) {
-            threads_with_roots_.insert(info.GetThreadId());
+            const art::JavaFrameRootInfo& jfri =
+                art::down_cast<const art::JavaFrameRootInfo&>(info);
+            if (jfri.GetVReg() == art::JavaFrameRootInfo::kMethodDeclaringClass) {
+              info.Describe(LOG_STREAM(INFO) << "Not changing declaring-class during stack walk. "
+                                                "Found obsolete java frame id ");
+              continue;
+            } else {
+              info.Describe(LOG_STREAM(INFO) << "Found java frame id ");
+              threads_with_roots_.insert(info.GetThreadId());
+            }
           }
           *obj = new_val_.Ptr();
         }
@@ -1703,7 +1729,16 @@
           // Java frames might have the JIT doing optimizations (for example loop-unrolling or
           // eliding bounds checks) so we need deopt them once we're done here.
           if (info.GetType() == art::RootType::kRootJavaFrame) {
-            threads_with_roots_.insert(info.GetThreadId());
+            const art::JavaFrameRootInfo& jfri =
+                art::down_cast<const art::JavaFrameRootInfo&>(info);
+            if (jfri.GetVReg() == art::JavaFrameRootInfo::kMethodDeclaringClass) {
+              info.Describe(LOG_STREAM(INFO) << "Not changing declaring-class during stack walk. "
+                                                "Found obsolete java frame id ");
+              continue;
+            } else {
+              info.Describe(LOG_STREAM(INFO) << "Found java frame id ");
+              threads_with_roots_.insert(info.GetThreadId());
+            }
           }
           obj->Assign(new_val_);
         }
@@ -1715,11 +1750,11 @@
     }
 
    private:
-    ArrayPtr new_val_;
-    ArrayPtr old_val_;
+    ObjectPtr new_val_;
+    ObjectPtr old_val_;
     std::unordered_set<uint32_t> threads_with_roots_;
   };
-  ResizeRootVisitor rrv(new_arr_ptr, old_arr_ptr);
+  ResizeRootVisitor rrv(new_obj_ptr, old_obj_ptr);
   art::Runtime::Current()->VisitRoots(&rrv, art::VisitRootFlags::kVisitRootFlagAllRoots);
   // Handle java Frames. Annoyingly the JIT can embed information about the length of the array into
   // the compiled code. By changing the length of the array we potentially invalidate these
@@ -1732,6 +1767,7 @@
       art::Thread* t = thread_list->FindThreadByThreadId(id);
       CHECK(t != nullptr) << "id " << id << " does not refer to a valid thread."
                           << " Where did the roots come from?";
+      LOG(DEBUG) << "Instrumenting thread stack of thread " << *t;
       // TODO Use deopt manager. We need a version that doesn't acquire all the locks we
       // already have.
       // TODO We technically only need to do this if the frames are not already being interpreted.
@@ -1743,11 +1779,9 @@
 
 static void ReplaceWeakRoots(art::Thread* self,
                              EventHandler* event_handler,
-                             ArrayPtr old_arr_ptr,
-                             ArrayPtr new_arr_ptr)
-    REQUIRES(art::Locks::mutator_lock_,
-             art::Locks::user_code_suspension_lock_,
-             art::Roles::uninterruptible_) {
+                             ObjectPtr old_obj_ptr,
+                             ObjectPtr new_obj_ptr)
+    REQUIRES(art::Locks::mutator_lock_, art::Roles::uninterruptible_) {
   // Handle tags. We want to do this seprately from other weak-refs (handled below) because we need
   // to send additional events and handle cases where the agent might have tagged the new
   // replacement object during the VMObjectAlloc. We do this by removing all tags associated with
@@ -1767,8 +1801,8 @@
     // Get the tags and clear them (so we don't need to special-case the normal weak-ref visitor)
     jlong new_tag = 0;
     jlong obsolete_tag = 0;
-    bool had_new_tag = env->object_tag_table->RemoveLocked(new_arr_ptr, &new_tag);
-    bool had_obsolete_tag = env->object_tag_table->RemoveLocked(old_arr_ptr, &obsolete_tag);
+    bool had_new_tag = env->object_tag_table->RemoveLocked(new_obj_ptr, &new_tag);
+    bool had_obsolete_tag = env->object_tag_table->RemoveLocked(old_obj_ptr, &obsolete_tag);
     // Dispatch event.
     if (had_obsolete_tag || had_new_tag) {
       event_handler->DispatchEventOnEnv<ArtJvmtiEvent::kObsoleteObjectCreated>(env,
@@ -1779,60 +1813,56 @@
       non_obsolete_tags[env] = new_tag;
     }
     // After weak-ref update we need to go back and re-add obsoletes. We wait to avoid having to
-    // deal with the visit-weaks overwriting the initial new_arr_ptr tag and generally making things
+    // deal with the visit-weaks overwriting the initial new_obj_ptr tag and generally making things
     // difficult.
     env->object_tag_table->Unlock();
   });
   // Handle weak-refs.
   struct ReplaceWeaksVisitor : public art::IsMarkedVisitor {
    public:
-    ReplaceWeaksVisitor(ArrayPtr old_arr, ArrayPtr new_arr)
-        : old_arr_(old_arr), new_arr_(new_arr) {}
+    ReplaceWeaksVisitor(ObjectPtr old_obj, ObjectPtr new_obj)
+        : old_obj_(old_obj), new_obj_(new_obj) {}
 
     art::mirror::Object* IsMarked(art::mirror::Object* obj)
         REQUIRES_SHARED(art::Locks::mutator_lock_) {
-      if (obj == old_arr_) {
-        return new_arr_.Ptr();
+      if (obj == old_obj_) {
+        return new_obj_.Ptr();
       } else {
         return obj;
       }
     }
 
    private:
-    ArrayPtr old_arr_;
-    ArrayPtr new_arr_;
+    ObjectPtr old_obj_;
+    ObjectPtr new_obj_;
   };
-  ReplaceWeaksVisitor rwv(old_arr_ptr, new_arr_ptr);
+  ReplaceWeaksVisitor rwv(old_obj_ptr, new_obj_ptr);
   art::Runtime::Current()->SweepSystemWeaks(&rwv);
-  // Re-add the object tags. At this point all weak-references to the old_arr_ptr are gone.
+  // Re-add the object tags. At this point all weak-references to the old_obj_ptr are gone.
   event_handler->ForEachEnv(self, [&](ArtJvmTiEnv* env) {
     // Cannot have REQUIRES(art::Locks::mutator_lock_) since ForEachEnv doesn't require it.
     art::Locks::mutator_lock_->AssertExclusiveHeld(self);
     env->object_tag_table->Lock();
     if (obsolete_tags.find(env) != obsolete_tags.end()) {
-      env->object_tag_table->SetLocked(old_arr_ptr, obsolete_tags[env]);
+      env->object_tag_table->SetLocked(old_obj_ptr, obsolete_tags[env]);
     }
     if (non_obsolete_tags.find(env) != non_obsolete_tags.end()) {
-      env->object_tag_table->SetLocked(new_arr_ptr, non_obsolete_tags[env]);
+      env->object_tag_table->SetLocked(new_obj_ptr, non_obsolete_tags[env]);
     }
     env->object_tag_table->Unlock();
   });
 }
 
-static void PerformArrayReferenceReplacement(art::Thread* self,
-                                             EventHandler* event_handler,
-                                             ArrayPtr old_arr_ptr,
-                                             ArrayPtr new_arr_ptr)
-    REQUIRES(art::Locks::mutator_lock_,
-             art::Locks::user_code_suspension_lock_,
-             art::Roles::uninterruptible_) {
-  ReplaceObjectReferences(old_arr_ptr, new_arr_ptr);
-  ReplaceStrongRoots(self, old_arr_ptr, new_arr_ptr);
-  ReplaceWeakRoots(self, event_handler, old_arr_ptr, new_arr_ptr);
-}
-
 }  // namespace
 
+void HeapExtensions::ReplaceReference(art::Thread* self,
+                                      art::ObjPtr<art::mirror::Object> old_obj_ptr,
+                                      art::ObjPtr<art::mirror::Object> new_obj_ptr) {
+  ReplaceObjectReferences(old_obj_ptr, new_obj_ptr);
+  ReplaceStrongRoots(self, old_obj_ptr, new_obj_ptr);
+  ReplaceWeakRoots(self, HeapExtensions::gEventHandler, old_obj_ptr, new_obj_ptr);
+}
+
 jvmtiError HeapExtensions::ChangeArraySize(jvmtiEnv* env, jobject arr, jsize new_size) {
   if (ArtJvmTiEnv::AsArtJvmTiEnv(env)->capabilities.can_tag_objects != 1) {
     return ERR(MUST_POSSESS_CAPABILITY);
@@ -1921,7 +1951,7 @@
       UNREACHABLE();
   }
   // Actually replace all the pointers.
-  PerformArrayReferenceReplacement(self, gEventHandler, old_arr.Get(), new_arr.Get());
+  ReplaceReference(self, old_arr.Get(), new_arr.Get());
   return OK;
 }