Commit 7dc3b0b8 authored by Ulan Degenbaev's avatar Ulan Degenbaev Committed by Commit Bot

[heap] Support clear and update operation in worklist.

BUG=chromium:694255

Change-Id: Ie4f14e62afa63339c586c3872d6acfa2bf4833d8
Reviewed-on: https://chromium-review.googlesource.com/545717Reviewed-by: 's avatarMichael Lippautz <mlippautz@chromium.org>
Commit-Queue: Ulan Degenbaev <ulan@chromium.org>
Cr-Commit-Position: refs/heads/master@{#46207}
parent 13dc483c
......@@ -89,6 +89,46 @@ class Worklist {
return global_pool_.empty();
}
size_t LocalSize(int task_id) {
return private_pop_segment_[task_id]->Size() +
private_push_segment_[task_id]->Size();
}
// Clears all segments. Frees the global segment pool.
// This function assumes that other tasks are not running.
void Clear() {
for (int i = 0; i < kMaxNumTasks; i++) {
private_pop_segment_[i]->Clear();
private_push_segment_[i]->Clear();
}
for (Segment* segment : global_pool_) {
delete segment;
}
global_pool_.clear();
}
// Calls the specified callback on each element of the deques and replaces
// the element with the result of the callback. If the callback returns
// nullptr then the element is removed from the worklist.
// The callback must accept HeapObject* and return HeapObject*.
// This function assumes that other tasks are not running.
template <typename Callback>
void Update(Callback callback) {
for (int i = 0; i < kMaxNumTasks; i++) {
private_pop_segment_[i]->Update(callback);
private_push_segment_[i]->Update(callback);
}
for (size_t i = 0; i < global_pool_.size(); i++) {
Segment* segment = global_pool_[i];
segment->Update(callback);
if (segment->IsEmpty()) {
global_pool_[i] = global_pool_.back();
global_pool_.pop_back();
delete segment;
}
}
}
private:
FRIEND_TEST(Worklist, SegmentCreate);
FRIEND_TEST(Worklist, SegmentPush);
......@@ -98,6 +138,8 @@ class Worklist {
FRIEND_TEST(Worklist, SegmentClear);
FRIEND_TEST(Worklist, SegmentFullPushFails);
FRIEND_TEST(Worklist, SegmentEmptyPopFails);
FRIEND_TEST(Worklist, SegmentUpdateNull);
FRIEND_TEST(Worklist, SegmentUpdate);
class Segment {
public:
......@@ -124,6 +166,18 @@ class Worklist {
bool IsFull() { return index_ == kCapacity; }
void Clear() { index_ = 0; }
template <typename Callback>
void Update(Callback callback) {
size_t new_index = 0;
for (size_t i = 0; i < index_; i++) {
HeapObject* object = callback(objects_[i]);
if (object) {
objects_[new_index++] = object;
}
}
index_ = new_index;
}
private:
size_t index_;
HeapObject* objects_[kCapacity];
......@@ -135,8 +189,10 @@ class Worklist {
V8_NOINLINE void PublishPushSegmentToGlobal(int task_id) {
base::LockGuard<base::Mutex> guard(&lock_);
global_pool_.push_back(private_push_segment_[task_id]);
private_push_segment_[task_id] = new Segment();
if (!private_push_segment_[task_id]->IsEmpty()) {
global_pool_.push_back(private_push_segment_[task_id]);
private_push_segment_[task_id] = new Segment();
}
}
V8_NOINLINE bool StealPopSegmentFromGlobal(int task_id) {
......
......@@ -80,6 +80,28 @@ TEST(Worklist, SegmentEmptyPopFails) {
EXPECT_FALSE(segment.Pop(&object));
}
TEST(Worklist, SegmentUpdateNull) {
Worklist::Segment segment;
HeapObject* object;
object = reinterpret_cast<HeapObject*>(&object);
EXPECT_TRUE(segment.Push(object));
segment.Update([](HeapObject* object) { return nullptr; });
EXPECT_TRUE(segment.IsEmpty());
}
TEST(Worklist, SegmentUpdate) {
Worklist::Segment segment;
HeapObject* objectA;
objectA = reinterpret_cast<HeapObject*>(&objectA);
HeapObject* objectB;
objectB = reinterpret_cast<HeapObject*>(&objectB);
EXPECT_TRUE(segment.Push(objectA));
segment.Update([objectB](HeapObject* object) { return objectB; });
HeapObject* object;
EXPECT_TRUE(segment.Pop(&object));
EXPECT_EQ(object, objectB);
}
TEST(Worklist, CreateEmpty) {
Worklist worklist;
WorklistView worklist_view(&worklist, 0);
......@@ -130,6 +152,51 @@ TEST(Worklist, LocalPushStaysPrivate) {
EXPECT_TRUE(worklist.IsGlobalEmpty());
}
TEST(Worklist, GlobalUpdateNull) {
Worklist worklist;
WorklistView worklist_view(&worklist, 0);
HeapObject* object;
object = reinterpret_cast<HeapObject*>(&object);
for (size_t i = 0; i < Worklist::kSegmentCapacity; i++) {
EXPECT_TRUE(worklist_view.Push(object));
}
EXPECT_TRUE(worklist_view.Push(object));
worklist.Update([](HeapObject* object) { return nullptr; });
EXPECT_TRUE(worklist.IsGlobalEmpty());
}
TEST(Worklist, GlobalUpdate) {
Worklist worklist;
WorklistView worklist_view(&worklist, 0);
HeapObject* objectA;
objectA = reinterpret_cast<HeapObject*>(&objectA);
HeapObject* objectB;
objectB = reinterpret_cast<HeapObject*>(&objectB);
for (size_t i = 0; i < Worklist::kSegmentCapacity; i++) {
EXPECT_TRUE(worklist_view.Push(objectA));
}
EXPECT_TRUE(worklist_view.Push(objectA));
worklist.Update([objectB](HeapObject* object) { return objectB; });
for (size_t i = 0; i < Worklist::kSegmentCapacity + 1; i++) {
HeapObject* object;
EXPECT_TRUE(worklist_view.Pop(&object));
EXPECT_EQ(object, objectB);
}
}
TEST(Worklist, Clear) {
Worklist worklist;
WorklistView worklist_view(&worklist, 0);
HeapObject* object;
object = reinterpret_cast<HeapObject*>(&object);
for (size_t i = 0; i < Worklist::kSegmentCapacity; i++) {
EXPECT_TRUE(worklist_view.Push(object));
}
EXPECT_TRUE(worklist_view.Push(object));
worklist.Clear();
EXPECT_TRUE(worklist.IsGlobalEmpty());
}
TEST(Worklist, SingleSegmentSteal) {
Worklist worklist;
WorklistView worklist_view1(&worklist, 0);
......
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