ART: clear dirty cards of alloc space in pause phase

Clear the dirty cards of alloc spaces when scanning them in pause phase,
the dirty cards of image or zygote space will not be cleared in order to
track the references to the other spaces.

Change-Id: I519f071d954a589aa33dbce0cdba405f2d2cef71
Signed-off-by: Lei Li <lei.l.li@intel.com>
diff --git a/runtime/gc/accounting/card_table-inl.h b/runtime/gc/accounting/card_table-inl.h
index 15562e5..83ad33e 100644
--- a/runtime/gc/accounting/card_table-inl.h
+++ b/runtime/gc/accounting/card_table-inl.h
@@ -48,7 +48,7 @@
 #endif
 }
 
-template <typename Visitor>
+template <bool kClearCard, typename Visitor>
 inline size_t CardTable::Scan(ContinuousSpaceBitmap* bitmap, uint8_t* scan_begin, uint8_t* scan_end,
                               const Visitor& visitor, const uint8_t minimum_age) const {
   DCHECK_GE(scan_begin, reinterpret_cast<uint8_t*>(bitmap->HeapBegin()));
@@ -66,6 +66,9 @@
       uintptr_t start = reinterpret_cast<uintptr_t>(AddrFromCard(card_cur));
       bitmap->VisitMarkedRange(start, start + kCardSize, visitor);
       ++cards_scanned;
+      if (kClearCard) {
+        *card_cur = 0;
+      }
     }
     ++card_cur;
   }
@@ -95,6 +98,9 @@
             << "card " << static_cast<size_t>(*card) << " intptr_t " << (start_word & 0xFF);
         bitmap->VisitMarkedRange(start, start + kCardSize, visitor);
         ++cards_scanned;
+        if (kClearCard) {
+          *card = 0;
+        }
       }
       start_word >>= 8;
       start += kCardSize;
@@ -109,6 +115,9 @@
       uintptr_t start = reinterpret_cast<uintptr_t>(AddrFromCard(card_cur));
       bitmap->VisitMarkedRange(start, start + kCardSize, visitor);
       ++cards_scanned;
+      if (kClearCard) {
+        *card_cur = 0;
+      }
     }
     ++card_cur;
   }
diff --git a/runtime/gc/accounting/card_table.h b/runtime/gc/accounting/card_table.h
index 9bd3fba..a84cf34 100644
--- a/runtime/gc/accounting/card_table.h
+++ b/runtime/gc/accounting/card_table.h
@@ -101,7 +101,7 @@
 
   // For every dirty at least minumum age between begin and end invoke the visitor with the
   // specified argument. Returns how many cards the visitor was run on.
-  template <typename Visitor>
+  template <bool kClearCard, typename Visitor>
   size_t Scan(SpaceBitmap<kObjectAlignment>* bitmap, uint8_t* scan_begin, uint8_t* scan_end,
               const Visitor& visitor,
               const uint8_t minimum_age = kCardDirty) const
diff --git a/runtime/gc/collector/mark_sweep.cc b/runtime/gc/collector/mark_sweep.cc
index 80f7968..04fb694 100644
--- a/runtime/gc/collector/mark_sweep.cc
+++ b/runtime/gc/collector/mark_sweep.cc
@@ -687,12 +687,12 @@
   CardScanTask(ThreadPool* thread_pool, MarkSweep* mark_sweep,
                accounting::ContinuousSpaceBitmap* bitmap,
                uint8_t* begin, uint8_t* end, uint8_t minimum_age, size_t mark_stack_size,
-               Object** mark_stack_obj)
+               Object** mark_stack_obj, bool clear_card)
       : MarkStackTask<false>(thread_pool, mark_sweep, mark_stack_size, mark_stack_obj),
         bitmap_(bitmap),
         begin_(begin),
         end_(end),
-        minimum_age_(minimum_age) {
+        minimum_age_(minimum_age), clear_card_(clear_card) {
   }
 
  protected:
@@ -700,6 +700,7 @@
   uint8_t* const begin_;
   uint8_t* const end_;
   const uint8_t minimum_age_;
+  const bool clear_card_;
 
   virtual void Finalize() {
     delete this;
@@ -708,7 +709,9 @@
   virtual void Run(Thread* self) NO_THREAD_SAFETY_ANALYSIS {
     ScanObjectParallelVisitor visitor(this);
     accounting::CardTable* card_table = mark_sweep_->GetHeap()->GetCardTable();
-    size_t cards_scanned = card_table->Scan(bitmap_, begin_, end_, visitor, minimum_age_);
+    size_t cards_scanned = clear_card_ ?
+                           card_table->Scan<true>(bitmap_, begin_, end_, visitor, minimum_age_) :
+                           card_table->Scan<false>(bitmap_, begin_, end_, visitor, minimum_age_);
     VLOG(heap) << "Parallel scanning cards " << reinterpret_cast<void*>(begin_) << " - "
         << reinterpret_cast<void*>(end_) << " = " << cards_scanned;
     // Finish by emptying our local mark stack.
@@ -763,6 +766,11 @@
       // Calculate how much address range each task gets.
       const size_t card_delta = RoundUp(address_range / thread_count + 1,
                                         accounting::CardTable::kCardSize);
+      // If paused and the space is neither zygote nor image space, we could clear the dirty
+      // cards to avoid accumulating them to increase card scanning load in the following GC
+      // cycles. We need to keep dirty cards of image space and zygote space in order to track
+      // references to the other spaces.
+      bool clear_card = paused && !space->IsZygoteSpace() && !space->IsImageSpace();
       // Create the worker tasks for this space.
       while (card_begin != card_end) {
         // Add a range of cards.
@@ -777,7 +785,7 @@
         // Add the new task to the thread pool.
         auto* task = new CardScanTask(thread_pool, this, space->GetMarkBitmap(), card_begin,
                                       card_begin + card_increment, minimum_age,
-                                      mark_stack_increment, mark_stack_end);
+                                      mark_stack_increment, mark_stack_end, clear_card);
         thread_pool->AddTask(self, task);
         card_begin += card_increment;
       }
@@ -811,8 +819,14 @@
         }
         TimingLogger::ScopedTiming t(name, GetTimings());
         ScanObjectVisitor visitor(this);
-        card_table->Scan(space->GetMarkBitmap(), space->Begin(), space->End(), visitor,
-                         minimum_age);
+        bool clear_card = paused && !space->IsZygoteSpace() && !space->IsImageSpace();
+        if (clear_card) {
+          card_table->Scan<true>(space->GetMarkBitmap(), space->Begin(), space->End(), visitor,
+                                 minimum_age);
+        } else {
+          card_table->Scan<false>(space->GetMarkBitmap(), space->Begin(), space->End(), visitor,
+                                  minimum_age);
+        }
       }
     }
   }
diff --git a/runtime/gc/heap.cc b/runtime/gc/heap.cc
index 553a5d3..e094bb4 100644
--- a/runtime/gc/heap.cc
+++ b/runtime/gc/heap.cc
@@ -2370,8 +2370,8 @@
         // Attempt to see if the card table missed the reference.
         ScanVisitor scan_visitor;
         uint8_t* byte_cover_begin = reinterpret_cast<uint8_t*>(card_table->AddrFromCard(card_addr));
-        card_table->Scan(bitmap, byte_cover_begin,
-                         byte_cover_begin + accounting::CardTable::kCardSize, scan_visitor);
+        card_table->Scan<false>(bitmap, byte_cover_begin,
+                                byte_cover_begin + accounting::CardTable::kCardSize, scan_visitor);
       }
 
       // Search to see if any of the roots reference our object.