Flutter Engine
The Flutter Engine
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_;
133 DISALLOW_COPY_AND_ASSIGN(List);
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:
154 DISALLOW_COPY_AND_ASSIGN(BlockStack);
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 DART_FORCE_INLINE
175 bool Pop(ObjectPtr* object) {
176 ASSERT(local_input_ != nullptr);
177 if (UNLIKELY(local_input_->IsEmpty())) {
178 if (!local_output_->IsEmpty()) {
179 auto temp = local_output_;
180 local_output_ = local_input_;
181 local_input_ = temp;
182 } else {
183 Block* new_work = stack_->PopNonEmptyBlock();
184 if (new_work == nullptr) {
185 return false;
186 }
187 stack_->PushBlock(local_input_);
188 local_input_ = new_work;
189 // Generated code appends to marking stacks; tell MemorySanitizer.
190 MSAN_UNPOISON(local_input_, sizeof(*local_input_));
191 }
192 }
193 *object = local_input_->Pop();
194 return true;
195 }
196
197 // Returns false if no more work was found.
198 DART_FORCE_INLINE
199 static bool Pop(BlockWorkList* first_choice,
200 BlockWorkList* second_choice,
201 ObjectPtr* object) {
202 if (!first_choice->local_input_->IsEmpty()) {
203 *object = first_choice->local_input_->Pop();
204 return true;
205 }
206 if (!second_choice->local_input_->IsEmpty()) {
207 *object = second_choice->local_input_->Pop();
208 return true;
209 }
210 if (first_choice->Pop(object)) {
211 return true;
212 }
213 if (second_choice->Pop(object)) {
214 return true;
215 }
216 return false;
217 }
218
219 void Push(ObjectPtr raw_obj) {
220 if (UNLIKELY(local_output_->IsFull())) {
221 stack_->PushBlock(local_output_);
222 local_output_ = stack_->PopEmptyBlock();
223 }
224 local_output_->Push(raw_obj);
225 }
226
227 void Flush() {
228 if (!local_output_->IsEmpty()) {
229 stack_->PushBlock(local_output_);
230 local_output_ = stack_->PopEmptyBlock();
231 }
232 if (!local_input_->IsEmpty()) {
233 stack_->PushBlock(local_input_);
234 local_input_ = stack_->PopEmptyBlock();
235 }
236 }
237
238 bool WaitForWork(RelaxedAtomic<uintptr_t>* num_busy, bool abort = false) {
239 ASSERT(local_input_->IsEmpty() || abort);
240 Block* new_work = stack_->WaitForWork(num_busy, abort);
241 if (new_work == nullptr) {
242 return false;
243 }
244 stack_->PushBlock(local_input_);
245 local_input_ = new_work;
246 return true;
247 }
248
249 void Finalize() {
250 ASSERT(local_output_->IsEmpty());
251 stack_->PushBlock(local_output_);
252 local_output_ = nullptr;
253 ASSERT(local_input_->IsEmpty());
254 stack_->PushBlock(local_input_);
255 local_input_ = nullptr;
256 // Fail fast on attempts to mark after finalizing.
257 stack_ = nullptr;
258 }
259
260 void AbandonWork() {
261 stack_->PushBlock(local_output_);
262 local_output_ = nullptr;
263 stack_->PushBlock(local_input_);
264 local_input_ = nullptr;
265 stack_ = nullptr;
266 }
267
269 if (!local_input_->IsEmpty()) {
270 return false;
271 }
272 if (!local_output_->IsEmpty()) {
273 return false;
274 }
275 return true;
276 }
277
278 bool IsEmpty() { return IsLocalEmpty() && stack_->IsEmpty(); }
279
280 private:
281 Block* local_output_;
282 Block* local_input_;
283 Stack* stack_;
284};
285
286static constexpr int kStoreBufferBlockSize = 1024;
287class StoreBuffer : public BlockStack<kStoreBufferBlockSize> {
288 public:
289 // Interrupt when crossing this threshold of non-empty blocks in the buffer.
290 static constexpr intptr_t kMaxNonEmpty = 100;
291
293
294 // Adds and transfers ownership of the block to the buffer. Optionally
295 // checks the number of non-empty blocks for overflow, and schedules an
296 // interrupt on the current isolate if so.
298
299 // Check whether non-empty blocks have exceeded kMaxNonEmpty (but takes no
300 // action).
301 bool Overflowed();
302 intptr_t Size();
303};
304
306
307static constexpr int kMarkingStackBlockSize = 64;
308class MarkingStack : public BlockStack<kMarkingStackBlockSize> {
309 public:
310 // Adds and transfers ownership of the block to the buffer.
311 void PushBlock(Block* block) {
313 }
314};
315
318
319static constexpr int kPromotionStackBlockSize = 64;
320class PromotionStack : public BlockStack<kPromotionStackBlockSize> {
321 public:
322 // Adds and transfers ownership of the block to the buffer.
323 void PushBlock(Block* block) {
325 }
326};
327
330
331template <int Size, typename T>
333 public:
335 ~LocalBlockWorkList() { ASSERT(head_ == nullptr); }
336
337 template <typename Lambda>
338 DART_FORCE_INLINE void Process(Lambda action) {
339 auto* block = head_;
340 head_ = new PointerBlock<Size>();
341 while (block != nullptr) {
342 while (!block->IsEmpty()) {
343 action(static_cast<T>(block->Pop()));
344 }
345 auto* next = block->next();
346 delete block;
347 block = next;
348 }
349 }
350
351 void Push(T obj) {
352 if (UNLIKELY(head_->IsFull())) {
354 next->next_ = head_;
355 head_ = next;
356 }
357 head_->Push(obj);
358 }
359
360 void Finalize() {
361 ASSERT(head_ != nullptr);
362 ASSERT(head_->IsEmpty());
363 delete head_;
364 head_ = nullptr;
365 }
366
367 void AbandonWork() {
368 ASSERT(head_ != nullptr);
369 auto* block = head_;
370 head_ = nullptr;
371 while (block != nullptr) {
372 auto* next = block->next_;
373 block->Reset();
374 delete block;
375 block = next;
376 }
377 }
378
379 private:
380 PointerBlock<Size>* head_;
381};
382
383} // namespace dart
384
385#endif // RUNTIME_VM_HEAP_POINTER_BLOCK_H_
static float next(float f)
SkBlockAllocator::Block Block
intptr_t length() const
void Push(Block *block)
static void TrimGlobalEmpty()
Block * PopNonFullBlock()
static Mutex * global_mutex_
PointerBlock< BlockSize > Block
Definition: pointer_block.h:91
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()
Stack::Block Block
DART_FORCE_INLINE bool Pop(ObjectPtr *object)
void Push(ObjectPtr raw_obj)
static DART_FORCE_INLINE bool Pop(BlockWorkList *first_choice, BlockWorkList *second_choice, ObjectPtr *object)
BlockWorkList(Stack *stack)
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)
Definition: pointer_block.h:37
static intptr_t pointers_offset()
Definition: pointer_block.h:61
intptr_t Count() const
Definition: pointer_block.h:33
static intptr_t top_offset()
Definition: pointer_block.h:60
PointerBlock< Size > * next() const
Definition: pointer_block.h:30
bool IsFull() const
Definition: pointer_block.h:34
void set_next(PointerBlock< Size > *next)
Definition: pointer_block.h:31
void VisitObjectPointers(ObjectPointerVisitor *visitor)
bool IsEmpty() const
Definition: pointer_block.h:35
void PushBlock(Block *block)
void PushBlock(Block *block, ThresholdPolicy policy)
static constexpr intptr_t kMaxNonEmpty
#define ASSERT(E)
#define MSAN_UNPOISON(ptr, len)
bool Contains(const Container &container, const Value &value)
Definition: dart_vm.cc:33
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
it will be possible to load the file into Perfetto s trace viewer disable asset Prevents usage of any non test fonts unless they were explicitly Loaded via prefetched default font Indicates whether the embedding started a prefetch of the default font manager before creating the engine run In non interactive keep the shell running after the Dart script has completed enable serial On low power devices with low core running concurrent GC tasks on threads can cause them to contend with the UI thread which could potentially lead to jank This option turns off all concurrent GC activities domain network policy
Definition: switches.h:248
TSize< Scalar > Size
Definition: size.h:137
#define UNLIKELY(cond)
Definition: globals.h:261
#define DISALLOW_COPY_AND_ASSIGN(TypeName)
Definition: globals.h:581
#define T
Definition: precompiler.cc:65
#define OFFSET_OF(type, field)
Definition: globals.h:138