diff options
Diffstat (limited to 'deps/v8/test/unittests/heap/base/worklist-unittest.cc')
-rw-r--r-- | deps/v8/test/unittests/heap/base/worklist-unittest.cc | 311 |
1 files changed, 311 insertions, 0 deletions
diff --git a/deps/v8/test/unittests/heap/base/worklist-unittest.cc b/deps/v8/test/unittests/heap/base/worklist-unittest.cc new file mode 100644 index 0000000000..ae737a7aa3 --- /dev/null +++ b/deps/v8/test/unittests/heap/base/worklist-unittest.cc @@ -0,0 +1,311 @@ +// Copyright 2020 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/base/worklist.h" + +#include "testing/gtest/include/gtest/gtest.h" + +namespace heap { +namespace base { + +class SomeObject {}; + +using TestWorklist = Worklist<SomeObject*, 64>; + +TEST(CppgcWorkListTest, SegmentCreate) { + TestWorklist::Segment segment; + EXPECT_TRUE(segment.IsEmpty()); + EXPECT_EQ(0u, segment.Size()); + EXPECT_FALSE(segment.IsFull()); +} + +TEST(CppgcWorkListTest, SegmentPush) { + TestWorklist::Segment segment; + EXPECT_EQ(0u, segment.Size()); + segment.Push(nullptr); + EXPECT_EQ(1u, segment.Size()); +} + +TEST(CppgcWorkListTest, SegmentPushPop) { + TestWorklist::Segment segment; + segment.Push(nullptr); + EXPECT_EQ(1u, segment.Size()); + SomeObject dummy; + SomeObject* object = &dummy; + segment.Pop(&object); + EXPECT_EQ(0u, segment.Size()); + EXPECT_EQ(nullptr, object); +} + +TEST(CppgcWorkListTest, SegmentIsEmpty) { + TestWorklist::Segment segment; + EXPECT_TRUE(segment.IsEmpty()); + segment.Push(nullptr); + EXPECT_FALSE(segment.IsEmpty()); +} + +TEST(CppgcWorkListTest, SegmentIsFull) { + TestWorklist::Segment segment; + EXPECT_FALSE(segment.IsFull()); + for (size_t i = 0; i < TestWorklist::Segment::kSize; i++) { + segment.Push(nullptr); + } + EXPECT_TRUE(segment.IsFull()); +} + +TEST(CppgcWorkListTest, SegmentClear) { + TestWorklist::Segment segment; + segment.Push(nullptr); + EXPECT_FALSE(segment.IsEmpty()); + segment.Clear(); + EXPECT_TRUE(segment.IsEmpty()); + for (size_t i = 0; i < TestWorklist::Segment::kSize; i++) { + segment.Push(nullptr); + } +} + +TEST(CppgcWorkListTest, SegmentUpdateFalse) { + TestWorklist::Segment segment; + SomeObject* object; + object = reinterpret_cast<SomeObject*>(&object); + segment.Push(object); + segment.Update([](SomeObject* object, SomeObject** out) { return false; }); + EXPECT_TRUE(segment.IsEmpty()); +} + +TEST(CppgcWorkListTest, SegmentUpdate) { + TestWorklist::Segment segment; + SomeObject* objectA; + objectA = reinterpret_cast<SomeObject*>(&objectA); + SomeObject* objectB; + objectB = reinterpret_cast<SomeObject*>(&objectB); + segment.Push(objectA); + segment.Update([objectB](SomeObject* object, SomeObject** out) { + *out = objectB; + return true; + }); + SomeObject* object; + segment.Pop(&object); + EXPECT_EQ(object, objectB); +} + +TEST(CppgcWorkListTest, CreateEmpty) { + TestWorklist worklist; + TestWorklist::Local worklist_local(&worklist); + EXPECT_TRUE(worklist_local.IsLocalEmpty()); + EXPECT_TRUE(worklist.IsEmpty()); +} + +TEST(CppgcWorkListTest, LocalPushPop) { + TestWorklist worklist; + TestWorklist::Local worklist_local(&worklist); + SomeObject dummy; + SomeObject* retrieved = nullptr; + worklist_local.Push(&dummy); + EXPECT_FALSE(worklist_local.IsLocalEmpty()); + EXPECT_TRUE(worklist_local.Pop(&retrieved)); + EXPECT_EQ(&dummy, retrieved); +} + +TEST(CppgcWorkListTest, LocalPushStaysPrivate) { + TestWorklist worklist; + TestWorklist::Local worklist_view1(&worklist); + TestWorklist::Local worklist_view2(&worklist); + SomeObject dummy; + SomeObject* retrieved = nullptr; + EXPECT_TRUE(worklist.IsEmpty()); + EXPECT_EQ(0U, worklist.Size()); + worklist_view1.Push(&dummy); + EXPECT_EQ(0U, worklist.Size()); + EXPECT_FALSE(worklist_view2.Pop(&retrieved)); + EXPECT_EQ(nullptr, retrieved); + EXPECT_TRUE(worklist_view1.Pop(&retrieved)); + EXPECT_EQ(&dummy, retrieved); + EXPECT_EQ(0U, worklist.Size()); +} + +TEST(CppgcWorkListTest, GlobalUpdateNull) { + TestWorklist worklist; + TestWorklist::Local worklist_local(&worklist); + SomeObject* object; + object = reinterpret_cast<SomeObject*>(&object); + for (size_t i = 0; i < TestWorklist::kSegmentSize; i++) { + worklist_local.Push(object); + } + worklist_local.Push(object); + worklist_local.Publish(); + worklist.Update([](SomeObject* object, SomeObject** out) { return false; }); + EXPECT_TRUE(worklist.IsEmpty()); + EXPECT_EQ(0U, worklist.Size()); +} + +TEST(CppgcWorkListTest, GlobalUpdate) { + TestWorklist worklist; + TestWorklist::Local worklist_local(&worklist); + SomeObject* objectA = nullptr; + objectA = reinterpret_cast<SomeObject*>(&objectA); + SomeObject* objectB = nullptr; + objectB = reinterpret_cast<SomeObject*>(&objectB); + SomeObject* objectC = nullptr; + objectC = reinterpret_cast<SomeObject*>(&objectC); + for (size_t i = 0; i < TestWorklist::kSegmentSize; i++) { + worklist_local.Push(objectA); + } + for (size_t i = 0; i < TestWorklist::kSegmentSize; i++) { + worklist_local.Push(objectB); + } + worklist_local.Push(objectA); + worklist_local.Publish(); + worklist.Update([objectA, objectC](SomeObject* object, SomeObject** out) { + if (object != objectA) { + *out = objectC; + return true; + } + return false; + }); + for (size_t i = 0; i < TestWorklist::kSegmentSize; i++) { + SomeObject* object; + EXPECT_TRUE(worklist_local.Pop(&object)); + EXPECT_EQ(object, objectC); + } +} + +TEST(CppgcWorkListTest, FlushToGlobalPushSegment) { + TestWorklist worklist; + TestWorklist::Local worklist_local0(&worklist); + TestWorklist::Local worklist_local1(&worklist); + SomeObject* object = nullptr; + SomeObject* objectA = nullptr; + objectA = reinterpret_cast<SomeObject*>(&objectA); + worklist_local0.Push(objectA); + worklist_local0.Publish(); + EXPECT_EQ(1U, worklist.Size()); + EXPECT_TRUE(worklist_local1.Pop(&object)); +} + +TEST(CppgcWorkListTest, FlushToGlobalPopSegment) { + TestWorklist worklist; + TestWorklist::Local worklist_local0(&worklist); + TestWorklist::Local worklist_local1(&worklist); + SomeObject* object = nullptr; + SomeObject* objectA = nullptr; + objectA = reinterpret_cast<SomeObject*>(&objectA); + worklist_local0.Push(objectA); + worklist_local0.Push(objectA); + worklist_local0.Pop(&object); + worklist_local0.Publish(); + EXPECT_EQ(1U, worklist.Size()); + EXPECT_TRUE(worklist_local1.Pop(&object)); +} + +TEST(CppgcWorkListTest, Clear) { + TestWorklist worklist; + TestWorklist::Local worklist_local(&worklist); + SomeObject* object; + object = reinterpret_cast<SomeObject*>(&object); + worklist_local.Push(object); + worklist_local.Publish(); + EXPECT_EQ(1U, worklist.Size()); + worklist.Clear(); + EXPECT_TRUE(worklist.IsEmpty()); + EXPECT_EQ(0U, worklist.Size()); +} + +TEST(CppgcWorkListTest, SingleSegmentSteal) { + TestWorklist worklist; + TestWorklist::Local worklist_local1(&worklist); + TestWorklist::Local worklist_local2(&worklist); + SomeObject dummy; + for (size_t i = 0; i < TestWorklist::kSegmentSize; i++) { + worklist_local1.Push(&dummy); + } + SomeObject* retrieved = nullptr; + // One more push/pop to publish the full segment. + worklist_local1.Push(nullptr); + EXPECT_TRUE(worklist_local1.Pop(&retrieved)); + EXPECT_EQ(nullptr, retrieved); + EXPECT_EQ(1U, worklist.Size()); + // Stealing. + for (size_t i = 0; i < TestWorklist::kSegmentSize; i++) { + EXPECT_TRUE(worklist_local2.Pop(&retrieved)); + EXPECT_EQ(&dummy, retrieved); + EXPECT_FALSE(worklist_local1.Pop(&retrieved)); + } + EXPECT_TRUE(worklist.IsEmpty()); + EXPECT_EQ(0U, worklist.Size()); +} + +TEST(CppgcWorkListTest, MultipleSegmentsStolen) { + TestWorklist worklist; + TestWorklist::Local worklist_local1(&worklist); + TestWorklist::Local worklist_local2(&worklist); + TestWorklist::Local worklist_local3(&worklist); + SomeObject dummy1; + SomeObject dummy2; + for (size_t i = 0; i < TestWorklist::kSegmentSize; i++) { + worklist_local1.Push(&dummy1); + } + for (size_t i = 0; i < TestWorklist::kSegmentSize; i++) { + worklist_local1.Push(&dummy2); + } + SomeObject* retrieved = nullptr; + SomeObject dummy3; + // One more push/pop to publish the full segment. + worklist_local1.Push(&dummy3); + EXPECT_TRUE(worklist_local1.Pop(&retrieved)); + EXPECT_EQ(&dummy3, retrieved); + EXPECT_EQ(2U, worklist.Size()); + // Stealing. + EXPECT_TRUE(worklist_local2.Pop(&retrieved)); + SomeObject* const expect_bag2 = retrieved; + EXPECT_TRUE(worklist_local3.Pop(&retrieved)); + SomeObject* const expect_bag3 = retrieved; + EXPECT_EQ(0U, worklist.Size()); + 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 < TestWorklist::kSegmentSize; i++) { + EXPECT_TRUE(worklist_local2.Pop(&retrieved)); + EXPECT_EQ(expect_bag2, retrieved); + EXPECT_FALSE(worklist_local1.Pop(&retrieved)); + } + for (size_t i = 1; i < TestWorklist::kSegmentSize; i++) { + EXPECT_TRUE(worklist_local3.Pop(&retrieved)); + EXPECT_EQ(expect_bag3, retrieved); + EXPECT_FALSE(worklist_local1.Pop(&retrieved)); + } + EXPECT_TRUE(worklist.IsEmpty()); +} + +TEST(CppgcWorkListTest, MergeGlobalPool) { + TestWorklist worklist1; + TestWorklist::Local worklist_local1(&worklist1); + SomeObject dummy; + for (size_t i = 0; i < TestWorklist::kSegmentSize; i++) { + worklist_local1.Push(&dummy); + } + SomeObject* retrieved = nullptr; + // One more push/pop to publish the full segment. + worklist_local1.Push(nullptr); + EXPECT_TRUE(worklist_local1.Pop(&retrieved)); + EXPECT_EQ(nullptr, retrieved); + EXPECT_EQ(1U, worklist1.Size()); + // Merging global pool into a new Worklist. + TestWorklist worklist2; + TestWorklist::Local worklist_local2(&worklist2); + EXPECT_EQ(0U, worklist2.Size()); + worklist2.Merge(&worklist1); + EXPECT_EQ(1U, worklist2.Size()); + EXPECT_FALSE(worklist2.IsEmpty()); + for (size_t i = 0; i < TestWorklist::kSegmentSize; i++) { + EXPECT_TRUE(worklist_local2.Pop(&retrieved)); + EXPECT_EQ(&dummy, retrieved); + EXPECT_FALSE(worklist_local1.Pop(&retrieved)); + } + EXPECT_TRUE(worklist1.IsEmpty()); + EXPECT_TRUE(worklist2.IsEmpty()); +} + +} // namespace base +} // namespace heap |