Commit e5b07adf authored by hpayer's avatar hpayer Committed by Commit bot

[heap] Use the thread-safe free modes also for RemoveRange in SlotSet.

BUG=chromium:648568

Review-Url: https://codereview.chromium.org/2397373002
Cr-Commit-Position: refs/heads/master@{#40075}
parent 940efafd
...@@ -5951,8 +5951,10 @@ void Heap::ClearRecordedSlotRange(Address start, Address end) { ...@@ -5951,8 +5951,10 @@ void Heap::ClearRecordedSlotRange(Address start, Address end) {
if (!page->InNewSpace()) { if (!page->InNewSpace()) {
store_buffer()->MoveEntriesToRememberedSet(); store_buffer()->MoveEntriesToRememberedSet();
DCHECK_EQ(page->owner()->identity(), OLD_SPACE); DCHECK_EQ(page->owner()->identity(), OLD_SPACE);
RememberedSet<OLD_TO_NEW>::RemoveRange(page, start, end); RememberedSet<OLD_TO_NEW>::RemoveRange(page, start, end,
RememberedSet<OLD_TO_OLD>::RemoveRange(page, start, end); SlotSet::PREFREE_EMPTY_BUCKETS);
RememberedSet<OLD_TO_OLD>::RemoveRange(page, start, end,
SlotSet::FREE_EMPTY_BUCKETS);
} }
} }
......
...@@ -3480,7 +3480,8 @@ bool MarkCompactCollector::VisitLiveObjects(MemoryChunk* page, Visitor* visitor, ...@@ -3480,7 +3480,8 @@ bool MarkCompactCollector::VisitLiveObjects(MemoryChunk* page, Visitor* visitor,
page->AddressToMarkbitIndex(object->address())); page->AddressToMarkbitIndex(object->address()));
if (page->old_to_new_slots() != nullptr) { if (page->old_to_new_slots() != nullptr) {
page->old_to_new_slots()->RemoveRange( page->old_to_new_slots()->RemoveRange(
0, static_cast<int>(object->address() - page->address())); 0, static_cast<int>(object->address() - page->address()),
SlotSet::PREFREE_EMPTY_BUCKETS);
} }
if (page->typed_old_to_new_slots() != nullptr) { if (page->typed_old_to_new_slots() != nullptr) {
RememberedSet<OLD_TO_NEW>::RemoveRangeTyped(page, page->address(), RememberedSet<OLD_TO_NEW>::RemoveRangeTyped(page, page->address(),
......
...@@ -45,7 +45,8 @@ class RememberedSet { ...@@ -45,7 +45,8 @@ class RememberedSet {
// Given a page and a range of slots in that page, this function removes the // Given a page and a range of slots in that page, this function removes the
// slots from the remembered set. // slots from the remembered set.
static void RemoveRange(MemoryChunk* chunk, Address start, Address end) { static void RemoveRange(MemoryChunk* chunk, Address start, Address end,
SlotSet::EmptyBucketMode mode) {
SlotSet* slot_set = GetSlotSet(chunk); SlotSet* slot_set = GetSlotSet(chunk);
if (slot_set != nullptr) { if (slot_set != nullptr) {
uintptr_t start_offset = start - chunk->address(); uintptr_t start_offset = start - chunk->address();
...@@ -53,7 +54,7 @@ class RememberedSet { ...@@ -53,7 +54,7 @@ class RememberedSet {
DCHECK_LT(start_offset, end_offset); DCHECK_LT(start_offset, end_offset);
if (end_offset < static_cast<uintptr_t>(Page::kPageSize)) { if (end_offset < static_cast<uintptr_t>(Page::kPageSize)) {
slot_set->RemoveRange(static_cast<int>(start_offset), slot_set->RemoveRange(static_cast<int>(start_offset),
static_cast<int>(end_offset)); static_cast<int>(end_offset), mode);
} else { } else {
// The large page has multiple slot sets. // The large page has multiple slot sets.
// Compute slot set indicies for the range [start_offset, end_offset). // Compute slot set indicies for the range [start_offset, end_offset).
...@@ -67,17 +68,17 @@ class RememberedSet { ...@@ -67,17 +68,17 @@ class RememberedSet {
end_offset - static_cast<uintptr_t>(end_chunk) * Page::kPageSize); end_offset - static_cast<uintptr_t>(end_chunk) * Page::kPageSize);
if (start_chunk == end_chunk) { if (start_chunk == end_chunk) {
slot_set[start_chunk].RemoveRange(offset_in_start_chunk, slot_set[start_chunk].RemoveRange(offset_in_start_chunk,
offset_in_end_chunk); offset_in_end_chunk, mode);
} else { } else {
// Clear all slots from start_offset to the end of first chunk. // Clear all slots from start_offset to the end of first chunk.
slot_set[start_chunk].RemoveRange(offset_in_start_chunk, slot_set[start_chunk].RemoveRange(offset_in_start_chunk,
Page::kPageSize); Page::kPageSize, mode);
// Clear all slots in intermediate chunks. // Clear all slots in intermediate chunks.
for (int i = start_chunk + 1; i < end_chunk; i++) { for (int i = start_chunk + 1; i < end_chunk; i++) {
slot_set[i].RemoveRange(0, Page::kPageSize); slot_set[i].RemoveRange(0, Page::kPageSize, mode);
} }
// Clear slots from the beginning of the last page to end_offset. // Clear slots from the beginning of the last page to end_offset.
slot_set[end_chunk].RemoveRange(0, offset_in_end_chunk); slot_set[end_chunk].RemoveRange(0, offset_in_end_chunk, mode);
} }
} }
} }
......
...@@ -25,7 +25,13 @@ enum SlotCallbackResult { KEEP_SLOT, REMOVE_SLOT }; ...@@ -25,7 +25,13 @@ enum SlotCallbackResult { KEEP_SLOT, REMOVE_SLOT };
// Each bucket is a bitmap with a bit corresponding to a single slot offset. // Each bucket is a bitmap with a bit corresponding to a single slot offset.
class SlotSet : public Malloced { class SlotSet : public Malloced {
public: public:
enum IterationMode { PREFREE_EMPTY_BUCKETS, KEEP_EMPTY_BUCKETS }; enum EmptyBucketMode {
FREE_EMPTY_BUCKETS, // An empty bucket will be deallocated immediately.
PREFREE_EMPTY_BUCKETS, // An empty bucket will be unlinked from the slot
// set, but deallocated on demand by a sweeper
// thread.
KEEP_EMPTY_BUCKETS // An empty bucket will be kept.
};
SlotSet() { SlotSet() {
for (int i = 0; i < kBuckets; i++) { for (int i = 0; i < kBuckets; i++) {
...@@ -74,9 +80,16 @@ class SlotSet : public Malloced { ...@@ -74,9 +80,16 @@ class SlotSet : public Malloced {
} }
} }
void PreFreeEmptyBucket(int bucket_index) {
base::LockGuard<base::Mutex> guard(&to_be_freed_buckets_mutex_);
base::AtomicValue<uint32_t>* bucket_ptr = bucket[bucket_index].Value();
to_be_freed_buckets_.push(bucket_ptr);
bucket[bucket_index].SetValue(nullptr);
}
// The slot offsets specify a range of slots at addresses: // The slot offsets specify a range of slots at addresses:
// [page_start_ + start_offset ... page_start_ + end_offset). // [page_start_ + start_offset ... page_start_ + end_offset).
void RemoveRange(int start_offset, int end_offset) { void RemoveRange(int start_offset, int end_offset, EmptyBucketMode mode) {
CHECK_LE(end_offset, 1 << kPageSizeBits); CHECK_LE(end_offset, 1 << kPageSizeBits);
DCHECK_LE(start_offset, end_offset); DCHECK_LE(start_offset, end_offset);
int start_bucket, start_cell, start_bit; int start_bucket, start_cell, start_bit;
...@@ -108,7 +121,11 @@ class SlotSet : public Malloced { ...@@ -108,7 +121,11 @@ class SlotSet : public Malloced {
DCHECK(current_bucket == end_bucket || DCHECK(current_bucket == end_bucket ||
(current_bucket < end_bucket && current_cell == 0)); (current_bucket < end_bucket && current_cell == 0));
while (current_bucket < end_bucket) { while (current_bucket < end_bucket) {
ReleaseBucket(current_bucket); if (mode == PREFREE_EMPTY_BUCKETS) {
PreFreeEmptyBucket(current_bucket);
} else if (mode == FREE_EMPTY_BUCKETS) {
ReleaseBucket(current_bucket);
}
current_bucket++; current_bucket++;
} }
// All buckets between start_bucket and end_bucket are cleared. // All buckets between start_bucket and end_bucket are cleared.
...@@ -148,7 +165,7 @@ class SlotSet : public Malloced { ...@@ -148,7 +165,7 @@ class SlotSet : public Malloced {
// else return REMOVE_SLOT; // else return REMOVE_SLOT;
// }); // });
template <typename Callback> template <typename Callback>
int Iterate(Callback callback, IterationMode mode) { int Iterate(Callback callback, EmptyBucketMode mode) {
int new_count = 0; int new_count = 0;
for (int bucket_index = 0; bucket_index < kBuckets; bucket_index++) { for (int bucket_index = 0; bucket_index < kBuckets; bucket_index++) {
if (bucket[bucket_index].Value() != nullptr) { if (bucket[bucket_index].Value() != nullptr) {
...@@ -186,11 +203,7 @@ class SlotSet : public Malloced { ...@@ -186,11 +203,7 @@ class SlotSet : public Malloced {
} }
} }
if (mode == PREFREE_EMPTY_BUCKETS && in_bucket_count == 0) { if (mode == PREFREE_EMPTY_BUCKETS && in_bucket_count == 0) {
base::LockGuard<base::Mutex> guard(&to_be_freed_buckets_mutex_); PreFreeEmptyBucket(bucket_index);
base::AtomicValue<uint32_t>* bucket_ptr =
bucket[bucket_index].Value();
to_be_freed_buckets_.push(bucket_ptr);
bucket[bucket_index].SetValue(nullptr);
} }
new_count += in_bucket_count; new_count += in_bucket_count;
} }
......
...@@ -2905,8 +2905,10 @@ Address LargePage::GetAddressToShrink() { ...@@ -2905,8 +2905,10 @@ Address LargePage::GetAddressToShrink() {
} }
void LargePage::ClearOutOfLiveRangeSlots(Address free_start) { void LargePage::ClearOutOfLiveRangeSlots(Address free_start) {
RememberedSet<OLD_TO_NEW>::RemoveRange(this, free_start, area_end()); RememberedSet<OLD_TO_NEW>::RemoveRange(this, free_start, area_end(),
RememberedSet<OLD_TO_OLD>::RemoveRange(this, free_start, area_end()); SlotSet::FREE_EMPTY_BUCKETS);
RememberedSet<OLD_TO_OLD>::RemoveRange(this, free_start, area_end(),
SlotSet::FREE_EMPTY_BUCKETS);
RememberedSet<OLD_TO_NEW>::RemoveRangeTyped(this, free_start, area_end()); RememberedSet<OLD_TO_NEW>::RemoveRangeTyped(this, free_start, area_end());
RememberedSet<OLD_TO_OLD>::RemoveRangeTyped(this, free_start, area_end()); RememberedSet<OLD_TO_OLD>::RemoveRangeTyped(this, free_start, area_end());
} }
......
...@@ -7037,7 +7037,8 @@ TEST(RememberedSetRemoveRange) { ...@@ -7037,7 +7037,8 @@ TEST(RememberedSetRemoveRange) {
return KEEP_SLOT; return KEEP_SLOT;
}); });
RememberedSet<OLD_TO_NEW>::RemoveRange(chunk, start, start + kPointerSize); RememberedSet<OLD_TO_NEW>::RemoveRange(chunk, start, start + kPointerSize,
SlotSet::FREE_EMPTY_BUCKETS);
slots[start] = false; slots[start] = false;
RememberedSet<OLD_TO_NEW>::Iterate(chunk, [&slots](Address addr) { RememberedSet<OLD_TO_NEW>::Iterate(chunk, [&slots](Address addr) {
CHECK(slots[addr]); CHECK(slots[addr]);
...@@ -7045,7 +7046,8 @@ TEST(RememberedSetRemoveRange) { ...@@ -7045,7 +7046,8 @@ TEST(RememberedSetRemoveRange) {
}); });
RememberedSet<OLD_TO_NEW>::RemoveRange(chunk, start + kPointerSize, RememberedSet<OLD_TO_NEW>::RemoveRange(chunk, start + kPointerSize,
start + Page::kPageSize); start + Page::kPageSize,
SlotSet::FREE_EMPTY_BUCKETS);
slots[start + kPointerSize] = false; slots[start + kPointerSize] = false;
slots[start + Page::kPageSize - kPointerSize] = false; slots[start + Page::kPageSize - kPointerSize] = false;
RememberedSet<OLD_TO_NEW>::Iterate(chunk, [&slots](Address addr) { RememberedSet<OLD_TO_NEW>::Iterate(chunk, [&slots](Address addr) {
...@@ -7053,8 +7055,9 @@ TEST(RememberedSetRemoveRange) { ...@@ -7053,8 +7055,9 @@ TEST(RememberedSetRemoveRange) {
return KEEP_SLOT; return KEEP_SLOT;
}); });
RememberedSet<OLD_TO_NEW>::RemoveRange( RememberedSet<OLD_TO_NEW>::RemoveRange(chunk, start,
chunk, start, start + Page::kPageSize + kPointerSize); start + Page::kPageSize + kPointerSize,
SlotSet::FREE_EMPTY_BUCKETS);
slots[start + Page::kPageSize] = false; slots[start + Page::kPageSize] = false;
RememberedSet<OLD_TO_NEW>::Iterate(chunk, [&slots](Address addr) { RememberedSet<OLD_TO_NEW>::Iterate(chunk, [&slots](Address addr) {
CHECK(slots[addr]); CHECK(slots[addr]);
...@@ -7062,7 +7065,8 @@ TEST(RememberedSetRemoveRange) { ...@@ -7062,7 +7065,8 @@ TEST(RememberedSetRemoveRange) {
}); });
RememberedSet<OLD_TO_NEW>::RemoveRange( RememberedSet<OLD_TO_NEW>::RemoveRange(
chunk, chunk->area_end() - kPointerSize, chunk->area_end()); chunk, chunk->area_end() - kPointerSize, chunk->area_end(),
SlotSet::FREE_EMPTY_BUCKETS);
slots[chunk->area_end() - kPointerSize] = false; slots[chunk->area_end() - kPointerSize] = false;
RememberedSet<OLD_TO_NEW>::Iterate(chunk, [&slots](Address addr) { RememberedSet<OLD_TO_NEW>::Iterate(chunk, [&slots](Address addr) {
CHECK(slots[addr]); CHECK(slots[addr]);
......
...@@ -104,7 +104,7 @@ void CheckRemoveRangeOn(uint32_t start, uint32_t end) { ...@@ -104,7 +104,7 @@ void CheckRemoveRangeOn(uint32_t start, uint32_t end) {
for (uint32_t i = first; i <= last; i += kPointerSize) { for (uint32_t i = first; i <= last; i += kPointerSize) {
set.Insert(i); set.Insert(i);
} }
set.RemoveRange(start, end); set.RemoveRange(start, end, SlotSet::FREE_EMPTY_BUCKETS);
if (first != start) { if (first != start) {
EXPECT_TRUE(set.Lookup(first)); EXPECT_TRUE(set.Lookup(first));
} }
...@@ -135,7 +135,7 @@ TEST(SlotSet, RemoveRange) { ...@@ -135,7 +135,7 @@ TEST(SlotSet, RemoveRange) {
SlotSet set; SlotSet set;
set.SetPageStart(0); set.SetPageStart(0);
set.Insert(Page::kPageSize / 2); set.Insert(Page::kPageSize / 2);
set.RemoveRange(0, Page::kPageSize); set.RemoveRange(0, Page::kPageSize, SlotSet::FREE_EMPTY_BUCKETS);
for (uint32_t i = 0; i < Page::kPageSize; i += kPointerSize) { for (uint32_t i = 0; i < Page::kPageSize; i += kPointerSize) {
EXPECT_FALSE(set.Lookup(i)); EXPECT_FALSE(set.Lookup(i));
} }
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment