Avoid updating class loaders outside system weaks

We update all system weaks using Runtime::SweepSystemWeaks(). But when
we are tracing, we attempt to update them again via
ClassLinker::VisitRoots, which results in double updation of GC-root.
This is not tolerated by userfaultfd-GC as we do in-place sliding
compaction.

Bug: 250480435
Test: art/test/testrunner/testrunner.py --host --gcstres -t
2240-tracing-non-invokable-method

Change-Id: I970f2d47270837f7b02f34d34ae434ba8a4edd2b
diff --git a/runtime/class_linker.cc b/runtime/class_linker.cc
index f487e56..67a20a8 100644
--- a/runtime/class_linker.cc
+++ b/runtime/class_linker.cc
@@ -2146,9 +2146,18 @@
     boot_class_table_->VisitRoots(root_visitor);
     // If tracing is enabled, then mark all the class loaders to prevent unloading.
     if ((flags & kVisitRootFlagClassLoader) != 0 || tracing_enabled) {
-      for (const ClassLoaderData& data : class_loaders_) {
-        GcRoot<mirror::Object> root(GcRoot<mirror::Object>(self->DecodeJObject(data.weak_root)));
-        root.VisitRoot(visitor, RootInfo(kRootVMInternal));
+      gc::Heap* const heap = Runtime::Current()->GetHeap();
+      // Don't visit class-loaders if compacting with userfaultfd GC as these
+      // weaks are updated using Runtime::SweepSystemWeaks() and the GC doesn't
+      // tolerate double updates.
+      if (!gUseUserfaultfd
+          || !heap->MarkCompactCollector()->IsCompacting(self)) {
+        for (const ClassLoaderData& data : class_loaders_) {
+          GcRoot<mirror::Object> root(GcRoot<mirror::Object>(self->DecodeJObject(data.weak_root)));
+          root.VisitRoot(visitor, RootInfo(kRootVMInternal));
+        }
+      } else {
+        DCHECK_EQ(heap->CurrentCollectorType(), gc::CollectorType::kCollectorTypeCMC);
       }
     }
   } else if (!gUseReadBarrier && (flags & kVisitRootFlagNewRoots) != 0) {