[heap] Rename WorkStealingBag to Worklist.

Change-Id: I5d5df00a38b7196001fb91e2642914271d8e66d0
Reviewed-on: https://chromium-review.googlesource.com/544932
Commit-Queue: Ulan Degenbaev <ulan@chromium.org>
Reviewed-by: Michael Lippautz <mlippautz@chromium.org>
Cr-Commit-Position: refs/heads/master@{#46164}
This commit is contained in:
Ulan Degenbaev 2017-06-23 12:44:53 +02:00 committed by Commit Bot
parent 217d654c9b
commit b00de2a927
9 changed files with 248 additions and 249 deletions

View File

@ -1650,7 +1650,7 @@ v8_source_set("v8_base") {
"src/heap/spaces.h",
"src/heap/store-buffer.cc",
"src/heap/store-buffer.h",
"src/heap/workstealing-bag.h",
"src/heap/worklist.h",
"src/ic/access-compiler-data.h",
"src/ic/access-compiler.cc",
"src/ic/access-compiler.h",

View File

@ -26,7 +26,7 @@
#include "src/heap/objects-visiting-inl.h"
#include "src/heap/objects-visiting.h"
#include "src/heap/spaces-inl.h"
#include "src/heap/workstealing-bag.h"
#include "src/heap/worklist.h"
#include "src/ic/ic.h"
#include "src/ic/stub-cache.h"
#include "src/tracing/tracing-category-observer.h"
@ -2205,10 +2205,9 @@ void MarkCompactCollector::RecordObjectStats() {
class YoungGenerationMarkingVisitor final : public NewSpaceVisitor {
public:
YoungGenerationMarkingVisitor(Heap* heap,
WorkStealingBag* global_marking_deque,
YoungGenerationMarkingVisitor(Heap* heap, Worklist* global_worklist,
int task_id)
: heap_(heap), marking_deque_(global_marking_deque, task_id) {}
: heap_(heap), worklist_(global_worklist, task_id) {}
void VisitPointers(HeapObject* host, Object** start, Object** end) final {
for (Object** p = start; p < end; p++) {
@ -2236,12 +2235,12 @@ class YoungGenerationMarkingVisitor final : public NewSpaceVisitor {
if (ObjectMarking::WhiteToGrey<AccessMode::ATOMIC>(object,
marking_state(object))) {
// Marking deque overflow is unsupported for the young generation.
CHECK(marking_deque_.Push(object));
CHECK(worklist_.Push(object));
}
}
Heap* heap_;
LocalWorkStealingBag marking_deque_;
WorklistView worklist_;
};
class MinorMarkCompactCollector::RootMarkingVisitor : public RootVisitor {
@ -2297,7 +2296,7 @@ class YoungGenerationMarkingTask : public ItemParallelJob::Task {
public:
YoungGenerationMarkingTask(Isolate* isolate,
MinorMarkCompactCollector* collector,
WorkStealingBag* marking_deque, int task_id)
Worklist* marking_deque, int task_id)
: ItemParallelJob::Task(isolate),
collector_(collector),
marking_deque_(marking_deque, task_id),
@ -2370,7 +2369,7 @@ class YoungGenerationMarkingTask : public ItemParallelJob::Task {
}
MinorMarkCompactCollector* collector_;
LocalWorkStealingBag marking_deque_;
WorklistView marking_deque_;
YoungGenerationMarkingVisitor visitor_;
std::unordered_map<Page*, intptr_t, Page::Hasher> local_live_bytes_;
};
@ -2534,16 +2533,16 @@ class MinorMarkCompactCollector::RootMarkingVisitorSeedOnly
MinorMarkCompactCollector::MinorMarkCompactCollector(Heap* heap)
: MarkCompactCollectorBase(heap),
marking_deque_(new WorkStealingBag()),
worklist_(new Worklist()),
main_marking_visitor_(
new YoungGenerationMarkingVisitor(heap, marking_deque_, kMainMarker)),
new YoungGenerationMarkingVisitor(heap, worklist_, kMainMarker)),
page_parallel_job_semaphore_(0) {
static_assert(kNumMarkers <= WorkStealingBag::kMaxNumTasks,
static_assert(kNumMarkers <= Worklist::kMaxNumTasks,
"more marker tasks than marking deque can handle");
}
MinorMarkCompactCollector::~MinorMarkCompactCollector() {
delete marking_deque_;
delete worklist_;
delete main_marking_visitor_;
}
@ -2599,11 +2598,11 @@ void MinorMarkCompactCollector::MarkRootSetInParallel() {
static_cast<int>(heap()->new_space()->Capacity()) / Page::kPageSize;
const int num_tasks = NumberOfParallelMarkingTasks(new_space_pages);
for (int i = 0; i < num_tasks; i++) {
job.AddTask(new YoungGenerationMarkingTask(isolate(), this,
marking_deque(), i));
job.AddTask(
new YoungGenerationMarkingTask(isolate(), this, worklist(), i));
}
job.Run();
DCHECK(marking_deque()->IsGlobalEmpty());
DCHECK(worklist()->IsGlobalEmpty());
}
}
old_to_new_slots_ = static_cast<int>(slots.Value());
@ -2640,9 +2639,9 @@ void MinorMarkCompactCollector::ProcessMarkingDeque() {
}
void MinorMarkCompactCollector::EmptyMarkingDeque() {
LocalWorkStealingBag local_marking_deque(marking_deque(), kMainMarker);
WorklistView worklist_view(worklist(), kMainMarker);
HeapObject* object = nullptr;
while (local_marking_deque.Pop(&object)) {
while (worklist_view.Pop(&object)) {
DCHECK(!object->IsFiller());
DCHECK(object->IsHeapObject());
DCHECK(heap()->Contains(object));
@ -2652,7 +2651,7 @@ void MinorMarkCompactCollector::EmptyMarkingDeque() {
object, marking_state(object))));
main_marking_visitor()->Visit(object);
}
DCHECK(local_marking_deque.IsLocalEmpty());
DCHECK(worklist_view.IsLocalEmpty());
}
void MinorMarkCompactCollector::CollectGarbage() {

View File

@ -23,14 +23,14 @@ namespace internal {
class EvacuationJobTraits;
class HeapObjectVisitor;
class ItemParallelJob;
class LocalWorkStealingBag;
class WorklistView;
class MarkCompactCollector;
class MinorMarkCompactCollector;
class MarkingVisitor;
class MigrationObserver;
class RecordMigratedSlotVisitor;
class ThreadLocalTop;
class WorkStealingBag;
class Worklist;
class YoungGenerationMarkingVisitor;
#ifdef V8_CONCURRENT_MARKING
@ -352,7 +352,7 @@ class MinorMarkCompactCollector final : public MarkCompactCollectorBase {
static const int kNumMarkers = 8;
static const int kMainMarker = 0;
inline WorkStealingBag* marking_deque() { return marking_deque_; }
inline Worklist* worklist() { return worklist_; }
inline YoungGenerationMarkingVisitor* main_marking_visitor() {
return main_marking_visitor_;
@ -372,7 +372,7 @@ class MinorMarkCompactCollector final : public MarkCompactCollectorBase {
int NumberOfParallelMarkingTasks(int pages);
WorkStealingBag* marking_deque_;
Worklist* worklist_;
YoungGenerationMarkingVisitor* main_marking_visitor_;
base::Semaphore page_parallel_job_semaphore_;
List<Page*> new_space_evacuation_pages_;

View File

@ -2,8 +2,8 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef V8_HEAP_WORKSTEALING_BAG_
#define V8_HEAP_WORKSTEALING_BAG_
#ifndef V8_HEAP_WORKLIST_
#define V8_HEAP_WORKLIST_
#include <cstddef>
#include <vector>
@ -18,26 +18,26 @@ namespace internal {
class HeapObject;
// A concurrent work stealing bag based on segments. Each tasks gets private
// A concurrent worklist based on segments. Each tasks gets private
// push and pop segments. Empty pop segments are swapped with their
// corresponding push segments. Full push segments are published to a global
// pool of segments and replaced with empty segments.
//
// Work stealing is best effort, i.e., there is no way to inform other tasks
// of the need of items.
class WorkStealingBag {
class Worklist {
public:
static const int kMaxNumTasks = 8;
static const int kSegmentCapacity = 64;
WorkStealingBag() {
Worklist() {
for (int i = 0; i < kMaxNumTasks; i++) {
private_push_segment_[i] = new Segment();
private_pop_segment_[i] = new Segment();
}
}
~WorkStealingBag() {
~Worklist() {
CHECK(IsGlobalEmpty());
for (int i = 0; i < kMaxNumTasks; i++) {
DCHECK_NOT_NULL(private_push_segment_[i]);
@ -90,14 +90,14 @@ class WorkStealingBag {
}
private:
FRIEND_TEST(WorkStealingBag, SegmentCreate);
FRIEND_TEST(WorkStealingBag, SegmentPush);
FRIEND_TEST(WorkStealingBag, SegmentPushPop);
FRIEND_TEST(WorkStealingBag, SegmentIsEmpty);
FRIEND_TEST(WorkStealingBag, SegmentIsFull);
FRIEND_TEST(WorkStealingBag, SegmentClear);
FRIEND_TEST(WorkStealingBag, SegmentFullPushFails);
FRIEND_TEST(WorkStealingBag, SegmentEmptyPopFails);
FRIEND_TEST(Worklist, SegmentCreate);
FRIEND_TEST(Worklist, SegmentPush);
FRIEND_TEST(Worklist, SegmentPushPop);
FRIEND_TEST(Worklist, SegmentIsEmpty);
FRIEND_TEST(Worklist, SegmentIsFull);
FRIEND_TEST(Worklist, SegmentClear);
FRIEND_TEST(Worklist, SegmentFullPushFails);
FRIEND_TEST(Worklist, SegmentEmptyPopFails);
class Segment {
public:
@ -154,26 +154,26 @@ class WorkStealingBag {
std::vector<Segment*> global_pool_;
};
class LocalWorkStealingBag {
class WorklistView {
public:
LocalWorkStealingBag(WorkStealingBag* bag, int task_id)
: bag_(bag), task_id_(task_id) {}
WorklistView(Worklist* worklist, int task_id)
: worklist_(worklist), task_id_(task_id) {}
// Pushes an object onto the bag.
bool Push(HeapObject* object) { return bag_->Push(task_id_, object); }
// Pushes an object onto the worklist.
bool Push(HeapObject* object) { return worklist_->Push(task_id_, object); }
// Pops an object from the bag.
bool Pop(HeapObject** object) { return bag_->Pop(task_id_, object); }
// Pops an object from the worklist.
bool Pop(HeapObject** object) { return worklist_->Pop(task_id_, object); }
// Returns true if the local portion of the bag is empty.
bool IsLocalEmpty() { return bag_->IsLocalEmpty(task_id_); }
// Returns true if the local portion of the worklist is empty.
bool IsLocalEmpty() { return worklist_->IsLocalEmpty(task_id_); }
// Returns true if the bag is empty. Can only be used from the main thread
// without concurrent access.
bool IsGlobalEmpty() { return bag_->IsGlobalEmpty(); }
// Returns true if the worklist is empty. Can only be used from the main
// thread without concurrent access.
bool IsGlobalEmpty() { return worklist_->IsGlobalEmpty(); }
private:
WorkStealingBag* bag_;
Worklist* worklist_;
int task_id_;
};

View File

@ -1107,7 +1107,7 @@
'heap/spaces.h',
'heap/store-buffer.cc',
'heap/store-buffer.h',
'heap/workstealing-bag.h',
'heap/worklist.h',
'intl.cc',
'intl.h',
'icu_util.cc',

View File

@ -113,7 +113,7 @@ v8_executable("unittests") {
"heap/slot-set-unittest.cc",
"heap/spaces-unittest.cc",
"heap/unmapper-unittest.cc",
"heap/workstealing-bag-unittest.cc",
"heap/worklist-unittest.cc",
"interpreter/bytecode-array-builder-unittest.cc",
"interpreter/bytecode-array-iterator-unittest.cc",
"interpreter/bytecode-array-random-iterator-unittest.cc",

View File

@ -0,0 +1,196 @@
// Copyright 2017 the V8 project authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "src/heap/worklist.h"
#include "test/unittests/test-utils.h"
namespace v8 {
namespace internal {
class HeapObject {};
TEST(Worklist, SegmentCreate) {
Worklist::Segment segment;
EXPECT_TRUE(segment.IsEmpty());
EXPECT_EQ(0u, segment.Size());
EXPECT_FALSE(segment.IsFull());
}
TEST(Worklist, SegmentPush) {
Worklist::Segment segment;
EXPECT_EQ(0u, segment.Size());
EXPECT_TRUE(segment.Push(nullptr));
EXPECT_EQ(1u, segment.Size());
}
TEST(Worklist, SegmentPushPop) {
Worklist::Segment segment;
EXPECT_TRUE(segment.Push(nullptr));
EXPECT_EQ(1u, segment.Size());
HeapObject dummy;
HeapObject* object = &dummy;
EXPECT_TRUE(segment.Pop(&object));
EXPECT_EQ(0u, segment.Size());
EXPECT_EQ(nullptr, object);
}
TEST(Worklist, SegmentIsEmpty) {
Worklist::Segment segment;
EXPECT_TRUE(segment.IsEmpty());
EXPECT_TRUE(segment.Push(nullptr));
EXPECT_FALSE(segment.IsEmpty());
}
TEST(Worklist, SegmentIsFull) {
Worklist::Segment segment;
EXPECT_FALSE(segment.IsFull());
for (size_t i = 0; i < Worklist::Segment::kCapacity; i++) {
EXPECT_TRUE(segment.Push(nullptr));
}
EXPECT_TRUE(segment.IsFull());
}
TEST(Worklist, SegmentClear) {
Worklist::Segment segment;
EXPECT_TRUE(segment.Push(nullptr));
EXPECT_FALSE(segment.IsEmpty());
segment.Clear();
EXPECT_TRUE(segment.IsEmpty());
for (size_t i = 0; i < Worklist::Segment::kCapacity; i++) {
EXPECT_TRUE(segment.Push(nullptr));
}
}
TEST(Worklist, SegmentFullPushFails) {
Worklist::Segment segment;
EXPECT_FALSE(segment.IsFull());
for (size_t i = 0; i < Worklist::Segment::kCapacity; i++) {
EXPECT_TRUE(segment.Push(nullptr));
}
EXPECT_TRUE(segment.IsFull());
EXPECT_FALSE(segment.Push(nullptr));
}
TEST(Worklist, SegmentEmptyPopFails) {
Worklist::Segment segment;
EXPECT_TRUE(segment.IsEmpty());
HeapObject* object;
EXPECT_FALSE(segment.Pop(&object));
}
TEST(Worklist, CreateEmpty) {
Worklist worklist;
WorklistView worklist_view(&worklist, 0);
EXPECT_TRUE(worklist_view.IsLocalEmpty());
EXPECT_TRUE(worklist.IsGlobalEmpty());
}
TEST(Worklist, LocalPushPop) {
Worklist worklist;
WorklistView worklist_view(&worklist, 0);
HeapObject dummy;
HeapObject* retrieved = nullptr;
EXPECT_TRUE(worklist_view.Push(&dummy));
EXPECT_FALSE(worklist_view.IsLocalEmpty());
EXPECT_TRUE(worklist_view.Pop(&retrieved));
EXPECT_EQ(&dummy, retrieved);
}
TEST(Worklist, LocalIsBasedOnId) {
Worklist worklist;
// Use the same id.
WorklistView worklist_view1(&worklist, 0);
WorklistView worklist_view2(&worklist, 0);
HeapObject dummy;
HeapObject* retrieved = nullptr;
EXPECT_TRUE(worklist_view1.Push(&dummy));
EXPECT_FALSE(worklist_view1.IsLocalEmpty());
EXPECT_FALSE(worklist_view2.IsLocalEmpty());
EXPECT_TRUE(worklist_view2.Pop(&retrieved));
EXPECT_EQ(&dummy, retrieved);
EXPECT_TRUE(worklist_view1.IsLocalEmpty());
EXPECT_TRUE(worklist_view2.IsLocalEmpty());
}
TEST(Worklist, LocalPushStaysPrivate) {
Worklist worklist;
WorklistView worklist_view1(&worklist, 0);
WorklistView worklist_view2(&worklist, 1);
HeapObject dummy;
HeapObject* retrieved = nullptr;
EXPECT_TRUE(worklist.IsGlobalEmpty());
EXPECT_TRUE(worklist_view1.Push(&dummy));
EXPECT_FALSE(worklist.IsGlobalEmpty());
EXPECT_FALSE(worklist_view2.Pop(&retrieved));
EXPECT_EQ(nullptr, retrieved);
EXPECT_TRUE(worklist_view1.Pop(&retrieved));
EXPECT_EQ(&dummy, retrieved);
EXPECT_TRUE(worklist.IsGlobalEmpty());
}
TEST(Worklist, SingleSegmentSteal) {
Worklist worklist;
WorklistView worklist_view1(&worklist, 0);
WorklistView worklist_view2(&worklist, 1);
HeapObject dummy;
for (size_t i = 0; i < Worklist::kSegmentCapacity; i++) {
EXPECT_TRUE(worklist_view1.Push(&dummy));
}
HeapObject* retrieved = nullptr;
// One more push/pop to publish the full segment.
EXPECT_TRUE(worklist_view1.Push(nullptr));
EXPECT_TRUE(worklist_view1.Pop(&retrieved));
EXPECT_EQ(nullptr, retrieved);
// Stealing.
for (size_t i = 0; i < Worklist::kSegmentCapacity; i++) {
EXPECT_TRUE(worklist_view2.Pop(&retrieved));
EXPECT_EQ(&dummy, retrieved);
EXPECT_FALSE(worklist_view1.Pop(&retrieved));
}
EXPECT_TRUE(worklist.IsGlobalEmpty());
}
TEST(Worklist, MultipleSegmentsStolen) {
Worklist worklist;
WorklistView worklist_view1(&worklist, 0);
WorklistView worklist_view2(&worklist, 1);
WorklistView worklist_view3(&worklist, 2);
HeapObject dummy1;
HeapObject dummy2;
for (size_t i = 0; i < Worklist::kSegmentCapacity; i++) {
EXPECT_TRUE(worklist_view1.Push(&dummy1));
}
for (size_t i = 0; i < Worklist::kSegmentCapacity; i++) {
EXPECT_TRUE(worklist_view1.Push(&dummy2));
}
HeapObject* retrieved = nullptr;
HeapObject dummy3;
// One more push/pop to publish the full segment.
EXPECT_TRUE(worklist_view1.Push(&dummy3));
EXPECT_TRUE(worklist_view1.Pop(&retrieved));
EXPECT_EQ(&dummy3, retrieved);
// Stealing.
EXPECT_TRUE(worklist_view2.Pop(&retrieved));
HeapObject* const expect_bag2 = retrieved;
EXPECT_TRUE(worklist_view3.Pop(&retrieved));
HeapObject* const expect_bag3 = retrieved;
EXPECT_NE(expect_bag2, expect_bag3);
EXPECT_TRUE(expect_bag2 == &dummy1 || expect_bag2 == &dummy2);
EXPECT_TRUE(expect_bag3 == &dummy1 || expect_bag3 == &dummy2);
for (size_t i = 1; i < Worklist::kSegmentCapacity; i++) {
EXPECT_TRUE(worklist_view2.Pop(&retrieved));
EXPECT_EQ(expect_bag2, retrieved);
EXPECT_FALSE(worklist_view1.Pop(&retrieved));
}
for (size_t i = 1; i < Worklist::kSegmentCapacity; i++) {
EXPECT_TRUE(worklist_view3.Pop(&retrieved));
EXPECT_EQ(expect_bag3, retrieved);
EXPECT_FALSE(worklist_view1.Pop(&retrieved));
}
EXPECT_TRUE(worklist.IsGlobalEmpty());
}
} // namespace internal
} // namespace v8

View File

@ -1,196 +0,0 @@
// Copyright 2017 the V8 project authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "src/heap/workstealing-bag.h"
#include "test/unittests/test-utils.h"
namespace v8 {
namespace internal {
class HeapObject {};
TEST(WorkStealingBag, SegmentCreate) {
WorkStealingBag::Segment segment;
EXPECT_TRUE(segment.IsEmpty());
EXPECT_EQ(0u, segment.Size());
EXPECT_FALSE(segment.IsFull());
}
TEST(WorkStealingBag, SegmentPush) {
WorkStealingBag::Segment segment;
EXPECT_EQ(0u, segment.Size());
EXPECT_TRUE(segment.Push(nullptr));
EXPECT_EQ(1u, segment.Size());
}
TEST(WorkStealingBag, SegmentPushPop) {
WorkStealingBag::Segment segment;
EXPECT_TRUE(segment.Push(nullptr));
EXPECT_EQ(1u, segment.Size());
HeapObject dummy;
HeapObject* object = &dummy;
EXPECT_TRUE(segment.Pop(&object));
EXPECT_EQ(0u, segment.Size());
EXPECT_EQ(nullptr, object);
}
TEST(WorkStealingBag, SegmentIsEmpty) {
WorkStealingBag::Segment segment;
EXPECT_TRUE(segment.IsEmpty());
EXPECT_TRUE(segment.Push(nullptr));
EXPECT_FALSE(segment.IsEmpty());
}
TEST(WorkStealingBag, SegmentIsFull) {
WorkStealingBag::Segment segment;
EXPECT_FALSE(segment.IsFull());
for (size_t i = 0; i < WorkStealingBag::Segment::kCapacity; i++) {
EXPECT_TRUE(segment.Push(nullptr));
}
EXPECT_TRUE(segment.IsFull());
}
TEST(WorkStealingBag, SegmentClear) {
WorkStealingBag::Segment segment;
EXPECT_TRUE(segment.Push(nullptr));
EXPECT_FALSE(segment.IsEmpty());
segment.Clear();
EXPECT_TRUE(segment.IsEmpty());
for (size_t i = 0; i < WorkStealingBag::Segment::kCapacity; i++) {
EXPECT_TRUE(segment.Push(nullptr));
}
}
TEST(WorkStealingBag, SegmentFullPushFails) {
WorkStealingBag::Segment segment;
EXPECT_FALSE(segment.IsFull());
for (size_t i = 0; i < WorkStealingBag::Segment::kCapacity; i++) {
EXPECT_TRUE(segment.Push(nullptr));
}
EXPECT_TRUE(segment.IsFull());
EXPECT_FALSE(segment.Push(nullptr));
}
TEST(WorkStealingBag, SegmentEmptyPopFails) {
WorkStealingBag::Segment segment;
EXPECT_TRUE(segment.IsEmpty());
HeapObject* object;
EXPECT_FALSE(segment.Pop(&object));
}
TEST(WorkStealingBag, CreateEmpty) {
WorkStealingBag marking_bag;
LocalWorkStealingBag local_marking_bag(&marking_bag, 0);
EXPECT_TRUE(local_marking_bag.IsLocalEmpty());
EXPECT_TRUE(marking_bag.IsGlobalEmpty());
}
TEST(WorkStealingBag, LocalPushPop) {
WorkStealingBag marking_bag;
LocalWorkStealingBag local_marking_bag(&marking_bag, 0);
HeapObject dummy;
HeapObject* retrieved = nullptr;
EXPECT_TRUE(local_marking_bag.Push(&dummy));
EXPECT_FALSE(local_marking_bag.IsLocalEmpty());
EXPECT_TRUE(local_marking_bag.Pop(&retrieved));
EXPECT_EQ(&dummy, retrieved);
}
TEST(WorkStealingBag, LocalIsBasedOnId) {
WorkStealingBag marking_bag;
// Use the same id.
LocalWorkStealingBag local_marking_bag1(&marking_bag, 0);
LocalWorkStealingBag local_marking_bag2(&marking_bag, 0);
HeapObject dummy;
HeapObject* retrieved = nullptr;
EXPECT_TRUE(local_marking_bag1.Push(&dummy));
EXPECT_FALSE(local_marking_bag1.IsLocalEmpty());
EXPECT_FALSE(local_marking_bag2.IsLocalEmpty());
EXPECT_TRUE(local_marking_bag2.Pop(&retrieved));
EXPECT_EQ(&dummy, retrieved);
EXPECT_TRUE(local_marking_bag1.IsLocalEmpty());
EXPECT_TRUE(local_marking_bag2.IsLocalEmpty());
}
TEST(WorkStealingBag, LocalPushStaysPrivate) {
WorkStealingBag marking_bag;
LocalWorkStealingBag local_marking_bag1(&marking_bag, 0);
LocalWorkStealingBag local_marking_bag2(&marking_bag, 1);
HeapObject dummy;
HeapObject* retrieved = nullptr;
EXPECT_TRUE(marking_bag.IsGlobalEmpty());
EXPECT_TRUE(local_marking_bag1.Push(&dummy));
EXPECT_FALSE(marking_bag.IsGlobalEmpty());
EXPECT_FALSE(local_marking_bag2.Pop(&retrieved));
EXPECT_EQ(nullptr, retrieved);
EXPECT_TRUE(local_marking_bag1.Pop(&retrieved));
EXPECT_EQ(&dummy, retrieved);
EXPECT_TRUE(marking_bag.IsGlobalEmpty());
}
TEST(WorkStealingBag, SingleSegmentSteal) {
WorkStealingBag marking_bag;
LocalWorkStealingBag local_marking_bag1(&marking_bag, 0);
LocalWorkStealingBag local_marking_bag2(&marking_bag, 1);
HeapObject dummy;
for (size_t i = 0; i < WorkStealingBag::kSegmentCapacity; i++) {
EXPECT_TRUE(local_marking_bag1.Push(&dummy));
}
HeapObject* retrieved = nullptr;
// One more push/pop to publish the full segment.
EXPECT_TRUE(local_marking_bag1.Push(nullptr));
EXPECT_TRUE(local_marking_bag1.Pop(&retrieved));
EXPECT_EQ(nullptr, retrieved);
// Stealing.
for (size_t i = 0; i < WorkStealingBag::kSegmentCapacity; i++) {
EXPECT_TRUE(local_marking_bag2.Pop(&retrieved));
EXPECT_EQ(&dummy, retrieved);
EXPECT_FALSE(local_marking_bag1.Pop(&retrieved));
}
EXPECT_TRUE(marking_bag.IsGlobalEmpty());
}
TEST(WorkStealingBag, MultipleSegmentsStolen) {
WorkStealingBag marking_bag;
LocalWorkStealingBag local_marking_bag1(&marking_bag, 0);
LocalWorkStealingBag local_marking_bag2(&marking_bag, 1);
LocalWorkStealingBag local_marking_bag3(&marking_bag, 2);
HeapObject dummy1;
HeapObject dummy2;
for (size_t i = 0; i < WorkStealingBag::kSegmentCapacity; i++) {
EXPECT_TRUE(local_marking_bag1.Push(&dummy1));
}
for (size_t i = 0; i < WorkStealingBag::kSegmentCapacity; i++) {
EXPECT_TRUE(local_marking_bag1.Push(&dummy2));
}
HeapObject* retrieved = nullptr;
HeapObject dummy3;
// One more push/pop to publish the full segment.
EXPECT_TRUE(local_marking_bag1.Push(&dummy3));
EXPECT_TRUE(local_marking_bag1.Pop(&retrieved));
EXPECT_EQ(&dummy3, retrieved);
// Stealing.
EXPECT_TRUE(local_marking_bag2.Pop(&retrieved));
HeapObject* const expect_bag2 = retrieved;
EXPECT_TRUE(local_marking_bag3.Pop(&retrieved));
HeapObject* const expect_bag3 = retrieved;
EXPECT_NE(expect_bag2, expect_bag3);
EXPECT_TRUE(expect_bag2 == &dummy1 || expect_bag2 == &dummy2);
EXPECT_TRUE(expect_bag3 == &dummy1 || expect_bag3 == &dummy2);
for (size_t i = 1; i < WorkStealingBag::kSegmentCapacity; i++) {
EXPECT_TRUE(local_marking_bag2.Pop(&retrieved));
EXPECT_EQ(expect_bag2, retrieved);
EXPECT_FALSE(local_marking_bag1.Pop(&retrieved));
}
for (size_t i = 1; i < WorkStealingBag::kSegmentCapacity; i++) {
EXPECT_TRUE(local_marking_bag3.Pop(&retrieved));
EXPECT_EQ(expect_bag3, retrieved);
EXPECT_FALSE(local_marking_bag1.Pop(&retrieved));
}
EXPECT_TRUE(marking_bag.IsGlobalEmpty());
}
} // namespace internal
} // namespace v8

View File

@ -110,7 +110,7 @@
'heap/slot-set-unittest.cc',
'heap/spaces-unittest.cc',
'heap/unmapper-unittest.cc',
'heap/workstealing-bag-unittest.cc',
'heap/worklist-unittest.cc',
'interpreter/bytecodes-unittest.cc',
'interpreter/bytecode-array-builder-unittest.cc',
'interpreter/bytecode-array-iterator-unittest.cc',