Flutter Engine
The Flutter Engine
Loading...
Searching...
No Matches
pointer_block.h
Go to the documentation of this file.
1// Copyright (c) 2012, the Dart project authors. Please see the AUTHORS file
2// for details. All rights reserved. Use of this source code is governed by a
3// BSD-style license that can be found in the LICENSE file.
4
5#ifndef RUNTIME_VM_HEAP_POINTER_BLOCK_H_
6#define RUNTIME_VM_HEAP_POINTER_BLOCK_H_
7
8#include "platform/assert.h"
9#include "vm/globals.h"
10#include "vm/os_thread.h"
11#include "vm/tagged_pointer.h"
12
13namespace dart {
14
15// Forward declarations.
16class Isolate;
17class ObjectPointerVisitor;
18
19// A set of ObjectPtr. Must be emptied before destruction (using Pop/Reset).
20template <int Size>
22 public:
23 enum { kSize = Size };
24
25 void Reset() {
26 top_ = 0;
27 next_ = nullptr;
28 }
29
30 PointerBlock<Size>* next() const { return next_; }
32
33 intptr_t Count() const { return top_; }
34 bool IsFull() const { return Count() == kSize; }
35 bool IsEmpty() const { return Count() == 0; }
36
37 void Push(ObjectPtr obj) {
38 ASSERT(!IsFull());
39 pointers_[top_++] = obj;
40 }
41
43 ASSERT(!IsEmpty());
44 return pointers_[--top_];
45 }
46
47#if defined(TESTING)
48 bool Contains(ObjectPtr obj) const {
49 // Generated code appends to store buffers; tell MemorySanitizer.
50 MSAN_UNPOISON(this, sizeof(*this));
51 for (intptr_t i = 0; i < Count(); i++) {
52 if (pointers_[i] == obj) {
53 return true;
54 }
55 }
56 return false;
57 }
58#endif // TESTING
59
60 static intptr_t top_offset() { return OFFSET_OF(PointerBlock<Size>, top_); }
61 static intptr_t pointers_offset() {
62 return OFFSET_OF(PointerBlock<Size>, pointers_);
63 }
64
66
67 private:
68 PointerBlock() : next_(nullptr), top_(0) {}
69 ~PointerBlock() {
70 ASSERT(IsEmpty()); // Guard against unintentionally discarding pointers.
71 }
72
73 PointerBlock<Size>* next_;
74 int32_t top_;
75 ObjectPtr pointers_[kSize];
76
77 template <int>
78 friend class BlockStack;
79 template <int, typename T>
80 friend class LocalBlockWorkList;
81
83};
84
85// A synchronized collection of pointer blocks of a particular size.
86// This class is meant to be used as a base (note PushBlockImpl is protected).
87// The global list of cached empty blocks is currently per-size.
88template <int BlockSize>
90 public:
92
93 BlockStack();
95 static void Init();
96 static void Cleanup();
97
98 // Partially filled blocks can be reused, and there is an "infinite" supply
99 // of empty blocks (reused or newly allocated). In any case, the caller
100 // takes ownership of the returned block.
104
105 // Pops and returns all non-empty blocks as a linked list (owned by caller).
106 Block* PopAll();
107 void PushAll(Block* blocks);
108
109 // Discards the contents of all non-empty blocks.
110 void Reset();
111
112 bool IsEmpty();
113
114 Block* WaitForWork(RelaxedAtomic<uintptr_t>* num_busy, bool abort);
115
117
118 protected:
119 class List {
120 public:
121 List() : head_(nullptr), length_(0) {}
122 ~List();
123 void Push(Block* block);
124 Block* Pop();
125 intptr_t length() const { return length_; }
126 bool IsEmpty() const { return head_ == nullptr; }
127 Block* PopAll();
128 Block* Peek() { return head_; }
129
130 private:
131 Block* head_;
132 intptr_t length_;
134 };
135
136 bool IsEmptyLocked();
137
138 // Adds and transfers ownership of the block to the buffer.
139 void PushBlockImpl(Block* block);
140
141 // If needed, trims the global cache of empty blocks.
142 static void TrimGlobalEmpty();
143
147
148 // Note: This is shared on the basis of block size.
149 static constexpr intptr_t kMaxGlobalEmpty = 100;
152
153 private:
155};
156
157template <typename Stack>
159 public:
160 typedef typename Stack::Block Block;
161
162 explicit BlockWorkList(Stack* stack) : stack_(stack) {
163 local_output_ = stack_->PopEmptyBlock();
164 local_input_ = stack_->PopEmptyBlock();
165 }
166
168 ASSERT(local_output_ == nullptr);
169 ASSERT(local_input_ == nullptr);
170 ASSERT(stack_ == nullptr);
171 }
172
173 // Returns false if no more work was found.
174 bool Pop(ObjectPtr* object) {
175 ASSERT(local_input_ != nullptr);
176 if (UNLIKELY(local_input_->IsEmpty())) {
177 if (!local_output_->IsEmpty()) {
178 auto temp = local_output_;
179 local_output_ = local_input_;
180 local_input_ = temp;
181 } else {
182 Block* new_work = stack_->PopNonEmptyBlock();
183 if (new_work == nullptr) {
184 return false;
185 }
186 stack_->PushBlock(local_input_);
187 local_input_ = new_work;
188 // Generated code appends to marking stacks; tell MemorySanitizer.
189 MSAN_UNPOISON(local_input_, sizeof(*local_input_));
190 }
191 }
192 *object = local_input_->Pop();
193 return true;
194 }
195
196 void Push(ObjectPtr raw_obj) {
197 if (UNLIKELY(local_output_->IsFull())) {
198 stack_->PushBlock(local_output_);
199 local_output_ = stack_->PopEmptyBlock();
200 }
201 local_output_->Push(raw_obj);
202 }
203
204 void Flush() {
205 if (!local_output_->IsEmpty()) {
206 stack_->PushBlock(local_output_);
207 local_output_ = stack_->PopEmptyBlock();
208 }
209 if (!local_input_->IsEmpty()) {
210 stack_->PushBlock(local_input_);
211 local_input_ = stack_->PopEmptyBlock();
212 }
213 }
214
215 bool WaitForWork(RelaxedAtomic<uintptr_t>* num_busy, bool abort = false) {
216 ASSERT(local_input_->IsEmpty() || abort);
217 Block* new_work = stack_->WaitForWork(num_busy, abort);
218 if (new_work == nullptr) {
219 return false;
220 }
221 stack_->PushBlock(local_input_);
222 local_input_ = new_work;
223 return true;
224 }
225
226 void Finalize() {
227 ASSERT(local_output_->IsEmpty());
228 stack_->PushBlock(local_output_);
229 local_output_ = nullptr;
230 ASSERT(local_input_->IsEmpty());
231 stack_->PushBlock(local_input_);
232 local_input_ = nullptr;
233 // Fail fast on attempts to mark after finalizing.
234 stack_ = nullptr;
235 }
236
237 void AbandonWork() {
238 stack_->PushBlock(local_output_);
239 local_output_ = nullptr;
240 stack_->PushBlock(local_input_);
241 local_input_ = nullptr;
242 stack_ = nullptr;
243 }
244
246 if (!local_input_->IsEmpty()) {
247 return false;
248 }
249 if (!local_output_->IsEmpty()) {
250 return false;
251 }
252 return true;
253 }
254
255 bool IsEmpty() { return IsLocalEmpty() && stack_->IsEmpty(); }
256
257 private:
258 Block* local_output_;
259 Block* local_input_;
260 Stack* stack_;
261};
262
263static constexpr int kStoreBufferBlockSize = 1024;
264class StoreBuffer : public BlockStack<kStoreBufferBlockSize> {
265 public:
266 // Interrupt when crossing this threshold of non-empty blocks in the buffer.
267 static constexpr intptr_t kMaxNonEmpty = 100;
268
270
271 // Adds and transfers ownership of the block to the buffer. Optionally
272 // checks the number of non-empty blocks for overflow, and schedules an
273 // interrupt on the current isolate if so.
274 void PushBlock(Block* block, ThresholdPolicy policy);
275
276 // Check whether non-empty blocks have exceeded kMaxNonEmpty (but takes no
277 // action).
278 bool Overflowed();
279 intptr_t Size();
280};
281
283
284static constexpr int kMarkingStackBlockSize = 64;
285class MarkingStack : public BlockStack<kMarkingStackBlockSize> {
286 public:
287 // Adds and transfers ownership of the block to the buffer.
291};
292
295
296static constexpr int kPromotionStackBlockSize = 64;
297class PromotionStack : public BlockStack<kPromotionStackBlockSize> {
298 public:
299 // Adds and transfers ownership of the block to the buffer.
303};
304
307
308template <int Size, typename T>
310 public:
312 ~LocalBlockWorkList() { ASSERT(head_ == nullptr); }
313
314 template <typename Lambda>
315 DART_FORCE_INLINE void Process(Lambda action) {
316 auto* block = head_;
317 head_ = new PointerBlock<Size>();
318 while (block != nullptr) {
319 while (!block->IsEmpty()) {
320 action(static_cast<T>(block->Pop()));
321 }
322 auto* next = block->next();
323 delete block;
324 block = next;
325 }
326 }
327
328 void Push(T obj) {
329 if (UNLIKELY(head_->IsFull())) {
331 next->next_ = head_;
332 head_ = next;
333 }
334 head_->Push(obj);
335 }
336
337 void Finalize() {
338 ASSERT(head_ != nullptr);
339 ASSERT(head_->IsEmpty());
340 delete head_;
341 head_ = nullptr;
342 }
343
344 void AbandonWork() {
345 ASSERT(head_ != nullptr);
346 auto* block = head_;
347 head_ = nullptr;
348 while (block != nullptr) {
349 auto* next = block->next_;
350 block->Reset();
351 delete block;
352 block = next;
353 }
354 }
355
356 private:
357 PointerBlock<Size>* head_;
358};
359
360} // namespace dart
361
362#endif // RUNTIME_VM_HEAP_POINTER_BLOCK_H_
static float next(float f)
intptr_t length() const
void Push(Block *block)
static void TrimGlobalEmpty()
Block * PopNonFullBlock()
static Mutex * global_mutex_
PointerBlock< BlockSize > Block
Block * WaitForWork(RelaxedAtomic< uintptr_t > *num_busy, bool abort)
static List * global_empty_
void PushAll(Block *blocks)
void VisitObjectPointers(ObjectPointerVisitor *visitor)
static constexpr intptr_t kMaxGlobalEmpty
Block * PopEmptyBlock()
void PushBlockImpl(Block *block)
Block * PopNonEmptyBlock()
static void Init()
static void Cleanup()
void Push(ObjectPtr raw_obj)
BlockWorkList(Stack *stack)
bool Pop(ObjectPtr *object)
bool WaitForWork(RelaxedAtomic< uintptr_t > *num_busy, bool abort=false)
DART_FORCE_INLINE void Process(Lambda action)
void PushBlock(Block *block)
void Push(ObjectPtr obj)
static intptr_t pointers_offset()
intptr_t Count() const
static intptr_t top_offset()
PointerBlock< Size > * next() const
bool IsFull() const
void set_next(PointerBlock< Size > *next)
void VisitObjectPointers(ObjectPointerVisitor *visitor)
bool IsEmpty() const
void PushBlock(Block *block)
void PushBlock(Block *block, ThresholdPolicy policy)
static constexpr intptr_t kMaxNonEmpty
#define ASSERT(E)
#define MSAN_UNPOISON(ptr, len)
StoreBuffer::Block StoreBufferBlock
static constexpr int kMarkingStackBlockSize
MarkingStack::Block MarkingStackBlock
static constexpr int kPromotionStackBlockSize
PromotionStack::Block PromotionStackBlock
BlockWorkList< PromotionStack > PromotionWorkList
static constexpr int kStoreBufferBlockSize
BlockWorkList< MarkingStack > MarkerWorkList
#define UNLIKELY(cond)
Definition globals.h:261
#define DISALLOW_COPY_AND_ASSIGN(TypeName)
Definition globals.h:581
#define T
#define OFFSET_OF(type, field)
Definition globals.h:138