Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

deps: V8: cherry-pick 163d360 from upstream #15664

Closed
wants to merge 1 commit into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 5 additions & 1 deletion deps/v8/src/heap/heap.cc
Original file line number Diff line number Diff line change
Expand Up @@ -1814,7 +1814,11 @@ void Heap::Scavenge() {
ArrayBufferTracker::FreeDeadInNewSpace(this);

RememberedSet<OLD_TO_NEW>::IterateMemoryChunks(this, [](MemoryChunk* chunk) {
RememberedSet<OLD_TO_NEW>::PreFreeEmptyBuckets(chunk);
if (chunk->SweepingDone()) {
RememberedSet<OLD_TO_NEW>::FreeEmptyBuckets(chunk);
} else {
RememberedSet<OLD_TO_NEW>::PreFreeEmptyBuckets(chunk);
}
});

// Update how much has survived scavenge.
Expand Down
25 changes: 25 additions & 0 deletions deps/v8/src/heap/remembered-set.h
Original file line number Diff line number Diff line change
Expand Up @@ -150,6 +150,19 @@ class RememberedSet : public AllStatic {
}
}

static int NumberOfPreFreedEmptyBuckets(MemoryChunk* chunk) {
DCHECK(type == OLD_TO_NEW);
int result = 0;
SlotSet* slots = chunk->slot_set<type>();
if (slots != nullptr) {
size_t pages = (chunk->size() + Page::kPageSize - 1) / Page::kPageSize;
for (size_t page = 0; page < pages; page++) {
result += slots[page].NumberOfPreFreedEmptyBuckets();
}
}
return result;
}

static void PreFreeEmptyBuckets(MemoryChunk* chunk) {
DCHECK(type == OLD_TO_NEW);
SlotSet* slots = chunk->slot_set<type>();
Expand All @@ -161,6 +174,18 @@ class RememberedSet : public AllStatic {
}
}

static void FreeEmptyBuckets(MemoryChunk* chunk) {
DCHECK(type == OLD_TO_NEW);
SlotSet* slots = chunk->slot_set<type>();
if (slots != nullptr) {
size_t pages = (chunk->size() + Page::kPageSize - 1) / Page::kPageSize;
for (size_t page = 0; page < pages; page++) {
slots[page].FreeEmptyBuckets();
slots[page].FreeToBeFreedBuckets();
}
}
}

