summaryrefslogtreecommitdiff
path: root/deps/v8/src/heap/workstealing-marking-deque.h
diff options
context:
space:
mode:
Diffstat (limited to 'deps/v8/src/heap/workstealing-marking-deque.h')
-rw-r--r--deps/v8/src/heap/workstealing-marking-deque.h167
1 files changed, 167 insertions, 0 deletions
diff --git a/deps/v8/src/heap/workstealing-marking-deque.h b/deps/v8/src/heap/workstealing-marking-deque.h
new file mode 100644
index 0000000000..1a3dc865e4
--- /dev/null
+++ b/deps/v8/src/heap/workstealing-marking-deque.h
@@ -0,0 +1,167 @@
+// 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.
+
+#ifndef V8_HEAP_WORKSTEALING_MARKING_DEQUE_
+#define V8_HEAP_WORKSTEALING_MARKING_DEQUE_
+
+#include <cstddef>
+
+#include "src/base/logging.h"
+#include "src/base/macros.h"
+
+namespace v8 {
+namespace internal {
+
+class HeapObject;
+
+class StackSegment {
+ public:
+ static const int kNumEntries = 64;
+
+ StackSegment(StackSegment* next, StackSegment* prev)
+ : next_(next), prev_(prev), index_(0) {}
+
+ bool Push(HeapObject* object) {
+ if (IsFull()) return false;
+
+ objects_[index_++] = object;
+ return true;
+ }
+
+ bool Pop(HeapObject** object) {
+ if (IsEmpty()) return false;
+
+ *object = objects_[--index_];
+ return true;
+ }
+
+ size_t Size() { return index_; }
+ bool IsEmpty() { return index_ == 0; }
+ bool IsFull() { return index_ == kNumEntries; }
+ void Clear() { index_ = 0; }
+
+ StackSegment* next() { return next_; }
+ StackSegment* prev() { return prev_; }
+ void set_next(StackSegment* next) { next_ = next; }
+ void set_prev(StackSegment* prev) { prev_ = prev; }
+
+ void Unlink() {
+ if (next() != nullptr) next()->set_prev(prev());
+ if (prev() != nullptr) prev()->set_next(next());
+ }
+
+ private:
+ StackSegment* next_;
+ StackSegment* prev_;
+ size_t index_;
+ HeapObject* objects_[kNumEntries];
+};
+
+class SegmentedStack {
+ public:
+ SegmentedStack()
+ : front_(new StackSegment(nullptr, nullptr)), back_(front_) {}
+
+ ~SegmentedStack() {
+ CHECK(IsEmpty());
+ delete front_;
+ }
+
+ bool Push(HeapObject* object) {
+ if (!front_->Push(object)) {
+ NewFront();
+ bool success = front_->Push(object);
+ USE(success);
+ DCHECK(success);
+ }
+ return true;
+ }
+
+ bool Pop(HeapObject** object) {
+ if (!front_->Pop(object)) {
+ if (IsEmpty()) return false;
+ DeleteFront();
+ bool success = front_->Pop(object);
+ USE(success);
+ DCHECK(success);
+ }
+ return object;
+ }
+
+ bool IsEmpty() { return front_ == back_ && front_->IsEmpty(); }
+
+ private:
+ void NewFront() {
+ StackSegment* s = new StackSegment(front_, nullptr);
+ front_->set_prev(s);
+ front_ = s;
+ }
+
+ void DeleteFront() { delete Unlink(front_); }
+
+ StackSegment* Unlink(StackSegment* segment) {
+ CHECK_NE(front_, back_);
+ if (segment == front_) front_ = front_->next();
+ if (segment == back_) back_ = back_->prev();
+ segment->Unlink();
+ return segment;
+ }
+
+ StackSegment* front_;
+ StackSegment* back_;
+};
+
+// TODO(mlippautz): Implement actual work stealing.
+class WorkStealingMarkingDeque {
+ public:
+ static const int kMaxNumTasks = 4;
+
+ bool Push(int task_id, HeapObject* object) {
+ DCHECK_LT(task_id, kMaxNumTasks);
+ return private_stacks_[task_id].Push(object);
+ }
+
+ bool Pop(int task_id, HeapObject** object) {
+ DCHECK_LT(task_id, kMaxNumTasks);
+ return private_stacks_[task_id].Pop(object);
+ }
+
+ bool IsLocalEmpty(int task_id) { return private_stacks_[task_id].IsEmpty(); }
+
+ private:
+ SegmentedStack private_stacks_[kMaxNumTasks];
+};
+
+class LocalWorkStealingMarkingDeque {
+ public:
+ LocalWorkStealingMarkingDeque(WorkStealingMarkingDeque* deque, int task_id)
+ : deque_(deque), task_id_(task_id) {}
+
+ // Pushes an object onto the marking deque.
+ bool Push(HeapObject* object) { return deque_->Push(task_id_, object); }
+
+ // Pops an object onto the marking deque.
+ bool Pop(HeapObject** object) { return deque_->Pop(task_id_, object); }
+
+ // Returns true if the local portion of the marking deque is empty.
+ bool IsEmpty() { return deque_->IsLocalEmpty(task_id_); }
+
+ // Blocks if there are no more objects available. Returns execution with
+ // |true| once new objects are available and |false| otherwise.
+ bool WaitForMoreObjects() {
+ // Return false once the local portion of the marking deque is drained.
+ // TODO(mlippautz): Implement a barrier that can be used to synchronize
+ // work stealing and emptiness.
+ return !IsEmpty();
+ }
+
+ private:
+ WorkStealingMarkingDeque* deque_;
+ int task_id_;
+};
+
+} // namespace internal
+} // namespace v8
+
+#endif // V8_HEAP_WORKSTEALING_MARKING_DEQUE_