diff --git a/BUILD.gn b/BUILD.gn index 26a1c73da0..4793cda273 100644 --- a/BUILD.gn +++ b/BUILD.gn @@ -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", diff --git a/src/heap/mark-compact.cc b/src/heap/mark-compact.cc index ed87177792..de7ffe09fd 100644 --- a/src/heap/mark-compact.cc +++ b/src/heap/mark-compact.cc @@ -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(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 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(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(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() { diff --git a/src/heap/mark-compact.h b/src/heap/mark-compact.h index 811c4e9eb2..4c29471ec1 100644 --- a/src/heap/mark-compact.h +++ b/src/heap/mark-compact.h @@ -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 new_space_evacuation_pages_; diff --git a/src/heap/workstealing-bag.h b/src/heap/worklist.h similarity index 76% rename from src/heap/workstealing-bag.h rename to src/heap/worklist.h index 3f2e55ab45..e6a7bd3d9d 100644 --- a/src/heap/workstealing-bag.h +++ b/src/heap/worklist.h @@ -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 #include @@ -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 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_; }; diff --git a/src/v8.gyp b/src/v8.gyp index b1b66dd46d..a07fc96060 100644 --- a/src/v8.gyp +++ b/src/v8.gyp @@ -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', diff --git a/test/unittests/BUILD.gn b/test/unittests/BUILD.gn index dce372164e..3dba3da77e 100644 --- a/test/unittests/BUILD.gn +++ b/test/unittests/BUILD.gn @@ -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", diff --git a/test/unittests/heap/worklist-unittest.cc b/test/unittests/heap/worklist-unittest.cc new file mode 100644 index 0000000000..51317eb063 --- /dev/null +++ b/test/unittests/heap/worklist-unittest.cc @@ -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 diff --git a/test/unittests/heap/workstealing-bag-unittest.cc b/test/unittests/heap/workstealing-bag-unittest.cc deleted file mode 100644 index e5f8e626f9..0000000000 --- a/test/unittests/heap/workstealing-bag-unittest.cc +++ /dev/null @@ -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 diff --git a/test/unittests/unittests.gyp b/test/unittests/unittests.gyp index 12d1ea0df7..a1b88dbc9d 100644 --- a/test/unittests/unittests.gyp +++ b/test/unittests/unittests.gyp @@ -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',