// Given a page and a typed slot in that page, this function adds the slot
// to the remembered set.
static void InsertTyped(Page* page, Address host_addr, SlotType slot_type,
Expand Down
36 changes: 27 additions & 9 deletions deps/v8/src/heap/slot-set.h
Original file line number Diff line number Diff line change
Expand Up @@ -225,32 +225,41 @@ class SlotSet : public Malloced {
return new_count;
}

int NumberOfPreFreedEmptyBuckets() {
base::LockGuard<base::Mutex> guard(&to_be_freed_buckets_mutex_);
return static_cast<int>(to_be_freed_buckets_.size());
}

void PreFreeEmptyBuckets() {
for (int bucket_index = 0; bucket_index < kBuckets; bucket_index++) {
Bucket bucket = LoadBucket(&buckets_[bucket_index]);
if (bucket != nullptr) {
bool found_non_empty_cell = false;
int cell_offset = bucket_index * kBitsPerBucket;
for (int i = 0; i < kCellsPerBucket; i++, cell_offset += kBitsPerCell) {
if (LoadCell(&bucket[i])) {
found_non_empty_cell = true;
break;
}
}
if (!found_non_empty_cell) {
if (IsEmptyBucket(bucket)) {
PreFreeEmptyBucket(bucket_index);
}
}
}
}

void FreeEmptyBuckets() {
for (int bucket_index = 0; bucket_index < kBuckets; bucket_index++) {
Bucket bucket = LoadBucket(&buckets_[bucket_index]);
if (bucket != nullptr) {
if (IsEmptyBucket(bucket)) {
ReleaseBucket(bucket_index);
}
}
}
}

void FreeToBeFreedBuckets() {
base::LockGuard<base::Mutex> guard(&to_be_freed_buckets_mutex_);
while (!to_be_freed_buckets_.empty()) {
Bucket top = to_be_freed_buckets_.top();
to_be_freed_buckets_.pop();
DeleteArray<uint32_t>(top);
}
DCHECK_EQ(0u, to_be_freed_buckets_.size());
}

private:
Expand Down Expand Up @@ -313,6 +322,15 @@ class SlotSet : public Malloced {
}
}

bool IsEmptyBucket(Bucket bucket) {
for (int i = 0; i < kCellsPerBucket; i++) {
if (LoadCell(&bucket[i])) {
return false;
}
}
return true;
}

template <AccessMode access_mode = AccessMode::ATOMIC>
bool SwapInNewBucket(Bucket* bucket, Bucket value) {
if (access_mode == AccessMode::ATOMIC) {
Expand Down
1 change: 1 addition & 0 deletions deps/v8/src/heap/spaces.cc
Original file line number Diff line number Diff line change
Expand Up @@ -3308,6 +3308,7 @@ void LargeObjectSpace::ClearMarkingStateOfLiveObjects() {
Marking::MarkWhite(
ObjectMarking::MarkBitFrom(obj, MarkingState::Internal(obj)));
MemoryChunk* chunk = MemoryChunk::FromAddress(obj->address());
RememberedSet<OLD_TO_NEW>::FreeEmptyBuckets(chunk);
chunk->ResetProgressBar();
MarkingState::Internal(chunk).SetLiveBytes(0);
}
Expand Down
47 changes: 47 additions & 0 deletions deps/v8/test/cctest/heap/test-heap.cc
Original file line number Diff line number Diff line change
Expand Up @@ -6237,6 +6237,53 @@ HEAP_TEST(Regress5831) {
CHECK(chunk->NeverEvacuate());
}

TEST(Regress6800) {
CcTest::InitializeVM();
Isolate* isolate = CcTest::i_isolate();
HandleScope handle_scope(isolate);

const int kRootLength = 1000;
Handle<FixedArray> root =
isolate->factory()->NewFixedArray(kRootLength, TENURED);
{
HandleScope inner_scope(isolate);
Handle<FixedArray> new_space_array = isolate->factory()->NewFixedArray(1);
for (int i = 0; i < kRootLength; i++) {
root->set(i, *new_space_array);
}
for (int i = 0; i < kRootLength; i++) {
root->set(i, CcTest::heap()->undefined_value());
}
}
CcTest::CollectGarbage(NEW_SPACE);
CHECK_EQ(0, RememberedSet<OLD_TO_NEW>::NumberOfPreFreedEmptyBuckets(
MemoryChunk::FromAddress(root->address())));
}

TEST(Regress6800LargeObject) {
CcTest::InitializeVM();
Isolate* isolate = CcTest::i_isolate();
HandleScope handle_scope(isolate);

const int kRootLength = i::kMaxRegularHeapObjectSize / kPointerSize;
Handle<FixedArray> root =
isolate->factory()->NewFixedArray(kRootLength, TENURED);
CcTest::heap()->lo_space()->Contains(*root);
{
HandleScope inner_scope(isolate);
Handle<FixedArray> new_space_array = isolate->factory()->NewFixedArray(1);
for (int i = 0; i < kRootLength; i++) {
root->set(i, *new_space_array);
}
for (int i = 0; i < kRootLength; i++) {
root->set(i, CcTest::heap()->undefined_value());
}
}
CcTest::CollectGarbage(OLD_SPACE);
CHECK_EQ(0, RememberedSet<OLD_TO_NEW>::NumberOfPreFreedEmptyBuckets(
MemoryChunk::FromAddress(root->address())));
}

HEAP_TEST(RegressMissingWriteBarrierInAllocate) {
if (!FLAG_incremental_marking) return;
FLAG_black_allocation = true;
Expand Down