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_DART_API_STATE_H_
6#define RUNTIME_VM_DART_API_STATE_H_
7
8#include "include/dart_api.h"
9
10#include "platform/utils.h"
11#include "vm/bitfield.h"
12#include "vm/dart_api_impl.h"
13#include "vm/flags.h"
14#include "vm/growable_array.h"
15#include "vm/handles.h"
16#include "vm/heap/weak_table.h"
17#include "vm/object.h"
18#include "vm/os.h"
19#include "vm/os_thread.h"
20#include "vm/raw_object.h"
21#include "vm/thread_pool.h"
22#include "vm/visitor.h"
23
24#include "vm/handles_impl.h"
25
26namespace dart {
27
28// Implementation of Zone support for very fast allocation of small chunks
29// of memory. The chunks cannot be deallocated individually, but instead
30// zones support deallocating all chunks in one fast operation when the
31// scope is exited.
32class ApiZone {
33 public:
34 // Create an empty zone.
35 ApiZone() : zone_() {
36 Thread* thread = Thread::Current();
37 Zone* zone = thread != NULL ? thread->zone() : NULL;
38 zone_.Link(zone);
39 if (thread != NULL) {
40 thread->set_zone(&zone_);
41 }
42 if (FLAG_trace_zones) {
43 OS::PrintErr("*** Starting a new Api zone 0x%" Px "(0x%" Px ")\n",
44 reinterpret_cast<intptr_t>(this),
45 reinterpret_cast<intptr_t>(&zone_));
46 }
47 }
48
49 // Delete all memory associated with the zone.
50 ~ApiZone() {
51 Thread* thread = Thread::Current();
52#if defined(DEBUG)
53 if (thread == NULL) {
54 ASSERT(zone_.handles()->CountScopedHandles() == 0);
55 ASSERT(zone_.handles()->CountZoneHandles() == 0);
56 }
57#endif
58 if ((thread != NULL) && (thread->zone() == &zone_)) {
59 thread->set_zone(zone_.previous_);
60 }
61 if (FLAG_trace_zones) {
62 OS::PrintErr("*** Deleting Api zone 0x%" Px "(0x%" Px ")\n",
63 reinterpret_cast<intptr_t>(this),
64 reinterpret_cast<intptr_t>(&zone_));
65 }
66 }
67
68 // Allocates an array sized to hold 'len' elements of type
69 // 'ElementType'. Checks for integer overflow when performing the
70 // size computation.
71 template <class ElementType>
72 ElementType* Alloc(intptr_t len) {
73 return zone_.Alloc<ElementType>(len);
74 }
75
76 // Allocates an array sized to hold 'len' elements of type
77 // 'ElementType'. The new array is initialized from the memory of
78 // 'old_array' up to 'old_len'.
79 template <class ElementType>
80 ElementType* Realloc(ElementType* old_array,
81 intptr_t old_len,
82 intptr_t new_len) {
83 return zone_.Realloc<ElementType>(old_array, old_len, new_len);
84 }
85
86 // Allocates 'size' bytes of memory in the zone; expands the zone by
87 // allocating new segments of memory on demand using 'new'.
88 //
89 // It is preferred to use Alloc<T>() instead, as that function can
90 // check for integer overflow. If you use AllocUnsafe, you are
91 // responsible for avoiding integer overflow yourself.
92 uword AllocUnsafe(intptr_t size) { return zone_.AllocUnsafe(size); }
93
94 // Compute the total size of this zone. This includes wasted space that is
95 // due to internal fragmentation in the segments.
96 intptr_t SizeInBytes() const { return zone_.SizeInBytes(); }
97
98 Zone* GetZone() { return &zone_; }
99
100 void Reinit(Thread* thread) {
101 if (thread == NULL) {
102 zone_.Link(NULL);
103 } else {
104 zone_.Link(thread->zone());
105 thread->set_zone(&zone_);
106 }
107 }
108
109 void Reset(Thread* thread) {
110 if ((thread != NULL) && (thread->zone() == &zone_)) {
111 thread->set_zone(zone_.previous_);
112 }
113 zone_.DeleteAll();
114 }
115
116 private:
117 Zone zone_;
118
119 template <typename T>
120 friend class ApiGrowableArray;
121 DISALLOW_COPY_AND_ASSIGN(ApiZone);
122};
123
124// Implementation of local handles which are handed out from every
125// dart API call, these handles are valid only in the present scope
126// and are destroyed when a Dart_ExitScope() is called.
127class LocalHandle {
128 public:
129 // Accessors.
130 ObjectPtr raw() const { return raw_; }
131 void set_raw(ObjectPtr raw) { raw_ = raw; }
132 static intptr_t raw_offset() { return OFFSET_OF(LocalHandle, raw_); }
133
134 Dart_Handle apiHandle() { return reinterpret_cast<Dart_Handle>(this); }
135
136 private:
137 LocalHandle() {}
138 ~LocalHandle() {}
139
140 ObjectPtr raw_;
141 DISALLOW_ALLOCATION(); // Allocated through AllocateHandle methods.
142 DISALLOW_COPY_AND_ASSIGN(LocalHandle);
143};
144
145// A distinguished callback which indicates that a persistent handle
146// should not be deleted from the dart api.
147void ProtectedHandleCallback(void* peer);
148
149// Implementation of persistent handles which are handed out through the
150// dart API.
151class PersistentHandle {
152 public:
153 // Accessors.
154 ObjectPtr raw() const { return raw_; }
155 void set_raw(ObjectPtr ref) { raw_ = ref; }
156 void set_raw(const LocalHandle& ref) { raw_ = ref.raw(); }
157 void set_raw(const Object& object) { raw_ = object.raw(); }
158 ObjectPtr* raw_addr() { return &raw_; }
159 Dart_PersistentHandle apiHandle() {
160 return reinterpret_cast<Dart_PersistentHandle>(this);
161 }
162
163 static intptr_t raw_offset() { return OFFSET_OF(PersistentHandle, raw_); }
164
165 static PersistentHandle* Cast(Dart_PersistentHandle handle);
166
167 private:
168 friend class PersistentHandles;
169
170 PersistentHandle() {}
171 ~PersistentHandle() {}
172
173 // Overload the raw_ field as a next pointer when adding freed
174 // handles to the free list.
175 PersistentHandle* Next() {
176 return reinterpret_cast<PersistentHandle*>(static_cast<uword>(raw_));
177 }
178 void SetNext(PersistentHandle* free_list) {
179 raw_ = static_cast<ObjectPtr>(reinterpret_cast<uword>(free_list));
180 ASSERT(!raw_->IsHeapObject());
181 }
182 void FreeHandle(PersistentHandle* free_list) { SetNext(free_list); }
183
184 ObjectPtr raw_;
185 DISALLOW_ALLOCATION(); // Allocated through AllocateHandle methods.
186 DISALLOW_COPY_AND_ASSIGN(PersistentHandle);
187};
188
189// Implementation of persistent handles which are handed out through the
190// dart API.
191class FinalizablePersistentHandle {
192 public:
193 // TODO(http://dartbug.com/42312): Delete this on migrating signature
194 // Dart_NewWeakPersistentHandle to Dart_HandleFinalizer.
195 enum class CallbackSignature {
196 // Uses a Dart_WeakPersistentHandleFinalizer.
197 kWeakPersistentHandleFinalizer = 0,
198 // Uses a Dart_HandleFinalizer.
199 kHandleFinalizer = 1,
200 };
201
202 static FinalizablePersistentHandle* New(
203 Isolate* isolate,
204 const Object& object,
205 void* peer,
206 Dart_WeakPersistentHandleFinalizer callback,
207 intptr_t external_size,
208 bool auto_delete);
209
210 static FinalizablePersistentHandle* New(Isolate* isolate,
211 const Object& object,
212 void* peer,
213 Dart_HandleFinalizer callback,
214 intptr_t external_size,
215 bool auto_delete);
216
217 // Accessors.
218 ObjectPtr raw() const { return raw_; }
219 ObjectPtr* raw_addr() { return &raw_; }
220 static intptr_t raw_offset() {
221 return OFFSET_OF(FinalizablePersistentHandle, raw_);
222 }
223 void* peer() const { return peer_; }
224 Dart_WeakPersistentHandleFinalizer CallbackWeakFinalizer() const {
225 ASSERT(callback_signature_ ==
226 CallbackSignature::kWeakPersistentHandleFinalizer);
227 return callback_.weak_persistent;
228 }
229 Dart_HandleFinalizer callback() const {
230 ASSERT(callback_signature_ == CallbackSignature::kHandleFinalizer);
231 return callback_.finalizable;
232 }
233 uword callback_address() const {
234 return reinterpret_cast<uword>(callback_.finalizable);
235 }
236 Dart_WeakPersistentHandle ApiWeakPersistentHandle() {
237 return reinterpret_cast<Dart_WeakPersistentHandle>(this);
238 }
239 Dart_FinalizableHandle ApiFinalizableHandle() {
240 return reinterpret_cast<Dart_FinalizableHandle>(this);
241 }
242
243 bool auto_delete() const { return auto_delete_; }
244
245 intptr_t external_size() const {
246 return ExternalSizeInWordsBits::decode(external_data_) * kWordSize;
247 }
248
249 void SetExternalSize(intptr_t size, IsolateGroup* isolate_group) {
250 ASSERT(size >= 0);
251 set_external_size(size);
252 if (SpaceForExternal() == Heap::kNew) {
253 SetExternalNewSpaceBit();
254 }
255 isolate_group->heap()->AllocatedExternal(external_size(),
256 SpaceForExternal());
257 }
258 void UpdateExternalSize(intptr_t size, IsolateGroup* isolate_group) {
259 ASSERT(size >= 0);
260 intptr_t old_size = external_size();
261 set_external_size(size);
262 if (size > old_size) {
263 isolate_group->heap()->AllocatedExternal(size - old_size,
264 SpaceForExternal());
265 } else {
266 isolate_group->heap()->FreedExternal(old_size - size, SpaceForExternal());
267 }
268 }
269
270 // Called when the referent becomes unreachable.
271 void UpdateUnreachable(IsolateGroup* isolate_group) {
272 EnsureFreedExternal(isolate_group);
273 Finalize(isolate_group, this);
274 }
275
276 // Called when the referent has moved, potentially between generations.
277 void UpdateRelocated(IsolateGroup* isolate_group) {
278 if (IsSetNewSpaceBit() && (SpaceForExternal() == Heap::kOld)) {
279 isolate_group->heap()->PromotedExternal(external_size());
280 ClearExternalNewSpaceBit();
281 }
282 }
283
284 // Idempotent. Called when the handle is explicitly deleted or the
285 // referent becomes unreachable.
286 void EnsureFreedExternal(IsolateGroup* isolate_group) {
287 isolate_group->heap()->FreedExternal(external_size(), SpaceForExternal());
288 set_external_size(0);
289 }
290
291 static FinalizablePersistentHandle* Cast(Dart_WeakPersistentHandle handle);
292 static FinalizablePersistentHandle* Cast(Dart_FinalizableHandle handle);
293
294 private:
295 enum {
296 kExternalNewSpaceBit = 0,
297 kExternalSizeBits = 1,
298 kExternalSizeBitsSize = (kBitsPerWord - 1),
299 };
300
301 union HandleFinalizer {
302 Dart_HandleFinalizer finalizable;
303 Dart_WeakPersistentHandleFinalizer weak_persistent;
304 HandleFinalizer(Dart_HandleFinalizer finalizer) : finalizable(finalizer) {}
305 HandleFinalizer(Dart_WeakPersistentHandleFinalizer finalizer)
306 : weak_persistent(finalizer) {}
307 HandleFinalizer() : finalizable(nullptr) {}
308 };
309
310 // This part of external_data_ is the number of externally allocated bytes.
311 class ExternalSizeInWordsBits : public BitField<uword,
312 intptr_t,
313 kExternalSizeBits,
314 kExternalSizeBitsSize> {};
315 // This bit of external_data_ is true if the referent was created in new
316 // space and UpdateRelocated has not yet detected any promotion.
317 class ExternalNewSpaceBit
318 : public BitField<uword, bool, kExternalNewSpaceBit, 1> {};
319
320 friend class FinalizablePersistentHandles;
321
322 FinalizablePersistentHandle()
323 : raw_(nullptr),
324 peer_(NULL),
325 external_data_(0),
326 callback_(HandleFinalizer()) {}
327 ~FinalizablePersistentHandle() {}
328
329 static void Finalize(IsolateGroup* isolate_group,
330 FinalizablePersistentHandle* handle);
331
332 // Overload the raw_ field as a next pointer when adding freed
333 // handles to the free list.
334 FinalizablePersistentHandle* Next() {
335 return reinterpret_cast<FinalizablePersistentHandle*>(
336 static_cast<uword>(raw_));
337 }
338 void SetNext(FinalizablePersistentHandle* free_list) {
339 raw_ = static_cast<ObjectPtr>(reinterpret_cast<uword>(free_list));
340 ASSERT(!raw_->IsHeapObject());
341 }
342
343 void FreeHandle(FinalizablePersistentHandle* free_list) {
344 Clear();
345 SetNext(free_list);
346 }
347
348 void Clear() {
349 raw_ = Object::null();
350 peer_ = NULL;
351 external_data_ = 0;
352 callback_ = HandleFinalizer();
353 auto_delete_ = false;
354 callback_signature_ = CallbackSignature::kWeakPersistentHandleFinalizer;
355 }
356
357 void set_raw(ObjectPtr raw) { raw_ = raw; }
358 void set_raw(const LocalHandle& ref) { raw_ = ref.raw(); }
359 void set_raw(const Object& object) { raw_ = object.raw(); }
360
361 void set_peer(void* peer) { peer_ = peer; }
362
363 void set_callback_signature(CallbackSignature callback_signature) {
364 callback_signature_ = callback_signature;
365 }
366
367 void set_callback(HandleFinalizer callback) { callback_ = callback; }
368
369 void set_auto_delete(bool auto_delete) { auto_delete_ = auto_delete; }
370
371 void set_external_size(intptr_t size) {
372 intptr_t size_in_words = Utils::RoundUp(size, kObjectAlignment) / kWordSize;
373 ASSERT(ExternalSizeInWordsBits::is_valid(size_in_words));
374 external_data_ =
375 ExternalSizeInWordsBits::update(size_in_words, external_data_);
376 }
377
378 bool IsSetNewSpaceBit() const {
379 return ExternalNewSpaceBit::decode(external_data_);
380 }
381
382 void SetExternalNewSpaceBit() {
383 external_data_ = ExternalNewSpaceBit::update(true, external_data_);
384 }
385
386 void ClearExternalNewSpaceBit() {
387 external_data_ = ExternalNewSpaceBit::update(false, external_data_);
388 }
389
390 // Returns the space to charge for the external size.
391 Heap::Space SpaceForExternal() const {
392 // Non-heap and VM-heap objects count as old space here.
393 return raw_->IsSmiOrOldObject() ? Heap::kOld : Heap::kNew;
394 }
395
396 ObjectPtr raw_;
397 void* peer_;
398 uword external_data_;
399 HandleFinalizer callback_;
400 bool auto_delete_;
401 CallbackSignature callback_signature_;
402
403 DISALLOW_ALLOCATION(); // Allocated through AllocateHandle methods.
404 DISALLOW_COPY_AND_ASSIGN(FinalizablePersistentHandle);
405};
406
407// Local handles repository structure.
408static const int kLocalHandleSizeInWords = sizeof(LocalHandle) / kWordSize;
409static const int kLocalHandlesPerChunk = 64;
410static const int kOffsetOfRawPtrInLocalHandle = 0;
411class LocalHandles : Handles<kLocalHandleSizeInWords,
412 kLocalHandlesPerChunk,
413 kOffsetOfRawPtrInLocalHandle> {
414 public:
415 LocalHandles()
416 : Handles<kLocalHandleSizeInWords,
417 kLocalHandlesPerChunk,
418 kOffsetOfRawPtrInLocalHandle>() {
419 if (FLAG_trace_handles) {
420 OS::PrintErr("*** Starting a new Local handle block 0x%" Px "\n",
421 reinterpret_cast<intptr_t>(this));
422 }
423 }
424 ~LocalHandles() {
425 if (FLAG_trace_handles) {
426 OS::PrintErr("*** Handle Counts for 0x(%" Px "):Scoped = %d\n",
427 reinterpret_cast<intptr_t>(this), CountHandles());
428 OS::PrintErr("*** Deleting Local handle block 0x%" Px "\n",
429 reinterpret_cast<intptr_t>(this));
430 }
431 }
432
433 // Visit all object pointers stored in the various handles.
434 void VisitObjectPointers(ObjectPointerVisitor* visitor) {
435 visitor->set_gc_root_type("local handle");
436 Handles<kLocalHandleSizeInWords, kLocalHandlesPerChunk,
437 kOffsetOfRawPtrInLocalHandle>::VisitObjectPointers(visitor);
438 visitor->clear_gc_root_type();
439 }
440
441 // Reset the local handles block for reuse.
442 void Reset() {
443 Handles<kLocalHandleSizeInWords, kLocalHandlesPerChunk,
444 kOffsetOfRawPtrInLocalHandle>::Reset();
445 }
446
447 // Allocates a handle in the current handle scope. This handle is valid only
448 // in the current handle scope and is destroyed when the current handle
449 // scope ends.
450 LocalHandle* AllocateHandle() {
451 return reinterpret_cast<LocalHandle*>(AllocateScopedHandle());
452 }
453
454 // Validate if passed in handle is a Local Handle.
455 bool IsValidHandle(Dart_Handle object) const {
456 return IsValidScopedHandle(reinterpret_cast<uword>(object));
457 }
458
459 // Returns a count of active handles (used for testing purposes).
460 int CountHandles() const { return CountScopedHandles(); }
461
462 private:
463 DISALLOW_COPY_AND_ASSIGN(LocalHandles);
464};
465
466// Persistent handles repository structure.
467static const int kPersistentHandleSizeInWords =
468 sizeof(PersistentHandle) / kWordSize;
469static const int kPersistentHandlesPerChunk = 64;
470static const int kOffsetOfRawPtrInPersistentHandle = 0;
471class PersistentHandles : Handles<kPersistentHandleSizeInWords,
472 kPersistentHandlesPerChunk,
473 kOffsetOfRawPtrInPersistentHandle> {
474 public:
475 PersistentHandles()
476 : Handles<kPersistentHandleSizeInWords,
477 kPersistentHandlesPerChunk,
478 kOffsetOfRawPtrInPersistentHandle>(),
479 free_list_(NULL) {
480 if (FLAG_trace_handles) {
481 OS::PrintErr("*** Starting a new Persistent handle block 0x%" Px "\n",
482 reinterpret_cast<intptr_t>(this));
483 }
484 }
485 ~PersistentHandles() {
486 free_list_ = NULL;
487 if (FLAG_trace_handles) {
488 OS::PrintErr("*** Handle Counts for 0x(%" Px "):Scoped = %d\n",
489 reinterpret_cast<intptr_t>(this), CountHandles());
490 OS::PrintErr("*** Deleting Persistent handle block 0x%" Px "\n",
491 reinterpret_cast<intptr_t>(this));
492 }
493 }
494
495 // Accessors.
496 PersistentHandle* free_list() const { return free_list_; }
497 void set_free_list(PersistentHandle* value) { free_list_ = value; }
498
499 // Visit all object pointers stored in the various handles.
500 void VisitObjectPointers(ObjectPointerVisitor* visitor) {
501 visitor->set_gc_root_type("persistent handle");
502 Handles<kPersistentHandleSizeInWords, kPersistentHandlesPerChunk,
503 kOffsetOfRawPtrInPersistentHandle>::VisitObjectPointers(visitor);
504 visitor->clear_gc_root_type();
505 }
506
507 // Visit all the handles.
508 void Visit(HandleVisitor* visitor) {
509 Handles<kPersistentHandleSizeInWords, kPersistentHandlesPerChunk,
510 kOffsetOfRawPtrInPersistentHandle>::Visit(visitor);
511 }
512
513 // Allocates a persistent handle, these have to be destroyed explicitly
514 // by calling FreeHandle.
515 PersistentHandle* AllocateHandle() {
516 PersistentHandle* handle;
517 if (free_list_ != NULL) {
518 handle = free_list_;
519 free_list_ = handle->Next();
520 } else {
521 handle = reinterpret_cast<PersistentHandle*>(AllocateScopedHandle());
522 }
523 handle->set_raw(Object::null());
524 return handle;
525 }
526
527 void FreeHandle(PersistentHandle* handle) {
528 handle->FreeHandle(free_list());
529 set_free_list(handle);
530 }
531
532 // Validate if passed in handle is a Persistent Handle.
533 bool IsValidHandle(Dart_PersistentHandle object) const {
534 return IsValidScopedHandle(reinterpret_cast<uword>(object));
535 }
536
537 bool IsFreeHandle(Dart_PersistentHandle object) const {
538 PersistentHandle* handle = free_list_;
539 while (handle != NULL) {
540 if (handle == reinterpret_cast<PersistentHandle*>(object)) {
541 return true;
542 }
543 handle = handle->Next();
544 }
545 return false;
546 }
547
548 // Returns a count of active handles (used for testing purposes).
549 int CountHandles() const { return CountScopedHandles(); }
550
551 private:
552 PersistentHandle* free_list_;
553 DISALLOW_COPY_AND_ASSIGN(PersistentHandles);
554};
555
556// Finalizable persistent handles repository structure.
557static const int kFinalizablePersistentHandleSizeInWords =
558 sizeof(FinalizablePersistentHandle) / kWordSize;
559static const int kFinalizablePersistentHandlesPerChunk = 64;
560static const int kOffsetOfRawPtrInFinalizablePersistentHandle = 0;
561class FinalizablePersistentHandles
562 : Handles<kFinalizablePersistentHandleSizeInWords,
563 kFinalizablePersistentHandlesPerChunk,
564 kOffsetOfRawPtrInFinalizablePersistentHandle> {
565 public:
566 FinalizablePersistentHandles()
567 : Handles<kFinalizablePersistentHandleSizeInWords,
568 kFinalizablePersistentHandlesPerChunk,
569 kOffsetOfRawPtrInFinalizablePersistentHandle>(),
570 free_list_(NULL) {}
571 ~FinalizablePersistentHandles() { free_list_ = NULL; }
572
573 // Accessors.
574 FinalizablePersistentHandle* free_list() const { return free_list_; }
575 void set_free_list(FinalizablePersistentHandle* value) { free_list_ = value; }
576
577 // Visit all handles stored in the various handle blocks.
578 void VisitHandles(HandleVisitor* visitor) {
579 Handles<kFinalizablePersistentHandleSizeInWords,
580 kFinalizablePersistentHandlesPerChunk,
581 kOffsetOfRawPtrInFinalizablePersistentHandle>::Visit(visitor);
582 }
583
584 // Visit all object pointers stored in the various handles.
585 void VisitObjectPointers(ObjectPointerVisitor* visitor) {
586 visitor->set_gc_root_type("weak persistent handle");
587 Handles<kFinalizablePersistentHandleSizeInWords,
588 kFinalizablePersistentHandlesPerChunk,
589 kOffsetOfRawPtrInFinalizablePersistentHandle>::
590 VisitObjectPointers(visitor);
591 visitor->clear_gc_root_type();
592 }
593
594 // Allocates a persistent handle, these have to be destroyed explicitly
595 // by calling FreeHandle.
596 FinalizablePersistentHandle* AllocateHandle() {
597 FinalizablePersistentHandle* handle;
598 if (free_list_ != NULL) {
599 handle = free_list_;
600 free_list_ = handle->Next();
601 handle->set_raw(Object::null());
602 return handle;
603 }
604
605 handle =
606 reinterpret_cast<FinalizablePersistentHandle*>(AllocateScopedHandle());
607 handle->Clear();
608 return handle;
609 }
610
611 void FreeHandle(FinalizablePersistentHandle* handle) {
612 handle->FreeHandle(free_list());
613 set_free_list(handle);
614 }
615
616 // Validate if passed in handle is a Persistent Handle.
617 bool IsValidHandle(Dart_WeakPersistentHandle object) const {
618 return IsValidScopedHandle(reinterpret_cast<uword>(object));
619 }
620
621 bool IsValidHandle(Dart_FinalizableHandle object) const {
622 return IsValidScopedHandle(reinterpret_cast<uword>(object));
623 }
624
625 bool IsFreeHandle(Dart_WeakPersistentHandle object) const {
626 FinalizablePersistentHandle* handle = free_list_;
627 while (handle != NULL) {
628 if (handle == reinterpret_cast<FinalizablePersistentHandle*>(object)) {
629 return true;
630 }
631 handle = handle->Next();
632 }
633 return false;
634 }
635
636 // Returns a count of active handles (used for testing purposes).
637 int CountHandles() const { return CountScopedHandles(); }
638
639 private:
640 FinalizablePersistentHandle* free_list_;
641 DISALLOW_COPY_AND_ASSIGN(FinalizablePersistentHandles);
642};
643
644// Structure used for the implementation of local scopes used in dart_api.
645// These local scopes manage handles and memory allocated in the scope.
646class ApiLocalScope {
647 public:
648 ApiLocalScope(ApiLocalScope* previous, uword stack_marker)
649 : previous_(previous), stack_marker_(stack_marker) {}
650 ~ApiLocalScope() { previous_ = NULL; }
651
652 // Reinit the ApiLocalScope to new values.
653 void Reinit(Thread* thread, ApiLocalScope* previous, uword stack_marker) {
654 previous_ = previous;
655 stack_marker_ = stack_marker;
656 zone_.Reinit(thread);
657 }
658
659 // Reset the ApiLocalScope so that it can be reused again.
660 void Reset(Thread* thread) {
661 local_handles_.Reset();
662 zone_.Reset(thread);
663 previous_ = NULL;
664 stack_marker_ = 0;
665 }
666
667 // Accessors.
668 ApiLocalScope* previous() const { return previous_; }
669 uword stack_marker() const { return stack_marker_; }
670 void set_previous(ApiLocalScope* value) { previous_ = value; }
671 LocalHandles* local_handles() { return &local_handles_; }
672 Zone* zone() { return zone_.GetZone(); }
673
674 private:
675 ApiLocalScope* previous_;
676 uword stack_marker_;
677 LocalHandles local_handles_;
678 ApiZone zone_;
679
680 DISALLOW_COPY_AND_ASSIGN(ApiLocalScope);
681};
682
683class ApiNativeScope {
684 public:
685 ApiNativeScope() {
686 // Currently no support for nesting native scopes.
687 ASSERT(Current() == NULL);
688 OSThread::SetThreadLocal(Api::api_native_key_,
689 reinterpret_cast<uword>(this));
690 // We manually increment the memory usage counter since there is memory
691 // initially allocated within the zone on creation.
692 IncrementNativeScopeMemoryCapacity(zone_.GetZone()->CapacityInBytes());
693 }
694
695 ~ApiNativeScope() {
696 ASSERT(Current() == this);
697 OSThread::SetThreadLocal(Api::api_native_key_, 0);
698 // We must also manually decrement the memory usage counter since the native
699 // is still holding it's initial memory and ~Zone() won't be able to
700 // determine which memory usage counter to decrement.
701 DecrementNativeScopeMemoryCapacity(zone_.GetZone()->CapacityInBytes());
702 }
703
704 static inline ApiNativeScope* Current() {
705 return reinterpret_cast<ApiNativeScope*>(
706 OSThread::GetThreadLocal(Api::api_native_key_));
707 }
708
709 static uintptr_t current_memory_usage() { return current_memory_usage_; }
710
711 static void IncrementNativeScopeMemoryCapacity(intptr_t size) {
712 current_memory_usage_.fetch_add(size);
713 }
714
715 static void DecrementNativeScopeMemoryCapacity(intptr_t size) {
716 current_memory_usage_.fetch_sub(size);
717 }
718
719 Zone* zone() {
720 Zone* result = zone_.GetZone();
721 ASSERT(result->handles()->CountScopedHandles() == 0);
722 ASSERT(result->handles()->CountZoneHandles() == 0);
723 return result;
724 }
725
726 private:
727 // The current total memory usage within ApiNativeScopes.
728 static RelaxedAtomic<intptr_t> current_memory_usage_;
729
730 ApiZone zone_;
731};
732
733// Api growable arrays use a zone for allocation. The constructor
734// picks the zone from the current isolate if in an isolate
735// environment. When outside an isolate environment it picks the zone
736// from the current native scope.
737template <typename T>
738class ApiGrowableArray : public BaseGrowableArray<T, ValueObject, Zone> {
739 public:
740 explicit ApiGrowableArray(int initial_capacity)
741 : BaseGrowableArray<T, ValueObject, Zone>(
742 initial_capacity,
743 ApiNativeScope::Current()->zone()) {}
744 ApiGrowableArray()
745 : BaseGrowableArray<T, ValueObject, Zone>(
746 ApiNativeScope::Current()->zone()) {}
747 ApiGrowableArray(intptr_t initial_capacity, Zone* zone)
748 : BaseGrowableArray<T, ValueObject, Zone>(initial_capacity, zone) {}
749};
750
751// Implementation of the API State used in dart api for maintaining
752// local scopes, persistent handles etc. These are setup on a per isolate
753// group basis and destroyed when the isolate group is shutdown.
754class ApiState {
755 public:
756 ApiState()
757 : persistent_handles_(),
758 weak_persistent_handles_(),
759 null_(NULL),
760 true_(NULL),
761 false_(NULL),
762 acquired_error_(NULL) {}
763 ~ApiState() {
764 if (null_ != NULL) {
765 persistent_handles_.FreeHandle(null_);
766 null_ = NULL;
767 }
768 if (true_ != NULL) {
769 persistent_handles_.FreeHandle(true_);
770 true_ = NULL;
771 }
772 if (false_ != NULL) {
773 persistent_handles_.FreeHandle(false_);
774 false_ = NULL;
775 }
776 if (acquired_error_ != NULL) {
777 persistent_handles_.FreeHandle(acquired_error_);
778 acquired_error_ = NULL;
779 }
780 }
781
782 void MergeOtherApiState(ApiState* api_state);
783
784 void VisitObjectPointersUnlocked(ObjectPointerVisitor* visitor) {
785 persistent_handles_.VisitObjectPointers(visitor);
786 if (visitor->visit_weak_persistent_handles()) {
787 weak_persistent_handles_.VisitObjectPointers(visitor);
788 }
789 }
790
791 void VisitWeakHandlesUnlocked(HandleVisitor* visitor) {
792 weak_persistent_handles_.VisitHandles(visitor);
793 }
794
795 PersistentHandle* AllocatePersistentHandle() {
796 MutexLocker ml(&mutex_);
797 return persistent_handles_.AllocateHandle();
798 }
799 void FreePersistentHandle(PersistentHandle* ref) {
800 MutexLocker ml(&mutex_);
801 persistent_handles_.FreeHandle(ref);
802 }
803
804 FinalizablePersistentHandle* AllocateWeakPersistentHandle() {
805 MutexLocker ml(&mutex_);
806 return weak_persistent_handles_.AllocateHandle();
807 }
808
809 void FreeWeakPersistentHandle(FinalizablePersistentHandle* weak_ref) {
810 MutexLocker ml(&mutex_);
811 weak_persistent_handles_.FreeHandle(weak_ref);
812 }
813
814 bool IsValidPersistentHandle(Dart_PersistentHandle object) {
815 MutexLocker ml(&mutex_);
816 return persistent_handles_.IsValidHandle(object);
817 }
818
819 bool IsActivePersistentHandle(Dart_PersistentHandle object) {
820 MutexLocker ml(&mutex_);
821 return persistent_handles_.IsValidHandle(object) &&
822 !persistent_handles_.IsFreeHandle(object);
823 }
824
825 bool IsValidWeakPersistentHandle(Dart_WeakPersistentHandle object) {
826 MutexLocker ml(&mutex_);
827 return weak_persistent_handles_.IsValidHandle(object);
828 }
829
830 bool IsValidFinalizableHandle(Dart_FinalizableHandle object) {
831 MutexLocker ml(&mutex_);
832 return weak_persistent_handles_.IsValidHandle(object);
833 }
834
835 bool IsActiveWeakPersistentHandle(Dart_WeakPersistentHandle object) {
836 MutexLocker ml(&mutex_);
837 return weak_persistent_handles_.IsValidHandle(object) &&
838 !weak_persistent_handles_.IsFreeHandle(object);
839 }
840
841 bool IsProtectedHandle(PersistentHandle* object) {
842 MutexLocker ml(&mutex_);
843 if (object == NULL) return false;
844 return object == null_ || object == true_ || object == false_;
845 }
846
847 int CountPersistentHandles() {
848 MutexLocker ml(&mutex_);
849 return persistent_handles_.CountHandles();
850 }
851
852 PersistentHandle* AcquiredError() {
853 // The ApiError pre-allocated in the "vm-isolate" since we will not be able
854 // to allocate it when the error actually occurs.
855 // When the error occurs there will be outstanding acquires to internal
856 // data pointers making it unsafe to allocate objects on the dart heap.
857 MutexLocker ml(&mutex_);
858 if (acquired_error_ == nullptr) {
859 acquired_error_ = persistent_handles_.AllocateHandle();
860 acquired_error_->set_raw(ApiError::typed_data_acquire_error());
861 }
862 return acquired_error_;
863 }
864
865 void RunWithLockedPersistentHandles(
866 std::function<void(PersistentHandles&)> fun) {
867 MutexLocker ml(&mutex_);
868 fun(persistent_handles_);
869 }
870
871 void RunWithLockedWeakPersistentHandles(
872 std::function<void(FinalizablePersistentHandles&)> fun) {
873 MutexLocker ml(&mutex_);
874 fun(weak_persistent_handles_);
875 }
876
877 WeakTable* acquired_table() { return &acquired_table_; }
878
879 private:
880 Mutex mutex_;
881
882 PersistentHandles persistent_handles_;
883 FinalizablePersistentHandles weak_persistent_handles_;
884 WeakTable acquired_table_;
885
886 // Persistent handles to important objects.
887 PersistentHandle* null_;
888 PersistentHandle* true_;
889 PersistentHandle* false_;
890 PersistentHandle* acquired_error_;
891
892 DISALLOW_COPY_AND_ASSIGN(ApiState);
893};
894
895inline FinalizablePersistentHandle* FinalizablePersistentHandle::New(
896 Isolate* isolate,
897 const Object& object,
898 void* peer,
899 Dart_WeakPersistentHandleFinalizer callback,
900 intptr_t external_size,
901 bool auto_delete) {
902 ApiState* state = isolate->group()->api_state();
903 ASSERT(state != NULL);
904 ASSERT(callback != NULL);
905 FinalizablePersistentHandle* ref = state->AllocateWeakPersistentHandle();
906 ref->set_raw(object);
907 ref->set_peer(peer);
908 ref->set_callback_signature(
909 CallbackSignature::kWeakPersistentHandleFinalizer);
910 ref->set_callback(HandleFinalizer(callback));
911 ref->set_auto_delete(auto_delete);
912 // This may trigger GC, so it must be called last.
913 ref->SetExternalSize(external_size, isolate->group());
914 return ref;
915}
916
917inline FinalizablePersistentHandle* FinalizablePersistentHandle::New(
918 Isolate* isolate,
919 const Object& object,
920 void* peer,
921 Dart_HandleFinalizer callback,
922 intptr_t external_size,
923 bool auto_delete) {
924 ApiState* state = isolate->group()->api_state();
925 ASSERT(state != NULL);
926 FinalizablePersistentHandle* ref = state->AllocateWeakPersistentHandle();
927 ref->set_raw(object);
928 ref->set_peer(peer);
929 ref->set_callback_signature(CallbackSignature::kHandleFinalizer);
930 ref->set_callback(HandleFinalizer(callback));
931 ref->set_auto_delete(auto_delete);
932 // This may trigger GC, so it must be called last.
933 ref->SetExternalSize(external_size, isolate->group());
934 return ref;
935}
936
937} // namespace dart
938
939#endif // RUNTIME_VM_DART_API_STATE_H_
940