Always mark zygote large objects for CC

Prevent needing to gray holders of zygote large objects.
System wide zygote space PSS after boot:
12644 kB -> 5571 kB for CC.

Also PSS reduction in zygote large objects themselves since their
gray bit would have been set each GC.
Overall LOS savings hard to measure, could be up to 316 * 4KB per
app since there are 316 zygote large objects.

Also clear mod-union tables for image spaces to prevent dirty
image pages if any of the image spaces point to zygote large objects.
System wide .art mmap: 37432 kB -> 34372 kB

System server before (N6P):
LOS shared dirty: 12888 kB
Zygote space shared dirty: 700 kB
Zygote space private dirty: 868 kB
.art private dirty: 1696 kB

After:
LOS shared dirty 13672 kB
Zygote space shared dirty: 1072 kB
Zygote space private dirty: 496 kB
.art private dirty: 1432 kB

Bug: 29516968

Test: test-art-host with baker CC, debug N6P phone booting

Change-Id: Ia37ce2c11217cf56885bd1d1dc084332fcbb7843
diff --git a/runtime/gc/accounting/mod_union_table.cc b/runtime/gc/accounting/mod_union_table.cc
index 4e83913..35bcb18 100644
--- a/runtime/gc/accounting/mod_union_table.cc
+++ b/runtime/gc/accounting/mod_union_table.cc
@@ -175,6 +175,11 @@
   card_table->ModifyCardsAtomic(space_->Begin(), space_->End(), AgeCardVisitor(), visitor);
 }
 
+void ModUnionTableReferenceCache::ClearTable() {
+  cleared_cards_.clear();
+  references_.clear();
+}
+
 class AddToReferenceArrayVisitor {
  public:
   AddToReferenceArrayVisitor(ModUnionTableReferenceCache* mod_union_table,
@@ -526,6 +531,10 @@
   card_table->ModifyCardsAtomic(space_->Begin(), space_->End(), AgeCardVisitor(), visitor);
 }
 
+void ModUnionTableCardCache::ClearTable() {
+  card_bitmap_->Bitmap::Clear();
+}
+
 // Mark all references to the alloc space(s).
 void ModUnionTableCardCache::UpdateAndMarkReferences(MarkObjectVisitor* visitor) {
   // TODO: Needs better support for multi-images? b/26317072
diff --git a/runtime/gc/accounting/mod_union_table.h b/runtime/gc/accounting/mod_union_table.h
index bf665c5..6aa2417 100644
--- a/runtime/gc/accounting/mod_union_table.h
+++ b/runtime/gc/accounting/mod_union_table.h
@@ -63,6 +63,9 @@
   // Set all the cards.
   virtual void SetCards() = 0;
 
+  // Clear all of the table.
+  virtual void ClearTable() = 0;
+
   // Update the mod-union table using data stored by ClearCards. There may be multiple ClearCards
   // before a call to update, for example, back-to-back sticky GCs. Also mark references to other
   // spaces which are stored in the mod-union table.
@@ -140,6 +143,8 @@
 
   virtual void SetCards() OVERRIDE;
 
+  virtual void ClearTable() OVERRIDE;
+
  protected:
   // Cleared card array, used to update the mod-union table.
   ModUnionTable::CardSet cleared_cards_;
@@ -177,9 +182,10 @@
 
   virtual bool ContainsCardFor(uintptr_t addr) OVERRIDE;
 
-  // Sets all the cards in the mod union table to be marked.
   virtual void SetCards() OVERRIDE;
 
+  virtual void ClearTable() OVERRIDE;
+
  protected:
   // Cleared card bitmap, used to update the mod-union table.
   std::unique_ptr<CardBitmap> card_bitmap_;
diff --git a/runtime/gc/collector/concurrent_copying.cc b/runtime/gc/collector/concurrent_copying.cc
index 071537d..70faf4b 100644
--- a/runtime/gc/collector/concurrent_copying.cc
+++ b/runtime/gc/collector/concurrent_copying.cc
@@ -228,6 +228,8 @@
     }
     LOG(INFO) << "GC end of InitializePhase";
   }
+  // Mark all of the zygote large objects without graying them.
+  MarkZygoteLargeObjects();
 }
 
 // Used to switch the thread roots of a thread from from-space refs to to-space refs.
@@ -385,10 +387,18 @@
   void CheckReference(mirror::Object* ref, mirror::Object* holder, MemberOffset offset) const
       SHARED_REQUIRES(Locks::mutator_lock_) {
     if (ref != nullptr) {
-      CHECK(collector_->immune_spaces_.ContainsObject(ref))
-          << "Non gray object references non immune object "<< ref << " " << PrettyTypeOf(ref)
-          << " in holder " << holder << " " << PrettyTypeOf(holder) << " offset="
-          << offset.Uint32Value();
+      if (!collector_->immune_spaces_.ContainsObject(ref)) {
+        // Not immune, must be a zygote large object.
+        CHECK(Runtime::Current()->GetHeap()->GetLargeObjectsSpace()->IsZygoteLargeObject(
+            Thread::Current(), ref))
+            << "Non gray object references non immune, non zygote large object "<< ref << " "
+            << PrettyTypeOf(ref) << " in holder " << holder << " " << PrettyTypeOf(holder)
+            << " offset=" << offset.Uint32Value();
+      } else {
+        // Make sure the large object class is immune since we will never scan the large object.
+        CHECK(collector_->immune_spaces_.ContainsObject(
+            ref->GetClass<kVerifyNone, kWithoutReadBarrier>()));
+      }
     }
   }
 };
