Improve GSS reference processing.

Support the case where the reference object is in the free list space
and the referent object is in the bump pointer space at a bump pointer
space collection.

Bug: 11650816
Change-Id: If98b08edc9e37351c74ee07cb3f2d30c2b4d0056
diff --git a/runtime/gc/accounting/remembered_set.cc b/runtime/gc/accounting/remembered_set.cc
index 044216e..bbbd1ed 100644
--- a/runtime/gc/accounting/remembered_set.cc
+++ b/runtime/gc/accounting/remembered_set.cc
@@ -61,9 +61,10 @@
 class RememberedSetReferenceVisitor {
  public:
   RememberedSetReferenceVisitor(MarkHeapReferenceCallback* callback,
+                                DelayReferenceReferentCallback* ref_callback,
                                 space::ContinuousSpace* target_space,
                                 bool* const contains_reference_to_target_space, void* arg)
-      : callback_(callback), target_space_(target_space), arg_(arg),
+      : callback_(callback), ref_callback_(ref_callback), target_space_(target_space), arg_(arg),
         contains_reference_to_target_space_(contains_reference_to_target_space) {}
 
   void operator()(mirror::Object* obj, MemberOffset offset, bool /* is_static */) const
@@ -77,8 +78,18 @@
     }
   }
 
+  void operator()(mirror::Class* klass, mirror::Reference* ref) const
+      SHARED_LOCKS_REQUIRED(Locks::mutator_lock_)
+      EXCLUSIVE_LOCKS_REQUIRED(Locks::heap_bitmap_lock_) {
+    if (target_space_->HasAddress(ref->GetReferent())) {
+      *contains_reference_to_target_space_ = true;
+      ref_callback_(klass, ref, arg_);
+    }
+  }
+
  private:
   MarkHeapReferenceCallback* const callback_;
+  DelayReferenceReferentCallback* const ref_callback_;
   space::ContinuousSpace* const target_space_;
   void* const arg_;
   bool* const contains_reference_to_target_space_;
@@ -87,30 +98,33 @@
 class RememberedSetObjectVisitor {
  public:
   RememberedSetObjectVisitor(MarkHeapReferenceCallback* callback,
+                             DelayReferenceReferentCallback* ref_callback,
                              space::ContinuousSpace* target_space,
                              bool* const contains_reference_to_target_space, void* arg)
-      : callback_(callback), target_space_(target_space), arg_(arg),
+      : callback_(callback), ref_callback_(ref_callback), target_space_(target_space), arg_(arg),
         contains_reference_to_target_space_(contains_reference_to_target_space) {}
 
   void operator()(mirror::Object* obj) const EXCLUSIVE_LOCKS_REQUIRED(Locks::heap_bitmap_lock_)
       SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
-    RememberedSetReferenceVisitor ref_visitor(callback_, target_space_,
-                                              contains_reference_to_target_space_, arg_);
-    obj->VisitReferences<kMovingClasses>(ref_visitor);
+    RememberedSetReferenceVisitor visitor(callback_, ref_callback_, target_space_,
+                                          contains_reference_to_target_space_, arg_);
+    obj->VisitReferences<kMovingClasses>(visitor, visitor);
   }
 
  private:
   MarkHeapReferenceCallback* const callback_;
