Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(87)

Side by Side Diff: src/heap/concurrent-marking-deque.h

Issue 2810893002: [heap] Implement simple concurrent marking deque. (Closed)
Patch Set: Fix comment Created 3 years, 7 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
« no previous file with comments | « src/heap/concurrent-marking.cc ('k') | src/heap/heap.cc » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
(Empty)
1 // Copyright 2017 the V8 project authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4
5 #ifndef V8_HEAP_CONCURRENT_MARKING_DEQUE_
6 #define V8_HEAP_CONCURRENT_MARKING_DEQUE_
7
8 #include <deque>
9
10 #include "src/base/platform/mutex.h"
11
12 namespace v8 {
13 namespace internal {
14
15 class Heap;
16 class Isolate;
17 class HeapObject;
18
19 enum class MarkingThread { kMain, kConcurrent };
20
21 enum class TargetDeque { kShared, kBailout };
22
23 // The concurrent marking deque supports deque operations for two threads:
24 // main and concurrent. It is implemented using two deques: shared and bailout.
25 //
26 // The concurrent thread can use the push and pop operations with the
27 // MarkingThread::kConcurrent argument. All other operations are intended
28 // to be used by the main thread only.
29 //
30 // The interface of the concurrent marking deque for the main thread matches
31 // that of the sequential marking deque, so they can be easily switched
32 // at compile time without updating the main thread call-sites.
33 //
34 // The shared deque is shared between the main thread and the concurrent
35 // thread, so both threads can push to and pop from the shared deque.
36 // The bailout deque stores objects that cannot be processed by the concurrent
37 // thread. Only the concurrent thread can push to it and only the main thread
38 // can pop from it.
39 class ConcurrentMarkingDeque {
40 public:
41 // The heap parameter is needed to match the interface
42 // of the sequential marking deque.
43 explicit ConcurrentMarkingDeque(Heap* heap) {}
44
45 // Pushes the object into the specified deque assuming that the function is
46 // called on the specified thread. The main thread can push only to the shared
47 // deque. The concurrent thread can push to both deques.
48 bool Push(HeapObject* object, MarkingThread thread = MarkingThread::kMain,
49 TargetDeque target = TargetDeque::kShared) {
50 DCHECK_IMPLIES(thread == MarkingThread::kMain,
51 target == TargetDeque::kShared);
52 switch (target) {
53 case TargetDeque::kShared:
54 shared_deque_.Push(object);
55 break;
56 case TargetDeque::kBailout:
57 bailout_deque_.Push(object);
58 break;
59 }
60 return true;
61 }
62
63 // Pops an object from the bailout or shared deque assuming that the function
64 // is called on the specified thread. The main thread first tries to pop the
65 // bailout deque. If the deque is empty then it tries the shared deque.
66 // If the shared deque is also empty, then the function returns nullptr.
67 // The concurrent thread pops only from the shared deque.
68 HeapObject* Pop(MarkingThread thread = MarkingThread::kMain) {
69 if (thread == MarkingThread::kMain) {
70 HeapObject* result = bailout_deque_.Pop();
71 if (result != nullptr) return result;
72 }
73 return shared_deque_.Pop();
74 }
75
76 // All the following operations can used only by the main thread.
77 void Clear() {
78 bailout_deque_.Clear();
79 shared_deque_.Clear();
80 }
81
82 bool IsFull() { return false; }
83
84 bool IsEmpty() { return bailout_deque_.IsEmpty() && shared_deque_.IsEmpty(); }
85
86 int Size() { return bailout_deque_.Size() + shared_deque_.Size(); }
87
88 // This is used for a large array with a progress bar.
89 // For simpicity, unshift to the bailout deque so that the concurrent thread
90 // does not see such objects.
91 bool Unshift(HeapObject* object) {
92 bailout_deque_.Unshift(object);
93 return true;
94 }
95
96 // Calls the specified callback on each element of the deques and replaces
97 // the element with the result of the callback. If the callback returns
98 // nullptr then the element is removed from the deque.
99 // The callback must accept HeapObject* and return HeapObject*.
100 template <typename Callback>
101 void Update(Callback callback) {
102 bailout_deque_.Update(callback);
103 shared_deque_.Update(callback);
104 }
105
106 // These empty functions are needed to match the interface
107 // of the sequential marking deque.
108 void SetUp() {}
109 void TearDown() {}
110 void StartUsing() {}
111 void StopUsing() {}
112 void ClearOverflowed() {}
113 void SetOverflowed() {}
114 bool overflowed() const { return false; }
115
116 private:
117 // Simple, slow, and thread-safe deque that forwards all operations to
118 // a lock-protected std::deque.
119 class Deque {
120 public:
121 Deque() { cache_padding_[0] = 0; }
122 void Clear() {
123 base::LockGuard<base::Mutex> guard(&mutex_);
124 return deque_.clear();
125 }
126 bool IsEmpty() {
127 base::LockGuard<base::Mutex> guard(&mutex_);
128 return deque_.empty();
129 }
130 int Size() {
131 base::LockGuard<base::Mutex> guard(&mutex_);
132 return static_cast<int>(deque_.size());
133 }
134 void Push(HeapObject* object) {
135 base::LockGuard<base::Mutex> guard(&mutex_);
136 deque_.push_back(object);
137 }
138 HeapObject* Pop() {
139 base::LockGuard<base::Mutex> guard(&mutex_);
140 if (deque_.empty()) return nullptr;
141 HeapObject* result = deque_.back();
142 deque_.pop_back();
143 return result;
144 }
145 void Unshift(HeapObject* object) {
146 base::LockGuard<base::Mutex> guard(&mutex_);
147 deque_.push_front(object);
148 }
149 template <typename Callback>
150 void Update(Callback callback) {
151 base::LockGuard<base::Mutex> guard(&mutex_);
152 std::deque<HeapObject*> new_deque;
153 for (auto object : deque_) {
154 HeapObject* new_object = callback(object);
155 if (new_object) {
156 new_deque.push_back(new_object);
157 }
158 }
159 deque_.swap(new_deque);
160 }
161
162 private:
163 base::Mutex mutex_;
164 std::deque<HeapObject*> deque_;
165 // Ensure that two deques do not share the same cache line.
166 static int const kCachePadding = 64;
167 char cache_padding_[kCachePadding];
168 };
169 Deque bailout_deque_;
170 Deque shared_deque_;
171 DISALLOW_COPY_AND_ASSIGN(ConcurrentMarkingDeque);
172 };
173
174 } // namespace internal
175 } // namespace v8
176
177 #endif // V8_CONCURRENT_MARKING_DEQUE_
OLDNEW
« no previous file with comments | « src/heap/concurrent-marking.cc ('k') | src/heap/heap.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698