Flutter Engine
The Flutter Engine
Loading...
Searching...
No Matches
zone.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_ZONE_H_
6#define RUNTIME_VM_ZONE_H_
7
8#include "platform/utils.h"
9#include "vm/allocation.h"
10#include "vm/handles.h"
11#include "vm/memory_region.h"
12#include "vm/thread_state.h"
13
14namespace dart {
15
16// Zones support very fast allocation of small chunks of memory. The
17// chunks cannot be deallocated individually, but instead zones
18// support deallocating all chunks in one fast operation.
19
20class Zone {
21 public:
22 // Allocate an array sized to hold 'len' elements of type
23 // 'ElementType'. Checks for integer overflow when performing the
24 // size computation.
25 template <class ElementType>
26 inline ElementType* Alloc(intptr_t len);
27
28 // Allocates an array sized to hold 'len' elements of type
29 // 'ElementType'. The new array is initialized from the memory of
30 // 'old_array' up to 'old_len'.
31 template <class ElementType>
32 inline ElementType* Realloc(ElementType* old_array,
33 intptr_t old_len,
34 intptr_t new_len);
35
36 // Allocates 'size' bytes of memory in the zone; expands the zone by
37 // allocating new segments of memory on demand using 'new'.
38 //
39 // It is preferred to use Alloc<T>() instead, as that function can
40 // check for integer overflow. If you use AllocUnsafe, you are
41 // responsible for avoiding integer overflow yourself.
42 inline uword AllocUnsafe(intptr_t size);
43
44 // Make a copy of the string in the zone allocated area.
45 char* MakeCopyOfString(const char* str);
46
47 // Make a copy of the first n characters of a string in the zone
48 // allocated area.
49 char* MakeCopyOfStringN(const char* str, intptr_t len);
50
51 // Concatenate strings |a| and |b|. |a| may be nullptr. If |a| is not nullptr,
52 // |join| will be inserted between |a| and |b|.
53 char* ConcatStrings(const char* a, const char* b, char join = ',');
54
55 // TODO(zra): Remove these calls and replace them with calls to OS::SCreate
56 // and OS::VSCreate.
57 // These calls are deprecated. Do not add further calls to these functions.
58 // instead use OS::SCreate and OS::VSCreate.
59 // Make a zone-allocated string based on printf format and args.
60 char* PrintToString(const char* format, ...) PRINTF_ATTRIBUTE(2, 3);
61 char* VPrint(const char* format, va_list args);
62
63 // Compute the total size of allocations in this zone.
64 uintptr_t SizeInBytes() const;
65
66 // Computes the amount of space used by the zone.
67 uintptr_t CapacityInBytes() const;
68
69 // Dump the current allocated sizes in the zone object.
70 void Print() const;
71
72 // Structure for managing handles allocation.
73 VMHandles* handles() { return &handles_; }
74
76
77 Zone* previous() const { return previous_; }
78
79 bool ContainsNestedZone(Zone* other) const {
80 while (other != nullptr) {
81 if (this == other) return true;
82 other = other->previous_;
83 }
84 return false;
85 }
86
87 // All pointers returned from AllocateUnsafe() and New() have this alignment.
88 static constexpr intptr_t kAlignment = kDoubleSize;
89
90 static void Init();
91 static void Cleanup();
92
93 static void ClearCache();
94 static intptr_t Size() { return total_size_; }
95
96 private:
97 Zone();
98 ~Zone(); // Delete all memory associated with the zone.
99
100 // Default initial chunk size.
101 static constexpr intptr_t kInitialChunkSize = 128;
102
103 // Default segment size.
104 static constexpr intptr_t kSegmentSize = 64 * KB;
105
106 // Zap value used to indicate deleted zone area (debug purposes).
107 static constexpr unsigned char kZapDeletedByte = 0x42;
108
109 // Zap value used to indicate uninitialized zone area (debug purposes).
110 static constexpr unsigned char kZapUninitializedByte = 0xab;
111
112 // Total size of current zone segments.
113 static RelaxedAtomic<intptr_t> total_size_;
114
115 // Expand the zone to accommodate an allocation of 'size' bytes.
116 uword AllocateExpand(intptr_t size);
117
118 // Allocate a large segment.
119 uword AllocateLargeSegment(intptr_t size);
120
121 // Insert zone into zone chain, after current_zone.
122 void Link(Zone* current_zone) { previous_ = current_zone; }
123
124 // Delete all objects and free all memory allocated in the zone.
125 void Reset();
126
127 // Does not actually free any memory. Enables templated containers like
128 // BaseGrowableArray to use different allocators.
129 template <class ElementType>
130 void Free(ElementType* old_array, intptr_t len) {
131#ifdef DEBUG
132 if (len > 0) {
133 ASSERT(old_array != nullptr);
134 memset(static_cast<void*>(old_array), kZapUninitializedByte,
135 len * sizeof(ElementType));
136 }
137#endif
138 }
139
140 // Overflow check (FATAL) for array length.
141 template <class ElementType>
142 static inline void CheckLength(intptr_t len);
143
144 // The free region in the current (head) segment or the initial buffer is
145 // represented as the half-open interval [position, limit). The 'position'
146 // variable is guaranteed to be aligned as dictated by kAlignment.
147 uword position_;
148 uword limit_;
149
150 // Zone segments are internal data structures used to hold information
151 // about the memory segmentations that constitute a zone. The entire
152 // implementation is in zone.cc.
153 class Segment;
154
155 // Total size of all allocations in this zone.
156 intptr_t size_ = 0;
157
158 // Total size of all segments in [head_].
159 intptr_t small_segment_capacity_ = 0;
160
161 // List of all segments allocated in this zone; may be nullptr.
162 Segment* segments_;
163
164 // Used for chaining zones in order to allow unwinding of stacks.
165 Zone* previous_;
166
167 // Structure for managing handles allocation.
168 VMHandles handles_;
169
170 // This buffer is used for allocation before any segments.
171 // This would act as the initial stack allocated chunk so that we don't
172 // end up calling malloc/free on zone scopes that allocate less than
173 // kChunkSize
175 ALIGN8 uint8_t buffer_[kInitialChunkSize];
176
177 friend class StackZone;
178 friend class ApiZone;
179 friend class AllocOnlyStackZone;
180 template <typename T, typename B, typename Allocator>
181 friend class BaseGrowableArray;
182 template <typename T, typename B, typename Allocator>
185};
186
187class StackZone : public StackResource {
188 public:
189 // Create an empty zone and set is at the current zone for the Thread.
190 explicit StackZone(ThreadState* thread);
191
192 // Delete all memory associated with the zone.
193 virtual ~StackZone();
194
195 // DART_USE_ABSL encodes the use of fibers in the Dart VM for threading,
196#if defined(DART_USE_ABSL)
197 // Compute the total size of this zone. This includes wasted space that is
198 // due to internal fragmentation in the segments.
199 uintptr_t SizeInBytes() const { return zone_->SizeInBytes(); }
200
201 // Computes the used space in the zone.
202 intptr_t CapacityInBytes() const { return zone_->CapacityInBytes(); }
203
204 Zone* GetZone() { return zone_; }
205#else
206 // Compute the total size of this zone. This includes wasted space that is
207 // due to internal fragmentation in the segments.
208 uintptr_t SizeInBytes() const { return zone_.SizeInBytes(); }
209
210 // Computes the used space in the zone.
211 intptr_t CapacityInBytes() const { return zone_.CapacityInBytes(); }
212
213 Zone* GetZone() { return &zone_; }
214#endif // defined(DART_USE_ABSL)
215
216 private:
217#if defined(DART_USE_ABSL)
218 // When fibers are used we have to make do with a smaller stack size and hence
219 // the first zone is allocated instead of being a stack resource.
220 Zone* zone_;
221#else
222 // For regular configurations that have larger stack sizes it is ok to
223 // have the first zone be a stack resource, avoids the overhead of a malloc
224 // call for every stack zone creation.
225 Zone zone_;
226#endif // defined(DART_USE_ABSL)
227
228 template <typename T>
229 friend class GrowableArray;
230 template <typename T>
231 friend class ZoneGrowableArray;
232
234};
235
237 public:
238 AllocOnlyStackZone() : zone_() {}
240 // This zone is not linked into the thread, so any handles would not be
241 // visited.
242 ASSERT(zone_.handles()->IsEmpty());
243 }
244
245 Zone* GetZone() { return &zone_; }
246
247 private:
248 Zone zone_;
249
251};
252
253inline uword Zone::AllocUnsafe(intptr_t size) {
254 ASSERT(size >= 0);
255 // Round up the requested size to fit the alignment.
256 if (size > (kIntptrMax - kAlignment)) {
257 FATAL("Zone::Alloc: 'size' is too large: size=%" Pd "", size);
258 }
260
261 // Check if the requested size is available without expanding.
263 intptr_t free_size = (limit_ - position_);
264 if (free_size >= size) {
265 result = position_;
266 position_ += size;
267 size_ += size;
268 } else {
269 result = AllocateExpand(size);
270 }
271
272 // Check that the result has the proper alignment and return it.
274 return result;
275}
276
277template <class ElementType>
278inline void Zone::CheckLength(intptr_t len) {
279 const intptr_t kElementSize = sizeof(ElementType);
280 if (len > (kIntptrMax / kElementSize)) {
281 FATAL("Zone::Alloc: 'len' is too large: len=%" Pd ", kElementSize=%" Pd,
282 len, kElementSize);
283 }
284}
285
286template <class ElementType>
287inline ElementType* Zone::Alloc(intptr_t len) {
288 CheckLength<ElementType>(len);
289 return reinterpret_cast<ElementType*>(AllocUnsafe(len * sizeof(ElementType)));
290}
291
292template <class ElementType>
293inline ElementType* Zone::Realloc(ElementType* old_data,
294 intptr_t old_len,
295 intptr_t new_len) {
296 CheckLength<ElementType>(new_len);
297 const intptr_t kElementSize = sizeof(ElementType);
298 if (old_data != nullptr) {
299 uword old_end =
300 reinterpret_cast<uword>(old_data) + (old_len * kElementSize);
301 // Resize existing allocation if nothing was allocated in between...
302 if (Utils::RoundUp(old_end, kAlignment) == position_) {
303 uword new_end =
304 reinterpret_cast<uword>(old_data) + (new_len * kElementSize);
305 // ...and there is sufficient space.
306 if (new_end <= limit_) {
307 position_ = Utils::RoundUp(new_end, kAlignment);
308 size_ += static_cast<intptr_t>(new_len - old_len);
309 return old_data;
310 }
311 }
312 if (new_len <= old_len) {
313 return old_data;
314 }
315 }
316 ElementType* new_data = Alloc<ElementType>(new_len);
317 if (old_data != nullptr) {
318 memmove(reinterpret_cast<void*>(new_data),
319 reinterpret_cast<void*>(old_data), old_len * kElementSize);
320 }
321 return new_data;
322}
323
324} // namespace dart
325
326#endif // RUNTIME_VM_ZONE_H_
#define COMPILE_ASSERT(expr)
Definition assert.h:339
bool IsEmpty() const
Definition handles.h:103
ThreadState * thread() const
Definition allocation.h:33
virtual ~StackZone()
Definition zone.cc:347
Zone * GetZone()
Definition zone.h:213
intptr_t CapacityInBytes() const
Definition zone.h:211
uintptr_t SizeInBytes() const
Definition zone.h:208
static constexpr T RoundUp(T x, uintptr_t alignment, uintptr_t offset=0)
Definition utils.h:105
static constexpr bool IsAligned(T x, uintptr_t alignment, uintptr_t offset=0)
Definition utils.h:77
char * PrintToString(const char *format,...) PRINTF_ATTRIBUTE(2
Definition zone.cc:313
static void ClearCache()
Definition zone.cc:69
static void Init()
Definition zone.cc:58
uword AllocUnsafe(intptr_t size)
static intptr_t Size()
Definition zone.h:94
ElementType * Realloc(ElementType *old_array, intptr_t old_len, intptr_t new_len)
bool ContainsNestedZone(Zone *other) const
Definition zone.h:79
ElementType * Alloc(intptr_t len)
uintptr_t CapacityInBytes() const
Definition zone.cc:186
uintptr_t SizeInBytes() const
Definition zone.cc:182
void Free(ElementType *old_array, intptr_t len)
char * MakeCopyOfStringN(const char *str, intptr_t len)
Definition zone.cc:277
static constexpr intptr_t kAlignment
Definition zone.h:88
char * MakeCopyOfString(const char *str)
Definition zone.cc:270
ElementType * Realloc(ElementType *old_array, intptr_t old_length, intptr_t new_length)
static void Cleanup()
Definition zone.cc:63
char * ConcatStrings(const char *a, const char *b, char join=',')
Definition zone.cc:291
void Print() const
Definition zone.cc:194
VMHandles * handles()
Definition zone.h:73
ElementType * Alloc(intptr_t length)
void VisitObjectPointers(ObjectPointerVisitor *visitor)
Definition zone.cc:305
char char * VPrint(const char *format, va_list args)
Definition zone.cc:321
Zone * previous() const
Definition zone.h:77
#define ASSERT(E)
static bool b
struct MyStruct a[10]
#define FATAL(error)
G_BEGIN_DECLS G_MODULE_EXPORT FlValue * args
GAsyncResult * result
uint32_t uint32_t * format
constexpr intptr_t KB
Definition globals.h:528
uintptr_t uword
Definition globals.h:501
constexpr intptr_t kDoubleSize
Definition globals.h:456
constexpr intptr_t kIntptrMax
Definition globals.h:557
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 JSON encoded network policy per domain This overrides the DisallowInsecureConnections switch Embedder can specify whether to allow or disallow insecure connections at a domain level old gen heap size
Definition switches.h:259
#define Pd
Definition globals.h:408
#define DISALLOW_IMPLICIT_CONSTRUCTORS(TypeName)
Definition globals.h:593
#define PRINTF_ATTRIBUTE(string_index, first_to_check)
Definition globals.h:697
#define DISALLOW_COPY_AND_ASSIGN(TypeName)
Definition globals.h:581
#define ALIGN8
Definition globals.h:171