+  DelayReferenceReferentCallback* const ref_callback_;
   space::ContinuousSpace* const target_space_;
   void* const arg_;
   bool* const contains_reference_to_target_space_;
 };
 
 void RememberedSet::UpdateAndMarkReferences(MarkHeapReferenceCallback* callback,
+                                            DelayReferenceReferentCallback* ref_callback,
                                             space::ContinuousSpace* target_space, void* arg) {
   CardTable* card_table = heap_->GetCardTable();
   bool contains_reference_to_target_space = false;
-  RememberedSetObjectVisitor obj_visitor(callback, target_space,
+  RememberedSetObjectVisitor obj_visitor(callback, ref_callback, target_space,
                                          &contains_reference_to_target_space, arg);
   ContinuousSpaceBitmap* bitmap = space_->GetLiveBitmap();
   CardSet remove_card_set;
diff --git a/runtime/gc/accounting/remembered_set.h b/runtime/gc/accounting/remembered_set.h
index 4ed20dd..e3d8537 100644
--- a/runtime/gc/accounting/remembered_set.h
+++ b/runtime/gc/accounting/remembered_set.h
@@ -53,6 +53,7 @@
 
   // Mark through all references to the target space.
   void UpdateAndMarkReferences(MarkHeapReferenceCallback* callback,
+                               DelayReferenceReferentCallback* ref_callback,
                                space::ContinuousSpace* target_space, void* arg)
       EXCLUSIVE_LOCKS_REQUIRED(Locks::heap_bitmap_lock_)
       SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
diff --git a/runtime/gc/collector/semi_space.cc b/runtime/gc/collector/semi_space.cc
index b67bbb1..0413439 100644
--- a/runtime/gc/collector/semi_space.cc
+++ b/runtime/gc/collector/semi_space.cc
@@ -334,7 +334,8 @@
       accounting::RememberedSet* rem_set = heap_->FindRememberedSetFromSpace(space);
       if (kUseRememberedSet) {
         DCHECK(rem_set != nullptr);
-        rem_set->UpdateAndMarkReferences(MarkHeapReferenceCallback, from_space_, this);
+        rem_set->UpdateAndMarkReferences(MarkHeapReferenceCallback, DelayReferenceReferentCallback,
+                                         from_space_, this);
         if (kIsDebugBuild) {
           // Verify that there are no from-space references that
           // remain in the space, that is, the remembered set (and the
@@ -603,6 +604,11 @@
   reinterpret_cast<SemiSpace*>(arg)->MarkObject(obj_ptr);
 }
 
+void SemiSpace::DelayReferenceReferentCallback(mirror::Class* klass, mirror::Reference* ref,
+                                               void* arg) {
+  reinterpret_cast<SemiSpace*>(arg)->DelayReferenceReferent(klass, ref);
+}
+
 void SemiSpace::MarkRootCallback(Object** root, void* arg, uint32_t /*thread_id*/,
                                  RootType /*root_type*/) {
   auto ref = StackReference<mirror::Object>::FromMirrorPtr(*root);
diff --git a/runtime/gc/collector/semi_space.h b/runtime/gc/collector/semi_space.h
index 3d635f0..51b0869 100644
--- a/runtime/gc/collector/semi_space.h
+++ b/runtime/gc/collector/semi_space.h
@@ -138,6 +138,10 @@
   static void ProcessMarkStackCallback(void* arg)
       EXCLUSIVE_LOCKS_REQUIRED(Locks::mutator_lock_, Locks::heap_bitmap_lock_);
 
+  static void DelayReferenceReferentCallback(mirror::Class* klass, mirror::Reference* ref,
+                                             void* arg)
+      SHARED_LOCKS_REQUIRED(Locks::heap_bitmap_lock_, Locks::mutator_lock_);
+
   virtual mirror::Object* MarkNonForwardedObject(mirror::Object* obj)
       EXCLUSIVE_LOCKS_REQUIRED(Locks::heap_bitmap_lock_)
       SHARED_LOCKS_REQUIRED(Locks::mutator_lock_);
diff --git a/runtime/object_callbacks.h b/runtime/object_callbacks.h
index 9198c90..767c197 100644
--- a/runtime/object_callbacks.h
+++ b/runtime/object_callbacks.h
@@ -24,8 +24,10 @@
 
 namespace art {
 namespace mirror {
+class Class;
 class Object;
 template<class MirrorType> class HeapReference;
+class Reference;
 }  // namespace mirror
 class StackVisitor;
 
@@ -59,6 +61,7 @@
     const StackVisitor* visitor, RootType root_type);
 
 typedef void (MarkHeapReferenceCallback)(mirror::HeapReference<mirror::Object>* ref, void* arg);
+typedef void (DelayReferenceReferentCallback)(mirror::Class* klass, mirror::Reference* ref, void* arg);
 
 // A callback for testing if an object is marked, returns nullptr if not marked, otherwise the new
 // address the object (if the object didn't move, returns the object input parameter).