summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--runtime/gc/collector/immune_spaces.h1
-rw-r--r--runtime/gc/collector/mark_compact.cc111
-rw-r--r--runtime/gc/collector/mark_compact.h12
3 files changed, 35 insertions, 89 deletions
diff --git a/runtime/gc/collector/immune_spaces.h b/runtime/gc/collector/immune_spaces.h
index 5a8441a67a..950c35b27a 100644
--- a/runtime/gc/collector/immune_spaces.h
+++ b/runtime/gc/collector/immune_spaces.h
@@ -43,6 +43,7 @@ class ImmuneSpaces {
public:
ImmuneSpaces() {}
void Reset();
+ bool IsEmpty() const { return spaces_.empty(); }
// Add a continuous space to the immune spaces set.
void AddSpace(space::ContinuousSpace* space) REQUIRES(Locks::heap_bitmap_lock_);
diff --git a/runtime/gc/collector/mark_compact.cc b/runtime/gc/collector/mark_compact.cc
index c3c08b12b8..768547dac0 100644
--- a/runtime/gc/collector/mark_compact.cc
+++ b/runtime/gc/collector/mark_compact.cc
@@ -562,27 +562,28 @@ void MarkCompact::AddLinearAllocSpaceData(uint8_t* begin, size_t len) {
is_shared);
}
-void MarkCompact::BindAndResetBitmaps() {
- // TODO: We need to hold heap_bitmap_lock_ only for populating immune_spaces.
- // The card-table and mod-union-table processing can be done without it. So
- // change the logic below. Note that the bitmap clearing would require the
- // lock.
+void MarkCompact::PrepareCardTableForMarking(bool clear_alloc_space_cards) {
TimingLogger::ScopedTiming t(__FUNCTION__, GetTimings());
accounting::CardTable* const card_table = heap_->GetCardTable();
+ // immune_spaces_ is emptied in InitializePhase() before marking starts. This
+ // function is invoked twice during marking. We only need to populate immune_spaces_
+ // once per GC cycle. And when it's done (below), all the immune spaces are
+ // added to it. We can never have partially filled immune_spaces_.
+ bool update_immune_spaces = immune_spaces_.IsEmpty();
// Mark all of the spaces we never collect as immune.
for (const auto& space : GetHeap()->GetContinuousSpaces()) {
if (space->GetGcRetentionPolicy() == space::kGcRetentionPolicyNeverCollect ||
space->GetGcRetentionPolicy() == space::kGcRetentionPolicyFullCollect) {
CHECK(space->IsZygoteSpace() || space->IsImageSpace());
- immune_spaces_.AddSpace(space);
+ if (update_immune_spaces) {
+ immune_spaces_.AddSpace(space);
+ }
accounting::ModUnionTable* table = heap_->FindModUnionTableFromSpace(space);
if (table != nullptr) {
table->ProcessCards();
} else {
- // Keep cards aged if we don't have a mod-union table since we may need
+ // Keep cards aged if we don't have a mod-union table since we need
// to scan them in future GCs. This case is for app images.
- // TODO: We could probably scan the objects right here to avoid doing
- // another scan through the card-table.
card_table->ModifyCardsAtomic(
space->Begin(),
space->End(),
@@ -593,7 +594,7 @@ void MarkCompact::BindAndResetBitmaps() {
},
/* card modified visitor */ VoidFunctor());
}
- } else {
+ } else if (clear_alloc_space_cards) {
CHECK(!space->IsZygoteSpace());
CHECK(!space->IsImageSpace());
// The card-table corresponding to bump-pointer and non-moving space can
@@ -606,6 +607,16 @@ void MarkCompact::BindAndResetBitmaps() {
non_moving_space_ = space;
non_moving_space_bitmap_ = space->GetMarkBitmap();
}
+ } else {
+ card_table->ModifyCardsAtomic(
+ space->Begin(),
+ space->End(),
+ [](uint8_t card) {
+ return (card == gc::accounting::CardTable::kCardDirty) ?
+ gc::accounting::CardTable::kCardAged :
+ gc::accounting::CardTable::kCardClean;
+ },
+ /* card modified visitor */ VoidFunctor());
}
}
}
@@ -3796,26 +3807,6 @@ void MarkCompact::MarkReachableObjects() {
ProcessMarkStack();
}
-class MarkCompact::CardModifiedVisitor {
- public:
- explicit CardModifiedVisitor(MarkCompact* const mark_compact,
- accounting::ContinuousSpaceBitmap* const bitmap,
- accounting::CardTable* const card_table)
- : visitor_(mark_compact), bitmap_(bitmap), card_table_(card_table) {}
-
- void operator()(uint8_t* card, uint8_t expected_value, [[maybe_unused]] uint8_t new_value) const {
- if (expected_value == accounting::CardTable::kCardDirty) {
- uintptr_t start = reinterpret_cast<uintptr_t>(card_table_->AddrFromCard(card));
- bitmap_->VisitMarkedRange(start, start + accounting::CardTable::kCardSize, visitor_);
- }
- }
-
- private:
- ScanObjectVisitor visitor_;
- accounting::ContinuousSpaceBitmap* bitmap_;
- accounting::CardTable* const card_table_;
-};
-
void MarkCompact::ScanDirtyObjects(bool paused, uint8_t minimum_age) {
accounting::CardTable* card_table = heap_->GetCardTable();
for (const auto& space : heap_->GetContinuousSpaces()) {
@@ -3835,58 +3826,8 @@ void MarkCompact::ScanDirtyObjects(bool paused, uint8_t minimum_age) {
UNREACHABLE();
}
TimingLogger::ScopedTiming t(name, GetTimings());
- ScanObjectVisitor visitor(this);
- const bool is_immune_space = space->IsZygoteSpace() || space->IsImageSpace();
- if (paused) {
- DCHECK_EQ(minimum_age, gc::accounting::CardTable::kCardDirty);
- // We can clear the card-table for any non-immune space.
- if (is_immune_space) {
- card_table->Scan</*kClearCard*/false>(space->GetMarkBitmap(),
- space->Begin(),
- space->End(),
- visitor,
- minimum_age);
- } else {
- card_table->Scan</*kClearCard*/true>(space->GetMarkBitmap(),
- space->Begin(),
- space->End(),
- visitor,
- minimum_age);
- }
- } else {
- DCHECK_EQ(minimum_age, gc::accounting::CardTable::kCardAged);
- accounting::ModUnionTable* table = heap_->FindModUnionTableFromSpace(space);
- if (table) {
- table->ProcessCards();
- card_table->Scan</*kClearCard*/false>(space->GetMarkBitmap(),
- space->Begin(),
- space->End(),
- visitor,
- minimum_age);
- } else {
- CardModifiedVisitor card_modified_visitor(this, space->GetMarkBitmap(), card_table);
- // For the alloc spaces we should age the dirty cards and clear the rest.
- // For image and zygote-space without mod-union-table, age the dirty
- // cards but keep the already aged cards unchanged.
- // In either case, visit the objects on the cards that were changed from
- // dirty to aged.
- if (is_immune_space) {
- card_table->ModifyCardsAtomic(space->Begin(),
- space->End(),
- [](uint8_t card) {
- return (card == gc::accounting::CardTable::kCardClean)
- ? card
- : gc::accounting::CardTable::kCardAged;
- },
- card_modified_visitor);
- } else {
- card_table->ModifyCardsAtomic(space->Begin(),
- space->End(),
- AgeCardVisitor(),
- card_modified_visitor);
- }
- }
- }
+ card_table->Scan</*kClearCard*/ false>(
+ space->GetMarkBitmap(), space->Begin(), space->End(), ScanObjectVisitor(this), minimum_age);
}
}
@@ -3910,6 +3851,10 @@ void MarkCompact::MarkRoots(VisitRootFlags flags) {
void MarkCompact::PreCleanCards() {
TimingLogger::ScopedTiming t(__FUNCTION__, GetTimings());
CHECK(!Locks::mutator_lock_->IsExclusiveHeld(thread_running_gc_));
+ // Age the card-table before thread stack scanning checkpoint in MarkRoots()
+ // as it ensures that there are no in-progress write barriers which started
+ // prior to aging the card-table.
+ PrepareCardTableForMarking(/*clear_alloc_space_cards*/ false);
MarkRoots(static_cast<VisitRootFlags>(kVisitRootFlagClearRootLog | kVisitRootFlagNewRoots));
RecursiveMarkDirtyObjects(/*paused*/ false, accounting::CardTable::kCardDirty - 1);
}
@@ -3930,7 +3875,7 @@ void MarkCompact::MarkingPhase() {
TimingLogger::ScopedTiming t(__FUNCTION__, GetTimings());
DCHECK_EQ(thread_running_gc_, Thread::Current());
WriterMutexLock mu(thread_running_gc_, *Locks::heap_bitmap_lock_);
- BindAndResetBitmaps();
+ PrepareCardTableForMarking(/*clear_alloc_space_cards*/ true);
MarkZygoteLargeObjects();
MarkRoots(
static_cast<VisitRootFlags>(kVisitRootFlagAllRoots | kVisitRootFlagStartLoggingNewRoots));
diff --git a/runtime/gc/collector/mark_compact.h b/runtime/gc/collector/mark_compact.h
index d73f40d436..4e9780c970 100644
--- a/runtime/gc/collector/mark_compact.h
+++ b/runtime/gc/collector/mark_compact.h
@@ -290,10 +290,10 @@ class MarkCompact final : public GarbageCollector {
// GC cycle.
ALWAYS_INLINE mirror::Object* PostCompactBlackObjAddr(mirror::Object* old_ref) const
REQUIRES_SHARED(Locks::mutator_lock_);
- // Identify immune spaces and reset card-table, mod-union-table, and mark
- // bitmaps.
- void BindAndResetBitmaps() REQUIRES_SHARED(Locks::mutator_lock_)
- REQUIRES(Locks::heap_bitmap_lock_);
+ // Clears (for alloc spaces in the beginning of marking phase) or ages the
+ // card table. Also, identifies immune spaces and mark bitmap.
+ void PrepareCardTableForMarking(bool clear_alloc_space_cards)
+ REQUIRES_SHARED(Locks::mutator_lock_) REQUIRES(Locks::heap_bitmap_lock_);
// Perform one last round of marking, identifying roots from dirty cards
// during a stop-the-world (STW) pause.
@@ -767,8 +767,8 @@ class MarkCompact final : public GarbageCollector {
class VerifyRootMarkedVisitor;
class ScanObjectVisitor;
class CheckpointMarkThreadRoots;
- template<size_t kBufferSize> class ThreadRootsVisitor;
- class CardModifiedVisitor;
+ template <size_t kBufferSize>
+ class ThreadRootsVisitor;
class RefFieldsVisitor;
template <bool kCheckBegin, bool kCheckEnd> class RefsUpdateVisitor;
class ArenaPoolPageUpdater;