@@ -1440,6 +1450,26 @@
   SweepLargeObjects(swap_bitmaps);
 }
 
+void ConcurrentCopying::MarkZygoteLargeObjects() {
+  TimingLogger::ScopedTiming split(__FUNCTION__, GetTimings());
+  Thread* const self = Thread::Current();
+  WriterMutexLock rmu(self, *Locks::heap_bitmap_lock_);
+  space::LargeObjectSpace* const los = heap_->GetLargeObjectsSpace();
+  // Pick the current live bitmap (mark bitmap if swapped).
+  accounting::LargeObjectBitmap* const live_bitmap = los->GetLiveBitmap();
+  accounting::LargeObjectBitmap* const mark_bitmap = los->GetMarkBitmap();
+  // Walk through all of the objects and explicitly mark the zygote ones so they don't get swept.
+  live_bitmap->VisitMarkedRange(reinterpret_cast<uintptr_t>(los->Begin()),
+                                reinterpret_cast<uintptr_t>(los->End()),
+                                [mark_bitmap, los, self](mirror::Object* obj)
+      REQUIRES(Locks::heap_bitmap_lock_)
+      SHARED_REQUIRES(Locks::mutator_lock_) {
+    if (los->IsZygoteLargeObject(self, obj)) {
+      mark_bitmap->Set(obj);
+    }
+  });
+}
+
 void ConcurrentCopying::SweepLargeObjects(bool swap_bitmaps) {
   TimingLogger::ScopedTiming split("SweepLargeObjects", GetTimings());
   RecordFreeLOS(heap_->GetLargeObjectsSpace()->Sweep(swap_bitmaps));
diff --git a/runtime/gc/collector/concurrent_copying.h b/runtime/gc/collector/concurrent_copying.h
index a862802..55c4570 100644
--- a/runtime/gc/collector/concurrent_copying.h
+++ b/runtime/gc/collector/concurrent_copying.h
@@ -187,6 +187,8 @@
       SHARED_REQUIRES(Locks::mutator_lock_) REQUIRES(Locks::heap_bitmap_lock_, !mark_stack_lock_);
   void SweepLargeObjects(bool swap_bitmaps)
       SHARED_REQUIRES(Locks::mutator_lock_) REQUIRES(Locks::heap_bitmap_lock_);
+  void MarkZygoteLargeObjects()
+      SHARED_REQUIRES(Locks::mutator_lock_);
   void FillWithDummyObject(mirror::Object* dummy_obj, size_t byte_size)
       REQUIRES(!mark_stack_lock_, !skipped_blocks_lock_, !immune_gray_stack_lock_)
       SHARED_REQUIRES(Locks::mutator_lock_);
diff --git a/runtime/gc/heap.cc b/runtime/gc/heap.cc
index aa3bf61..39f26e7 100644
--- a/runtime/gc/heap.cc
+++ b/runtime/gc/heap.cc
@@ -2556,15 +2556,25 @@
 
   // Create the zygote space mod union table.
   accounting::ModUnionTable* mod_union_table =
-      new accounting::ModUnionTableCardCache("zygote space mod-union table", this,
-                                             zygote_space_);
+      new accounting::ModUnionTableCardCache("zygote space mod-union table", this, zygote_space_);
   CHECK(mod_union_table != nullptr) << "Failed to create zygote space mod-union table";
-  // Set all the cards in the mod-union table since we don't know which objects contain references
-  // to large objects.
-  mod_union_table->SetCards();
-  // Filter out cards that do not to be dirty. This is mostly for CC collector so that it does
-  // not gray the objects on all the cards in the zygote space.
-  mod_union_table->FilterCards();
+
+  if (collector_type_ != kCollectorTypeCC) {
+    // Set all the cards in the mod-union table since we don't know which objects contain references
+    // to large objects.
+    mod_union_table->SetCards();
+  } else {
+    // For CC we never collect zygote large objects. This means we do not need to set the cards for
+    // the zygote mod-union table and we can also clear all of the existing image mod-union tables.
+    // The existing mod-union tables are only for image spaces and may only reference zygote and
+    // image objects.
+    for (auto& pair : mod_union_tables_) {
+      CHECK(pair.first->IsImageSpace());
+      CHECK(!pair.first->AsImageSpace()->GetImageHeader().IsAppImage());
+      accounting::ModUnionTable* table = pair.second;
+      table->ClearTable();
+    }
+  }
   AddModUnionTable(mod_union_table);
   large_object_space_->SetAllLargeObjectsAsZygoteObjects(self);
   if (collector::SemiSpace::kUseRememberedSet) {