Fixed issue in structural redefinition around class init

On non-x86 ISAs class initialization is two stage with a class first
being 'kInitialized' and later being 'kVisiblyInitialized'. This has
to do with the memory model of non-x86 ISAs. Because we did not follow
this process correctly we could hit check-failures on non-x86 targets
if the redefined class was not fully initialized when being redefined.

To fix this we force the class-linker to bring the initialization
state of the newly created class all the way to visibly initialized
before allowing the redefinition to take place.

Test: ./test.py --target
Bug: 134162467
Bug: 141236848
Change-Id: I466861270b957a0fe6a90bda0bdabece950f99b2
diff --git a/openjdkjvmti/ti_redefine.cc b/openjdkjvmti/ti_redefine.cc
index af16b4e..97cf98b 100644
--- a/openjdkjvmti/ti_redefine.cc
+++ b/openjdkjvmti/ti_redefine.cc
@@ -422,6 +422,26 @@
   }
 
   if (kType == RedefinitionType::kStructural) {
+    // Class initialization interacts really badly with structural redefinition since we need to
+    // make the old class obsolete. We currently just blanket don't allow it.
+    // TODO It might be nice to allow this at some point.
+    if (klass->IsInitializing() &&
+       !klass->IsInitialized() &&
+        klass->GetClinitThreadId() == self->GetTid()) {
+      // We are in the class-init running on this thread.
+      *error_msg = "Modification of class " + klass->PrettyClass() + " during class" +
+                   " initialization is not allowed.";
+      return ERR(INTERNAL);
+    }
+    if (!art::Runtime::Current()->GetClassLinker()->EnsureInitialized(
+            self, klass, /*can_init_fields=*/true, /*can_init_parents=*/true)) {
+      self->AssertPendingException();
+      *error_msg = "Class " + klass->PrettyClass() + " failed initialization. Structural" +
+                   " redefinition of erroneous classes is not allowed. Failure was: " +
+                   self->GetException()->Dump();
+      self->ClearException();
+      return ERR(INVALID_CLASS);
+    }
     art::StackHandleScope<2> hs(self);
     art::Handle<art::mirror::ObjectArray<art::mirror::Class>> roots(
         hs.NewHandle(art::Runtime::Current()->GetClassLinker()->GetClassRoots()));
@@ -1676,7 +1696,11 @@
   art::ObjectLock<art::mirror::Class> objlock(driver_->self_, linked_class);
   // We already verified the class earlier. No need to do it again.
   linked_class->SetVerificationAttempted();
-  linked_class->SetStatus(linked_class, art::ClassStatus::kVisiblyInitialized, driver_->self_);
+  // Mark the class as initialized.
+  CHECK(old_class->IsInitialized())
+      << "Attempting to redefine an uninitalized class " << old_class->PrettyClass()
+      << " status=" << old_class->GetStatus();
+  linker->ForceClassInitialized(driver_->self_, linked_class);
   // Make sure we have ext-data space for method & field ids. We won't know if we need them until
   // it's too late to create them.
   // TODO We might want to remove these arrays if they're not needed.
diff --git a/runtime/class_linker.cc b/runtime/class_linker.cc
index 10b9da1..93fb8a3 100644
--- a/runtime/class_linker.cc
+++ b/runtime/class_linker.cc
@@ -387,6 +387,15 @@
   }
 }
 
+void ClassLinker::ForceClassInitialized(Thread* self, Handle<mirror::Class> klass) {
+  ClassLinker::VisiblyInitializedCallback* cb = MarkClassInitialized(self, klass);
+  if (cb != nullptr) {
+    cb->MakeVisible(self);
+  }
+  ScopedThreadSuspension sts(self, ThreadState::kSuspended);
+  MakeInitializedClassesVisiblyInitialized(self, /*wait=*/true);
+}
+
 ClassLinker::VisiblyInitializedCallback* ClassLinker::MarkClassInitialized(
     Thread* self, Handle<mirror::Class> klass) {
   if (kRuntimeISA == InstructionSet::kX86 || kRuntimeISA == InstructionSet::kX86_64) {
diff --git a/runtime/class_linker.h b/runtime/class_linker.h
index 792f7b7..a1ba461 100644
--- a/runtime/class_linker.h
+++ b/runtime/class_linker.h
@@ -781,6 +781,12 @@
     ClassTable* class_table;
   };
 
+  // Forces a class to be marked as initialized without actually running initializers. Should only
+  // be used by plugin code when creating new classes directly.
+  void ForceClassInitialized(Thread* self, Handle<mirror::Class> klass)
+      REQUIRES_SHARED(Locks::mutator_lock_)
+      REQUIRES(!Locks::dex_lock_, !Roles::uninterruptible_);
+
  protected:
   virtual bool InitializeClass(Thread* self,
                                Handle<mirror::Class> klass,