Do read barriers on native roots in CopyClassVisitor

Fixes a race condition caused by making a copy of a class then
clearing the native root arrays of the original class. If the
original class was gray and the new class was black then the GC
would miss the native roots.

Bug: 22957957

Change-Id: I706110018220af12a2ad0d72eb803f1cfe3580b9
diff --git a/runtime/mirror/class.cc b/runtime/mirror/class.cc
index 701ba4a..6af90bb 100644
--- a/runtime/mirror/class.cc
+++ b/runtime/mirror/class.cc
@@ -824,6 +824,34 @@
   }
 }
 
+class ReadBarrierOnNativeRootsVisitor {
+ public:
+  void operator()(mirror::Object* obj ATTRIBUTE_UNUSED,
+                  MemberOffset offset ATTRIBUTE_UNUSED,
+                  bool is_static ATTRIBUTE_UNUSED) const {}
+
+  void VisitRootIfNonNull(mirror::CompressedReference<mirror::Object>* root) const
+      SHARED_REQUIRES(Locks::mutator_lock_) {
+    if (!root->IsNull()) {
+      VisitRoot(root);
+    }
+  }
+
+  void VisitRoot(mirror::CompressedReference<mirror::Object>* root) const
+      SHARED_REQUIRES(Locks::mutator_lock_) {
+    mirror::Object* old_ref = root->AsMirrorPtr();
+    mirror::Object* new_ref = ReadBarrier::BarrierForRoot(root);
+    if (old_ref != new_ref) {
+      // Update the field atomically. This may fail if mutator updates before us, but it's ok.
+      auto* atomic_root =
+          reinterpret_cast<Atomic<mirror::CompressedReference<mirror::Object>>*>(root);
+      atomic_root->CompareExchangeStrongSequentiallyConsistent(
+          mirror::CompressedReference<mirror::Object>::FromMirrorPtr(old_ref),
+          mirror::CompressedReference<mirror::Object>::FromMirrorPtr(new_ref));
+    }
+  }
+};
+
 // The pre-fence visitor for Class::CopyOf().
 class CopyClassVisitor {
  public:
@@ -842,6 +870,10 @@
     mirror::Class::SetStatus(h_new_class_obj, Class::kStatusResolving, self_);
     h_new_class_obj->PopulateEmbeddedImtAndVTable(imt_, pointer_size_);
     h_new_class_obj->SetClassSize(new_length_);
+    // Visit all of the references to make sure there is no from space references in the native
+    // roots.
+    h_new_class_obj->VisitReferences<true>(h_new_class_obj->GetClass(),
+                                           ReadBarrierOnNativeRootsVisitor());
   }
 
  private: