Flutter Engine
The Flutter Engine
handles.h
Go to the documentation of this file.
1// Copyright (c) 2011, 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_HANDLES_H_
6#define RUNTIME_VM_HANDLES_H_
7
8#include "vm/allocation.h"
9#include "vm/flags.h"
10#include "vm/os.h"
11
12namespace dart {
13
14// Handles are used in the Dart Virtual Machine to ensure that access
15// to dart objects in the virtual machine code is done in a
16// Garbage Collection safe manner.
17//
18// The class Handles is the basic type that implements creation of handles and
19// manages their life cycle (allocated either in the current zone or
20// current handle scope).
21// The two forms of handle allocation are:
22// - allocation of handles in the current zone (Handle::AllocateZoneHandle).
23// Handles allocated in this manner are destroyed when the zone is destroyed.
24// - allocation of handles in a scoped manner (Handle::AllocateHandle).
25// A new scope can be started using HANDLESCOPE(thread).
26// Handles allocated in this manner are destroyed when the HandleScope
27// object is destroyed.
28// Code that uses scoped handles typically looks as follows:
29// {
30// HANDLESCOPE(thread);
31// const String& str = String::Handle(String::New("abc"));
32// .....
33// .....
34// }
35// Code that uses zone handles typically looks as follows:
36// const String& str = String::ZoneHandle(String::New("abc"));
37// .....
38// .....
39//
40// The Handle function for each object type internally uses the
41// Handles::AllocateHandle() function for creating handles. The Handle
42// function of the object type is the only way to create scoped handles
43// in the dart VM.
44// The ZoneHandle function for each object type internally uses the
45// Handles::AllocateZoneHandle() function for creating zone handles.
46// The ZoneHandle function of the object type is the only way to create
47// zone handles in the dart VM.
48
49// Forward declarations.
50class ObjectPointerVisitor;
51class HandleVisitor;
52
53template <int kHandleSizeInWords, int kHandlesPerChunk, int kOffsetOfRawPtr>
54class Handles {
55 public:
57 : zone_blocks_(nullptr),
58 first_scoped_block_(nullptr),
59 scoped_blocks_(&first_scoped_block_) {}
60 ~Handles() { DeleteAll(); }
61
62 // Visit all object pointers stored in the various handles.
64
65 // Visit all the scoped handles.
67
68 // Visit all blocks that have been added since the last time
69 // this method was called.
70 // Be careful with this, since multiple users of this method could
71 // interfere with eachother.
72 // Currently only used by GC trace facility.
74
75 // Visit all of the various handles.
76 void Visit(HandleVisitor* visitor);
77
78 // Reset the handles so that we can reuse.
79 void Reset();
80
81 // Allocates a handle in the current handle scope. This handle is valid only
82 // in the current handle scope and is destroyed when the current handle
83 // scope ends.
84 static uword AllocateHandle(Zone* zone);
85
86 // Allocates a handle in the current zone. This handle will be destroyed
87 // when the current zone is destroyed.
88 static uword AllocateZoneHandle(Zone* zone);
89
90#if defined(DEBUG)
91 // Returns true if specified handle is a zone handle.
92 static bool IsZoneHandle(uword handle);
93#endif
94
95 // Allocates space for a scoped handle.
97 if (scoped_blocks_->IsFull()) {
98 SetupNextScopeBlock();
99 }
100 return scoped_blocks_->AllocateHandle();
101 }
102
103 bool IsEmpty() const {
104 if (zone_blocks_ != nullptr) return false;
105 if (first_scoped_block_.HandleCount() != 0) return false;
106 if (scoped_blocks_ != &first_scoped_block_) return false;
107 return true;
108 }
109
110 intptr_t ZoneHandlesCapacityInBytes() const {
111 intptr_t capacity = 0;
112 for (HandlesBlock* block = zone_blocks_; block != nullptr;
113 block = block->next_block()) {
114 capacity += sizeof(*block);
115 }
116 return capacity;
117 }
118
120 intptr_t capacity = 0;
121 for (HandlesBlock* block = scoped_blocks_; block != nullptr;
122 block = block->next_block()) {
123 capacity += sizeof(*block);
124 }
125 return capacity;
126 }
127
128 protected:
129 // Returns a count of active handles (used for testing purposes).
130 int CountScopedHandles() const;
131 int CountZoneHandles() const;
132
133 // Returns true if passed in handle is a valid zone handle.
134 bool IsValidScopedHandle(uword handle) const;
135 bool IsValidZoneHandle(uword handle) const;
136
137 private:
138 // Base structure for managing blocks of handles.
139 // Handles are allocated in Chunks (each chunk holds kHandlesPerChunk
140 // handles). The chunk is uninitialized, subsequent requests for handles
141 // is allocated from the chunk until we run out space in the chunk,
142 // at this point another chunk is allocated. These chunks are chained
143 // together.
144 class HandlesBlock : public MallocAllocated {
145 public:
146 explicit HandlesBlock(HandlesBlock* next)
147 : next_block_(next), next_handle_slot_(0) {}
148 ~HandlesBlock();
149
150 // Reinitializes handle block for reuse.
151 void ReInit();
152
153 // Returns true if the handle block is full.
154 bool IsFull() const {
155 return next_handle_slot_ >= (kHandleSizeInWords * kHandlesPerChunk);
156 }
157
158 // Returns true if passed in handle belongs to this block.
159 bool IsValidHandle(uword handle) const {
160 uword start = reinterpret_cast<uword>(data_);
161 uword end = start + (kHandleSizeInWords * kWordSize * kHandlesPerChunk);
162 return (start <= handle && handle < end);
163 }
164
165 // Allocates space for a handle in the data area.
167 ASSERT(!IsFull());
168 uword handle_address = reinterpret_cast<uword>(data_ + next_handle_slot_);
169 next_handle_slot_ += kHandleSizeInWords;
170 return handle_address;
171 }
172
173 // Visit all object pointers in the handle block.
174 void VisitObjectPointers(ObjectPointerVisitor* visitor);
175
176 // Visit all of the handles in the handle block.
177 void Visit(HandleVisitor* visitor);
178
179#if defined(DEBUG)
180 // Zaps the free handle area to an uninitialized value.
181 void ZapFreeHandles();
182#endif
183
184 // Returns number of active handles in the handle block.
185 int HandleCount() const;
186
187 // Accessors.
188 intptr_t next_handle_slot() const { return next_handle_slot_; }
189 void set_next_handle_slot(intptr_t next_handle_slot) {
190 next_handle_slot_ = next_handle_slot;
191 }
192 HandlesBlock* next_block() const { return next_block_; }
193 void set_next_block(HandlesBlock* next) { next_block_ = next; }
194
195 private:
196 HandlesBlock* next_block_; // Link to next block of handles.
197 intptr_t next_handle_slot_; // Next slot for allocation in current block.
198 uword data_[kHandleSizeInWords * kHandlesPerChunk]; // Handles area.
199
200 DISALLOW_COPY_AND_ASSIGN(HandlesBlock);
201 };
202
203 // Deletes all the allocated handle blocks.
204 void DeleteAll();
205 void DeleteHandleBlocks(HandlesBlock* blocks);
206
207 // Sets up the next handle block (allocates a new one if needed).
208 void SetupNextScopeBlock();
209
210 // Allocates space for a zone handle.
211 uword AllocateHandleInZone() {
212 if (zone_blocks_ == nullptr || zone_blocks_->IsFull()) {
213 SetupNextZoneBlock();
214 }
215 return zone_blocks_->AllocateHandle();
216 }
217
218 // Allocates a new handle block and links it up.
219 void SetupNextZoneBlock();
220
221 HandlesBlock* zone_blocks_; // List of zone handles.
222 HandlesBlock first_scoped_block_; // First block of scoped handles.
223 HandlesBlock* scoped_blocks_; // List of scoped handles.
224
225 friend class HandleScope;
226 friend class Dart;
227 friend class IsolateObjectStore;
228 friend class ObjectStore;
229 friend class ThreadState;
232};
233
234#if defined(DEBUG)
235static constexpr int kVMHandleSizeInWords = 3;
236static constexpr int kOffsetOfIsZoneHandle = 2;
237#else
238static constexpr int kVMHandleSizeInWords = 2;
239#endif
240static constexpr int kVMHandlesPerChunk = 63;
241static constexpr int kOffsetOfRawPtr = kWordSize;
242class VMHandles : public Handles<kVMHandleSizeInWords,
243 kVMHandlesPerChunk,
244 kOffsetOfRawPtr> {
245 public:
247
250#if defined(DEBUG)
251 if (FLAG_trace_handles) {
252 OS::PrintErr("*** Starting a new VM handle block 0x%" Px "\n",
253 reinterpret_cast<intptr_t>(this));
254 }
255#endif
256 }
258#if defined(DEBUG)
259 if (FLAG_trace_handles) {
260 OS::PrintErr("*** Handle Counts for 0x(%" Px
261 "):Zone = %d,Scoped = %d\n",
262 reinterpret_cast<intptr_t>(this), CountZoneHandles(),
264 OS::PrintErr("*** Deleting VM handle block 0x%" Px "\n",
265 reinterpret_cast<intptr_t>(this));
266 }
267#endif
268 }
269
270 // Visit all object pointers stored in the various handles.
272
273 // Allocates a handle in the current handle scope of 'zone', which must be
274 // the current zone. This handle is valid only in the current handle scope
275 // and is destroyed when the current handle scope ends.
276 static uword AllocateHandle(Zone* zone);
277
278 // Allocates a handle in 'zone', which must be the current zone. This handle
279 // will be destroyed when the current zone is destroyed.
280 static uword AllocateZoneHandle(Zone* zone);
281
282#if defined(DEBUG)
283 // Returns true if specified handle is a zone handle.
284 static bool IsZoneHandle(uword handle);
285#endif
286
287 // Returns number of handles, these functions are used for testing purposes.
288 static int ScopedHandleCount();
289 static int ZoneHandleCount();
290
291 friend class ApiZone;
292 friend class ApiNativeScope;
293};
294
295// The class HandleScope is used to start a new handles scope in the code.
296// It is used as follows:
297// {
298// HANDLESCOPE(thread);
299// ....
300// .....
301// code that creates some scoped handles.
302// ....
303// }
305 public:
306 explicit HandleScope(ThreadState* thread);
307 ~HandleScope();
308
309 private:
310 void Initialize();
311
312 VMHandles::HandlesBlock* saved_handle_block_; // Handle block at prev scope.
313 uword saved_handle_slot_; // Next available handle slot at previous scope.
314#if defined(DEBUG)
315 HandleScope* link_; // Link to previous scope.
316#endif
317 DISALLOW_IMPLICIT_CONSTRUCTORS(HandleScope);
318};
319
320// Macro to start a new Handle scope.
321#define HANDLESCOPE(thread) \
322 dart::HandleScope vm_internal_handles_scope_(thread);
323
324} // namespace dart
325
326#endif // RUNTIME_VM_HANDLES_H_
static float next(float f)
HandleScope(ThreadState *thread)
Definition: handles.cc:85
int CountZoneHandles() const
Definition: handles_impl.h:228
static uword AllocateZoneHandle(Zone *zone)
Definition: handles_impl.h:95
void VisitUnvisitedScopedHandles(ObjectPointerVisitor *visitor)
bool IsValidZoneHandle(uword handle) const
Definition: handles_impl.h:188
intptr_t ZoneHandlesCapacityInBytes() const
Definition: handles.h:110
intptr_t ScopedHandlesCapacityInBytes() const
Definition: handles.h:119
void Visit(HandleVisitor *visitor)
Definition: handles_impl.h:43
void VisitObjectPointers(ObjectPointerVisitor *visitor)
Definition: handles_impl.h:16
uword AllocateScopedHandle()
Definition: handles.h:96
int CountScopedHandles() const
Definition: handles_impl.h:212
void VisitScopedHandles(ObjectPointerVisitor *visitor)
Definition: handles_impl.h:30
static uword AllocateHandle(Zone *zone)
Definition: handles_impl.h:81
bool IsEmpty() const
Definition: handles.h:103
bool IsValidScopedHandle(uword handle) const
Definition: handles_impl.h:175
static void static void PrintErr(const char *format,...) PRINTF_ATTRIBUTE(1
ThreadState * thread() const
Definition: allocation.h:33
static int ZoneHandleCount()
Definition: handles.cc:66
static constexpr int kOffsetOfRawPtrInHandle
Definition: handles.h:246
static uword AllocateZoneHandle(Zone *zone)
Definition: handles.cc:42
static uword AllocateHandle(Zone *zone)
Definition: handles.cc:32
void VisitObjectPointers(ObjectPointerVisitor *visitor)
Definition: handles.cc:20
static int ScopedHandleCount()
Definition: handles.cc:59
#define ASSERT(E)
glong glong end
Definition: dart_vm.cc:33
static constexpr int kVMHandleSizeInWords
Definition: handles.h:238
static constexpr int kVMHandlesPerChunk
Definition: handles.h:240
uintptr_t uword
Definition: globals.h:501
static constexpr int kOffsetOfRawPtr
Definition: handles.h:241
constexpr intptr_t kWordSize
Definition: globals.h:509
#define Px
Definition: globals.h:410
#define DISALLOW_ALLOCATION()
Definition: globals.h:604
#define DISALLOW_COPY_AND_ASSIGN(TypeName)
Definition: globals.h:581