v8
V8 is Google’s open source high-performance JavaScript and WebAssembly engine, written in C++.
Loading...
Searching...
No Matches
handles.h
Go to the documentation of this file.
1// Copyright 2011 the V8 project authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5#ifndef V8_HANDLES_HANDLES_H_
6#define V8_HANDLES_HANDLES_H_
7
8#include <type_traits>
9#include <vector>
10
11#include "src/base/hashing.h"
12#include "src/base/macros.h"
14#include "src/common/checks.h"
15#include "src/common/globals.h"
16#include "src/objects/casting.h"
17#include "src/objects/tagged.h"
18#include "v8-handle-base.h" // NOLINT(build/include_directory)
19
20#ifdef V8_ENABLE_DIRECT_HANDLE
21#include "src/flags/flags.h"
22#endif
23
24namespace v8 {
25
26class HandleScope;
27
28namespace internal {
29
30// Forward declarations.
31#ifdef V8_ENABLE_DIRECT_HANDLE
32class DirectHandleBase;
33#endif
34template <typename T>
35class DirectHandleUnchecked;
36class HandleScopeImplementer;
37class Isolate;
38class LocalHeap;
39class LocalIsolate;
40class TaggedIndex;
41class Object;
42class OrderedHashMap;
43class OrderedHashSet;
44class OrderedNameDictionary;
45class RootVisitor;
46class SmallOrderedHashMap;
47class SmallOrderedHashSet;
48class SmallOrderedNameDictionary;
49class SwissNameDictionary;
50class WasmExportedFunctionData;
51class ZoneAllocationPolicy;
52
54
55// ----------------------------------------------------------------------------
56// Base class for Handle instantiations. Don't use directly.
58 public:
59 // Check if this handle refers to the exact same object as the other handle.
60 V8_INLINE bool is_identical_to(const HandleBase& that) const;
61#ifdef V8_ENABLE_DIRECT_HANDLE
62 V8_INLINE bool is_identical_to(const DirectHandleBase& that) const;
63#else
64 template <typename T>
65 V8_INLINE bool is_identical_to(const DirectHandle<T>& that) const {
66 return is_identical_to(that.handle_);
67 }
68#endif
69 V8_INLINE bool is_null() const { return location_ == nullptr; }
70
71 // Returns the raw address where this handle is stored. This should only be
72 // used for hashing handles; do not ever try to dereference it.
74 return reinterpret_cast<Address>(location_);
75 }
76
77 // Returns the address to where the raw pointer is stored.
78 // TODO(leszeks): This should probably be a const Address*, to encourage using
79 // PatchValue for modifying the handle's value.
82 return location_;
83 }
84
85#ifdef V8_ENABLE_DIRECT_HANDLE
88 }
89#else
93#endif // V8_ENABLE_DIRECT_HANDLE
94
95 protected:
96#ifdef V8_ENABLE_DIRECT_HANDLE
97 friend class DirectHandleBase;
98
101 Isolate* isolate);
103 LocalIsolate* isolate);
105 LocalHeap* local_heap);
106
107 template <typename T>
109 template <typename T>
111 Isolate* isolate);
112 template <typename T>
114 LocalIsolate* isolate);
115 template <typename T>
117 LocalHeap* local_heap);
118#endif // V8_ENABLE_DIRECT_HANDLE
119
121 V8_INLINE explicit HandleBase(Address object, Isolate* isolate);
122 V8_INLINE explicit HandleBase(Address object, LocalIsolate* isolate);
123 V8_INLINE explicit HandleBase(Address object, LocalHeap* local_heap);
124
125#ifdef DEBUG
127#else
128 V8_INLINE bool IsDereferenceAllowed() const { return true; }
129#endif // DEBUG
130
131 // This uses type Address* as opposed to a pointer type to a typed
132 // wrapper class, because it doesn't point to instances of such a
133 // wrapper class. Design overview: https://goo.gl/Ph4CGz
135};
136
137// ----------------------------------------------------------------------------
138// A Handle provides a reference to an object that survives relocation by
139// the garbage collector.
140//
141// Handles are only valid within a HandleScope. When a handle is created
142// for an object a cell is allocated in the current HandleScope.
143//
144// Also note that Handles do not provide default equality comparison or hashing
145// operators on purpose. Such operators would be misleading, because intended
146// semantics is ambiguous between Handle location and object identity. Instead
147// use either {is_identical_to} or {location} explicitly.
148template <typename T>
149class Handle final : public HandleBase {
150 public:
151 // Handles denote strong references.
152 static_assert(!is_maybe_weak_v<T>);
153
155
157 // TODO(jkummerow): Runtime type check here as a SLOW_DCHECK?
158 }
159
160 V8_INLINE Handle(Tagged<T> object, Isolate* isolate);
161 V8_INLINE Handle(Tagged<T> object, LocalIsolate* isolate);
162 V8_INLINE Handle(Tagged<T> object, LocalHeap* local_heap);
163
164 // Allocate a new handle for the object.
165 V8_INLINE static Handle<T> New(Tagged<T> object, Isolate* isolate);
166
167 // Constructor for handling automatic up casting.
168 // Ex. Handle<JSFunction> can be passed when Handle<Object> is expected.
169 template <typename S>
173
174 // Access a member of the T object referenced by this handle.
175 //
176 // This is actually a double dereference -- first it dereferences the Handle
177 // pointing to a Tagged<T>, and then continues through Tagged<T>::operator->.
178 // This means that this is only permitted for Tagged<T> with an operator->,
179 // i.e. for on-heap object T.
181 // For non-HeapObjects, there's no on-heap object to dereference, so
182 // disallow using operator->.
183 //
184 // If you got an error here and want to access the Tagged<T>, use
185 // operator* -- e.g. for `Tagged<Smi>::value()`, use `(*handle).value()`.
186 static_assert(
188 "This handle does not reference a heap object. Use `(*handle).foo`.");
189 return **this;
190 }
191
193 // This static type check also fails for forward class declarations. We
194 // check on access instead of on construction to allow Handles to forward
195 // declared types.
196 static_assert(is_taggable_v<T>, "static type violation");
197 // Direct construction of Tagged from address, without a type check, because
198 // we rather trust Handle<T> to contain a T than include all the respective
199 // -inl.h headers for SLOW_DCHECKs.
201 return Tagged<T>(*location());
202 }
203
204 // Consider declaring values that contain empty handles as
205 // MaybeHandle to force validation before being used as handles.
206 static const Handle<T> null() { return Handle<T>(); }
207
208 // Location equality.
209 bool equals(Handle<T> other) const { return address() == other.address(); }
210
211 // Patches this Handle's value, in-place, with a new value. All indirect
212 // handles with the same location will see this update.
213 void PatchValue(Tagged<T> new_value) {
215 *location_ = new_value.ptr();
216 }
217
218 // Provide function object for location equality comparison.
219 struct equal_to {
221 return lhs.equals(rhs);
222 }
223 };
224
225 // Provide function object for location hashing.
226 struct hash {
227 V8_INLINE size_t operator()(Handle<T> const& handle) const {
228 return base::hash<Address>()(handle.address());
229 }
230 };
231
233
234 private:
235 // Handles of different classes are allowed to access each other's location_.
236 template <typename>
237 friend class Handle;
238 // MaybeHandle is allowed to access location_.
239 template <typename>
240 friend class MaybeHandle;
241 // Casts are allowed to access location_.
242 template <typename To, typename From>
244};
245
246template <typename T>
247std::ostream& operator<<(std::ostream& os, IndirectHandle<T> handle);
248
249// ----------------------------------------------------------------------------
250// A stack-allocated class that governs a number of local handles.
251// After a handle scope has been created, all local handles will be
252// allocated within that handle scope until either the handle scope is
253// deleted or another handle scope is created. If there is already a
254// handle scope and a new one is created, all allocations will take
255// place in the new handle scope until it is deleted. After that,
256// new handles will again be allocated in the original handle scope.
257//
258// After the handle scope of a local handle has been deleted the
259// garbage collector will no longer track the object stored in the
260// handle and may deallocate it. The behavior of accessing a handle
261// for which the handle scope has been deleted is undefined.
263 public:
264 explicit V8_INLINE HandleScope(Isolate* isolate);
265 inline HandleScope(HandleScope&& other) V8_NOEXCEPT;
266 HandleScope(const HandleScope&) = delete;
268
269 // Allow placement new.
270 void* operator new(size_t size, void* storage) {
271 return ::operator new(size, storage);
272 }
273
274 // Prevent heap allocation or illegal handle scopes.
275 void* operator new(size_t size) = delete;
276 void operator delete(void* size_t) = delete;
277
279
280 inline HandleScope& operator=(HandleScope&& other) V8_NOEXCEPT;
281
282 // Counts the number of allocated handles.
283 V8_EXPORT_PRIVATE static int NumberOfHandles(Isolate* isolate);
284
285 // Creates a new handle with the given value.
286 V8_INLINE static Address* CreateHandle(Isolate* isolate, Address value);
287
288 // Deallocates any extensions used by the current scope.
289 V8_EXPORT_PRIVATE static void DeleteExtensions(Isolate* isolate);
290
291 static Address current_next_address(Isolate* isolate);
292 static Address current_limit_address(Isolate* isolate);
293 static Address current_level_address(Isolate* isolate);
294
295 // Closes the HandleScope (invalidating all handles
296 // created in the scope of the HandleScope) and returns
297 // a Handle backed by the parent scope holding the
298 // value of the argument handle.
299 //
300 // TODO(42203211): When direct handles are enabled, the version with
301 // HandleType = DirectHandle does not need to be called, as it simply
302 // closes the scope (which is done by the scope's destructor anyway)
303 // and returns its parameter. This will be cleaned up after direct
304 // handles ship.
305 template <typename T, template <typename> typename HandleType>
306 requires(std::is_convertible_v<HandleType<T>, DirectHandle<T>>)
307 HandleType<T> CloseAndEscape(HandleType<T> handle_value);
308
309 Isolate* isolate() { return isolate_; }
310
311 // Limit for number of handles with --check-handle-count. This is
312 // large enough to compile natives and pass unit tests with some
313 // slack for future changes to natives.
314 static const int kCheckHandleThreshold = 30 * 1024;
315
316 private:
318 Address* prev_next_;
319 Address* prev_limit_;
320
321#ifdef V8_ENABLE_CHECKS
322 int scope_level_ = 0;
323#endif
324
325 // Close the handle scope resetting limits to a previous state.
326 static V8_INLINE void CloseScope(Isolate* isolate, Address* prev_next,
327 Address* prev_limit);
328
329 // Extend the handle scope making room for more handles.
330 V8_EXPORT_PRIVATE V8_NOINLINE static Address* Extend(Isolate* isolate);
331
332#if defined(ENABLE_GLOBAL_HANDLE_ZAPPING) || \
333 defined(ENABLE_LOCAL_HANDLE_ZAPPING)
334 // Zaps the handles in the half-open interval [start, end).
335 V8_EXPORT_PRIVATE static void ZapRange(Address* start, Address* end,
336 uintptr_t value = kHandleZapValue);
337#endif
338
339 friend class v8::HandleScope;
341 friend class Isolate;
342 friend class LocalHandles;
343 friend class LocalHandleScope;
344 friend class PersistentHandles;
345};
346
347// Forward declaration for CanonicalHandlesMap.
348template <typename V, class AllocationPolicy>
349class IdentityMap;
350
352
353// Seal off the current HandleScope so that new handles can only be created
354// if a new HandleScope is entered.
356 public:
357#ifndef DEBUG
358 explicit SealHandleScope(Isolate* isolate) {}
359 ~SealHandleScope() = default;
360#else
361 explicit inline SealHandleScope(Isolate* isolate);
362 inline ~SealHandleScope();
363
364 private:
366 Address* prev_limit_;
367 int prev_sealed_level_;
368#endif
369};
370
371struct HandleScopeData final {
372 static constexpr uint32_t kSizeInBytes =
374
377 int level;
379
380 void Initialize() {
381 next = limit = nullptr;
382 sealed_level = level = 0;
383 }
384};
385
386static_assert(HandleScopeData::kSizeInBytes == sizeof(HandleScopeData));
387
388template <typename T>
389struct is_direct_handle : public std::false_type {};
390template <typename T>
392
393#ifdef V8_ENABLE_DIRECT_HANDLE
394
395// Direct handles should not be used without conservative stack scanning,
396// as this would break the correctness of the GC.
398
399// ----------------------------------------------------------------------------
400// Base class for DirectHandle instantiations. Don't use directly.
401class V8_TRIVIAL_ABI DirectHandleBase :
402#ifdef ENABLE_SLOW_DCHECKS
404#else
405 public api_internal::StackAllocated<false>
406#endif
407{
408 public:
409 // Check if this handle refers to the exact same object as the other handle.
410 V8_INLINE bool is_identical_to(const HandleBase& that) const;
411 V8_INLINE bool is_identical_to(const DirectHandleBase& that) const;
412 V8_INLINE bool is_null() const { return obj_ == kTaggedNullAddress; }
413
414 V8_INLINE Address address() const { return obj_; }
415
417 return obj_;
418 }
419
420#ifdef ENABLE_SLOW_DCHECKS
421 // Counts the number of allocated handles for the current thread that are
422 // below the stack marker. The number is only accurate if
423 // V8_HAS_ATTRIBUTE_TRIVIAL_ABI, otherwise it's zero.
424 V8_INLINE static int NumberOfHandles() { return number_of_handles_; }
425
426 // Scope to temporarily reset the number of allocated handles.
427 class V8_NODISCARD ResetNumberOfHandlesScope {
428 public:
429 ResetNumberOfHandlesScope() : saved_number_of_handles_(number_of_handles_) {
430 number_of_handles_ = 0;
431 }
432 ~ResetNumberOfHandlesScope() {
433 number_of_handles_ = saved_number_of_handles_;
434 }
435
436 private:
437 int saved_number_of_handles_;
438 };
439#else
440 class V8_NODISCARD ResetNumberOfHandlesScope {};
441#endif // ENABLE_SLOW_DCHECKS
442
443 protected:
444 friend class HandleBase;
445
446#if defined(ENABLE_SLOW_DCHECKS) && V8_HAS_ATTRIBUTE_TRIVIAL_ABI
447 // In this case, DirectHandleBase becomes not trivially copyable.
448 V8_INLINE DirectHandleBase(const DirectHandleBase& other) V8_NOEXCEPT
449 : obj_(other.obj_) {
450 Register();
451 }
452 DirectHandleBase& operator=(const DirectHandleBase&) V8_NOEXCEPT = default;
453 V8_INLINE ~DirectHandleBase() V8_NOEXCEPT { Unregister(); }
454#endif
455
456 V8_INLINE explicit DirectHandleBase(Address object) : obj_(object) {
457 Register();
458 }
459
460#ifdef DEBUG
461 V8_EXPORT_PRIVATE bool IsDereferenceAllowed() const;
462#else
463 V8_INLINE bool IsDereferenceAllowed() const { return true; }
464#endif // DEBUG
465
466 DirectHandleBase(Address obj, no_checking_tag do_not_check)
467 : StackAllocated(do_not_check), obj_(obj) {
468 Register();
469 }
470
471 // This is a direct pointer to either a tagged object or SMI. Design overview:
472 // https://docs.google.com/document/d/1uRGYQM76vk1fc_aDqDH3pm2qhaJtnK2oyzeVng4cS6I/
473 Address obj_;
474
475 private:
476 V8_INLINE void Register() {
477#if defined(ENABLE_SLOW_DCHECKS) && V8_HAS_ATTRIBUTE_TRIVIAL_ABI
478 ++number_of_handles_;
479#endif
480 }
481
482 V8_INLINE void Unregister() {
483#if defined(ENABLE_SLOW_DCHECKS) && V8_HAS_ATTRIBUTE_TRIVIAL_ABI
484 SLOW_DCHECK(number_of_handles_ > 0);
485 --number_of_handles_;
486#endif
487 }
488
489#ifdef ENABLE_SLOW_DCHECKS
490 inline static thread_local int number_of_handles_ = 0;
491#endif
492};
493
494// ----------------------------------------------------------------------------
495// A DirectHandle provides a reference to an object without an intermediate
496// pointer.
497//
498// A DirectHandle is a simple wrapper around a tagged pointer to a heap object
499// or a SMI. Its methods are symmetrical with Handle, so that Handles can be
500// easily migrated.
501//
502// DirectHandles are intended to be used with conservative stack scanning, as
503// they do not provide a mechanism for keeping an object alive across a garbage
504// collection.
505//
506// Further motivation is explained in the design doc:
507// https://docs.google.com/document/d/1uRGYQM76vk1fc_aDqDH3pm2qhaJtnK2oyzeVng4cS6I/
508template <typename T>
509class DirectHandle : public DirectHandleBase {
510 public:
511 // Handles denote strong references.
512 static_assert(!is_maybe_weak_v<T>);
513
515
516 V8_INLINE DirectHandle(Tagged<T> object, Isolate* isolate)
517 : DirectHandle(object) {}
518 V8_INLINE DirectHandle(Tagged<T> object, LocalIsolate* isolate)
519 : DirectHandle(object) {}
520 V8_INLINE DirectHandle(Tagged<T> object, LocalHeap* local_heap)
521 : DirectHandle(object) {}
522
523 V8_INLINE static DirectHandle FromAddress(Address object) {
524 return DirectHandle(object);
525 }
526 V8_INLINE static DirectHandle FromSlot(Address* slot) {
527 return FromAddress(slot != nullptr ? *slot : kTaggedNullAddress);
528 }
529
530 V8_INLINE static DirectHandle<T> New(Tagged<T> object, Isolate* isolate) {
531 return DirectHandle<T>(object);
532 }
533
534 // Constructor for handling automatic up casting.
535 // Ex. DirectHandle<JSFunction> can be passed when DirectHandle<Object> is
536 // expected.
537 template <typename S, typename = std::enable_if_t<is_subtype_v<S, T>>>
539
540 template <typename S, typename = std::enable_if_t<is_subtype_v<S, T>>>
542 : DirectHandle(handle.location() != nullptr ? *handle.location()
544
545 V8_INLINE Tagged<T> operator->() const {
546 if constexpr (is_subtype_v<T, HeapObject>) {
547 return **this;
548 } else {
549 // For non-HeapObjects, there's no on-heap object to dereference, so
550 // disallow using operator->.
551 //
552 // If you got an error here and want to access the Tagged<T>, use
553 // operator* -- e.g. for `Tagged<Smi>::value()`, use `(*handle).value()`.
554 static_assert(
555 false,
556 "This handle does not reference a heap object. Use `(*handle).foo`.");
557 }
558 }
559
560 V8_INLINE Tagged<T> operator*() const {
561 // This static type check also fails for forward class declarations. We
562 // check on access instead of on construction to allow DirectHandles to
563 // forward declared types.
564 static_assert(is_taggable_v<T>, "static type violation");
565 // Direct construction of Tagged from address, without a type check, because
566 // we rather trust DirectHandle<T> to contain a T than include all the
567 // respective -inl.h headers for SLOW_DCHECKs.
568 SLOW_DCHECK(IsDereferenceAllowed());
569 return Tagged<T>(address());
570 }
571
572 // Consider declaring values that contain empty handles as
573 // MaybeDirectHandle to force validation before being used as handles.
574 V8_INLINE static const DirectHandle<T> null() { return DirectHandle<T>(); }
575
576 // Address equality.
577 bool equals(DirectHandle<T> other) const {
578 return address() == other.address();
579 }
580
581 // Sets this DirectHandle's value. This is equivalent to handle assignment,
582 // except for the check that is equivalent to that performed in
583 // Handle<T>::PatchValue.
584 // TODO(42203211): Calls to this method will eventually be replaced by direct
585 // handle assignments, when the migration to direct handles is complete.
586 void SetValue(Tagged<T> new_value) {
587 SLOW_DCHECK(obj_ != kTaggedNullAddress && IsDereferenceAllowed());
588 obj_ = new_value.ptr();
589 }
590
592
593 private:
594 // DirectHandles of different classes are allowed to access each other's
595 // obj_.
596 template <typename>
597 friend class DirectHandle;
598 // MaybeDirectHandle is allowed to access obj_.
599 template <typename>
600 friend class MaybeDirectHandle;
601 friend class DirectHandleUnchecked<T>;
602 // Casts are allowed to access obj_.
603 template <typename To, typename From>
605
606 V8_INLINE explicit DirectHandle(Tagged<T> object);
607 V8_INLINE explicit DirectHandle(Address object) : DirectHandleBase(object) {}
608
609 explicit DirectHandle(no_checking_tag do_not_check)
610 : DirectHandleBase(kTaggedNullAddress, do_not_check) {}
611 explicit DirectHandle(const DirectHandle<T>& other,
612 no_checking_tag do_not_check)
613 : DirectHandleBase(other.obj_, do_not_check) {}
614};
615
616template <typename T>
618 if (handle.is_null()) return IndirectHandle<T>();
619 return IndirectHandle<T>(HandleBase::indirect_handle(handle.address()));
620}
621
622template <typename T>
623IndirectHandle<T> indirect_handle(DirectHandle<T> handle, Isolate* isolate) {
624 if (handle.is_null()) return IndirectHandle<T>();
625 return IndirectHandle<T>(
626 HandleBase::indirect_handle(handle.address(), isolate));
627}
628
629template <typename T>
631 LocalIsolate* isolate) {
632 if (handle.is_null()) return IndirectHandle<T>();
633 return IndirectHandle<T>(
634 HandleBase::indirect_handle(handle.address(), isolate));
635}
636
637template <typename T>
639 LocalHeap* local_heap) {
640 if (handle.is_null()) return IndirectHandle<T>();
641 return IndirectHandle<T>(
642 HandleBase::indirect_handle(handle.address(), local_heap));
643}
644
645#else // !V8_ENABLE_DIRECT_HANDLE
646
647// ----------------------------------------------------------------------------
648// When conservative stack scanning is disabled, DirectHandle is a wrapper
649// around IndirectHandle (i.e. Handle). To preserve conservative stack scanning
650// semantics, DirectHandle be implicitly created from an IndirectHandle, but
651// does not implicitly convert to an IndirectHandle.
652template <typename T>
654#ifdef ENABLE_SLOW_DCHECKS
656#else
657 public api_internal::StackAllocated<false>
658#endif
659{
660 public:
661 V8_INLINE static const DirectHandle null() {
663 }
664 V8_INLINE static DirectHandle<T> New(Tagged<T> object, Isolate* isolate) {
665 return DirectHandle(Handle<T>::New(object, isolate));
666 }
667
669
671 : handle_(object, isolate) {}
673 : handle_(object, isolate) {}
675 : handle_(object, local_heap) {}
676
677 template <typename S>
679 requires(is_subtype_v<S, T>)
681
682 template <typename S>
684 requires(is_subtype_v<S, T>)
685 : handle_(handle) {}
686
687 V8_INLINE static DirectHandle FromSlot(Address* slot) {
688 return DirectHandle(IndirectHandle<T>(slot));
689 }
690
693 V8_INLINE bool is_null() const { return handle_.is_null(); }
694
695 V8_INLINE Address address() const { return handle_.address(); }
699
700 // Sets this Handle's value, in place, with a new value. Notice that, for
701 // efficiency reasons, this is implemented by calling method PatchValue of the
702 // underlying indirect handle. However, it should be considered as equivalent
703 // to a simple handle assignment, i.e., as if affecting only the specific
704 // handle and not all other indirect handles with the same location.
705 // TODO(42203211): Calls to this method will eventually be replaced by direct
706 // handle assignments, when the migration to direct handles is complete.
707 V8_INLINE void SetValue(Tagged<T> new_value) {
708 handle_.PatchValue(new_value);
709 }
710
711 V8_INLINE bool equals(DirectHandle<T> other) const {
712 return handle_.equals(other.handle_);
713 }
714
715 template <typename S>
717 return handle_.is_identical_to(other);
718 }
719 template <typename S>
721 return handle_.is_identical_to(other.handle_);
722 }
723
725
726 private:
727 // Handles of various different classes are allowed to access handle_.
728 friend class HandleBase;
729 template <typename>
730 friend class DirectHandle;
731 template <typename>
732 friend class MaybeDirectHandle;
733 friend class DirectHandleUnchecked<T>;
734 // Casts are allowed to access handle_.
735 template <typename To, typename From>
737 template <typename U>
739 template <typename U>
741 template <typename U>
743 LocalIsolate*);
744 template <typename U>
746
747 explicit DirectHandle(no_checking_tag do_not_check)
748 : StackAllocated(do_not_check), handle_() {}
749 explicit DirectHandle(const DirectHandle<T>& other,
750 no_checking_tag do_not_check)
751 : StackAllocated(do_not_check), handle_(other.handle_) {}
752
754};
755
756template <typename T>
760
761template <typename T>
766
767template <typename T>
772
773template <typename T>
778
779#endif // V8_ENABLE_DIRECT_HANDLE
780
781// A variant of DirectHandle that is suitable for off-stack allocation.
782// Used internally by DirectHandleVector<T>. Not to be used directly!
783template <typename T>
785 public:
787
788#if defined(ENABLE_SLOW_DCHECKS) && V8_HAS_ATTRIBUTE_TRIVIAL_ABI
789 // In this case, the check is also enforced in the copy constructor and we
790 // need to suppress it.
793 DirectHandleUnchecked& operator=(const DirectHandleUnchecked&)
794 V8_NOEXCEPT = default;
795#endif
796
797 // Implicit conversion from handles.
798 // NOLINTNEXTLINE(runtime/explicit)
801 // NOLINTNEXTLINE(runtime/explicit)
804};
805
806#if V8_ENABLE_DIRECT_HANDLE
807
808// Off-stack allocated direct handles must be registered as strong roots.
809// For off-stack indirect handles, this is not necessary.
810template <typename T>
811class StrongRootAllocator<DirectHandleUnchecked<T>>
812 : public StrongRootAllocatorBase {
813 public:
814 using value_type = DirectHandleUnchecked<T>;
815 static_assert(std::is_standard_layout_v<value_type>);
816 static_assert(sizeof(value_type) == sizeof(Address));
817
818 template <typename HeapOrIsolateT>
819 explicit StrongRootAllocator(HeapOrIsolateT* heap_or_isolate)
820 : StrongRootAllocatorBase(heap_or_isolate) {}
821 template <typename U>
822 StrongRootAllocator(const StrongRootAllocator<U>& other) noexcept
823 : StrongRootAllocatorBase(other) {}
824
825 value_type* allocate(size_t n) {
826 return reinterpret_cast<value_type*>(allocate_impl(n));
827 }
828 void deallocate(value_type* p, size_t n) noexcept {
829 return deallocate_impl(reinterpret_cast<Address*>(p), n);
830 }
831};
832
833#endif // V8_ENABLE_DIRECT_HANDLE
834
835template <typename T>
837 private:
839
840#ifdef V8_ENABLE_DIRECT_HANDLE
841 using allocator_type = internal::StrongRootAllocator<element_type>;
842
843 template <typename IsolateT>
844 static allocator_type make_allocator(IsolateT* isolate) noexcept {
845 return allocator_type(isolate);
846 }
847
848 using vector_type = std::vector<element_type, allocator_type>;
849#else
850 using vector_type = std::vector<element_type>;
851#endif
852
853 public:
858 using difference_type = ptrdiff_t;
859 using iterator =
862 internal::WrappedIterator<typename vector_type::const_iterator,
863 const value_type>;
864
865#ifdef V8_ENABLE_DIRECT_HANDLE
866 template <typename IsolateT>
867 explicit DirectHandleVector(IsolateT* isolate)
868 : backing_(make_allocator(isolate)) {}
869 template <typename IsolateT>
870 DirectHandleVector(IsolateT* isolate, size_t n)
871 : backing_(n, make_allocator(isolate)) {}
872 template <typename IsolateT>
873 DirectHandleVector(IsolateT* isolate, std::initializer_list<value_type> init)
874 : backing_(make_allocator(isolate)) {
875 if (init.size() == 0) return;
876 backing_.reserve(init.size());
877 backing_.insert(backing_.end(), init.begin(), init.end());
878 }
879#else
880 template <typename IsolateT>
881 explicit DirectHandleVector(IsolateT* isolate) : backing_() {}
882 template <typename IsolateT>
883 DirectHandleVector(IsolateT* isolate, size_t n) : backing_(n) {}
884 template <typename IsolateT>
885 DirectHandleVector(IsolateT* isolate, std::initializer_list<value_type> init)
886 : backing_() {
887 if (init.size() == 0) return;
888 backing_.reserve(init.size());
889 backing_.insert(backing_.end(), init.begin(), init.end());
890 }
891#endif
892
893 iterator begin() noexcept { return iterator(backing_.begin()); }
894 const_iterator begin() const noexcept {
895 return const_iterator(backing_.begin());
896 }
897 iterator end() noexcept { return iterator(backing_.end()); }
898 const_iterator end() const noexcept { return const_iterator(backing_.end()); }
899
900 size_t size() const noexcept { return backing_.size(); }
901 bool empty() const noexcept { return backing_.empty(); }
902 void reserve(size_t n) { backing_.reserve(n); }
903 void shrink_to_fit() { backing_.shrink_to_fit(); }
904
905 DirectHandle<T>& operator[](size_t n) { return backing_[n]; }
906 const DirectHandle<T>& operator[](size_t n) const { return backing_[n]; }
907
908 DirectHandle<T>& at(size_t n) { return backing_.at(n); }
909 const DirectHandle<T>& at(size_t n) const { return backing_.at(n); }
910
911 DirectHandle<T>& front() { return backing_.front(); }
912 const DirectHandle<T>& front() const { return backing_.front(); }
913 DirectHandle<T>& back() { return backing_.back(); }
914 const DirectHandle<T>& back() const { return backing_.back(); }
915
916 DirectHandle<T>* data() noexcept { return backing_.data(); }
917 const DirectHandle<T>* data() const noexcept { return backing_.data(); }
918
920 return iterator(backing_.insert(pos.base(), value));
921 }
922
923 template <typename InputIt>
924 iterator insert(const_iterator pos, InputIt first, InputIt last) {
925 return iterator(backing_.insert(pos.base(), first, last));
926 }
927
929 std::initializer_list<DirectHandle<T>> init) {
930 return iterator(backing_.insert(pos.base(), init.begin(), init.end()));
931 }
932
933 DirectHandleVector<T>& operator=(std::initializer_list<value_type> init) {
934 backing_.clear();
935 backing_.reserve(init.size());
936 backing_.insert(backing_.end(), init.begin(), init.end());
937 return *this;
938 }
939
940 void push_back(const DirectHandle<T>& x) { backing_.push_back(x); }
941 void pop_back() { backing_.pop_back(); }
942
943 template <typename... Args>
944 void emplace_back(Args&&... args) {
945 backing_.push_back(value_type{std::forward<Args>(args)...});
946 }
947
948 void clear() noexcept { backing_.clear(); }
949 void resize(size_t n) { backing_.resize(n); }
950 void resize(size_t n, const value_type& value) { backing_.resize(n, value); }
951 void swap(DirectHandleVector<T>& other) { backing_.swap(other.backing_); }
952
954 const DirectHandleVector<T>& y) {
955 return x.backing_ == y.backing_;
956 }
958 const DirectHandleVector<T>& y) {
959 return x.backing_ != y.backing_;
960 }
962 const DirectHandleVector<T>& y) {
963 return x.backing_ < y.backing_;
964 }
966 const DirectHandleVector<T>& y) {
967 return x.backing_ > y.backing_;
968 }
970 const DirectHandleVector<T>& y) {
971 return x.backing_ <= y.backing_;
972 }
974 const DirectHandleVector<T>& y) {
975 return x.backing_ >= y.backing_;
976 }
977
978 private:
980};
981
982template <typename T, size_t kSize>
984 private:
986
987#ifdef V8_ENABLE_DIRECT_HANDLE
988 using allocator_type = internal::StrongRootAllocator<element_type>;
989
990 template <typename IsolateT>
991 static allocator_type make_allocator(IsolateT* isolate) noexcept {
992 return allocator_type(isolate);
993 }
994
995 using vector_type =
997#else
999#endif
1000
1001 public:
1002 static constexpr size_t kInlineSize = kSize;
1007 using difference_type = ptrdiff_t;
1014
1015#ifdef V8_ENABLE_DIRECT_HANDLE
1016 template <typename IsolateT>
1017 explicit DirectHandleSmallVector(IsolateT* isolate)
1018 : backing_(make_allocator(isolate)) {}
1019 template <typename IsolateT>
1020 DirectHandleSmallVector(IsolateT* isolate, size_t n)
1021 : backing_(n, make_allocator(isolate)) {}
1022 template <typename IsolateT>
1023 DirectHandleSmallVector(IsolateT* isolate,
1024 std::initializer_list<value_type> init)
1025 : backing_(make_allocator(isolate)) {
1026 if (init.size() == 0) return;
1027 backing_.reserve(init.size());
1028 backing_.insert(backing_.end(), init.begin(), init.end());
1029 }
1030#else
1031 template <typename IsolateT>
1032 explicit DirectHandleSmallVector(IsolateT* isolate) : backing_() {}
1033 template <typename IsolateT>
1034 DirectHandleSmallVector(IsolateT* isolate, size_t n) : backing_(n) {}
1035 template <typename IsolateT>
1036 DirectHandleSmallVector(IsolateT* isolate,
1037 std::initializer_list<value_type> init)
1038 : backing_() {
1039 if (init.size() == 0) return;
1040 backing_.reserve(init.size());
1041 backing_.insert(backing_.end(), init.begin(), init.end());
1042 }
1043 template <typename IsolateT>
1046 : backing_() {
1047 if (init.size() == 0) return;
1048 backing_.reserve(init.size());
1049 backing_.insert(backing_.end(), init.begin(), init.end());
1050 }
1051#endif
1052
1053 value_type* data() noexcept { return backing_.data(); }
1054 const value_type* data() const noexcept { return backing_.data(); }
1055
1056 iterator begin() noexcept { return iterator(backing_.begin()); }
1057 const_iterator begin() const noexcept {
1058 return const_iterator(backing_.begin());
1059 }
1060 iterator end() noexcept { return iterator(backing_.end()); }
1061 const_iterator end() const noexcept { return const_iterator(backing_.end()); }
1062
1063 iterator rbegin() noexcept { return iterator(backing_.rbegin()); }
1064 const_iterator rbegin() const noexcept {
1065 return const_iterator(backing_.rbegin());
1066 }
1067 iterator rand() noexcept { return iterator(backing_.rend()); }
1068 const_iterator rend() const noexcept {
1069 return const_iterator(backing_.rend());
1070 }
1071
1072 size_t size() const noexcept { return backing_.size(); }
1073 bool empty() const noexcept { return backing_.empty(); }
1074 size_t capacity() const { return backing_.capacity(); }
1075
1077 const_reference front() const { return backing_.front(); }
1078 reference back() { return backing_.back(); }
1079 const_reference back() const { return backing_.back(); }
1080
1081 reference at(size_t n) { return backing_.at(n); }
1082 const_reference at(size_t n) const { return backing_.at(n); }
1083
1084 reference& operator[](size_t n) { return backing_[n]; }
1085 const_reference& operator[](size_t n) const { return backing_[n]; }
1086
1087 template <typename... Args>
1088 void emplace_back(Args&&... args) {
1089 backing_.emplace_back(std::forward<Args>(args)...);
1090 }
1091
1093 void pop_back(size_t count = 1) { backing_.pop_back(count); }
1094
1096 return iterator(backing_.insert(pos.base(), value));
1097 }
1099 return iterator(backing_.insert(pos.base(), count, value));
1100 }
1101 template <typename InputIt>
1102 iterator insert(const_iterator pos, InputIt first, InputIt last) {
1103 return iterator(backing_.insert(pos.base(), first, last));
1104 }
1105 iterator insert(const_iterator pos, std::initializer_list<value_type> init) {
1106 return iterator(backing_.insert(pos.base(), init.begin(), init.end()));
1107 }
1108
1109 void erase(iterator erase_start) { backing_.erase(erase_start.base()); }
1110 void resize(size_t new_size) { backing_.resize(new_size); }
1111 void resize(size_t new_size, const_reference initial_value) {
1112 backing_.resize(new_size, initial_value);
1113 }
1114
1115 void reserve(size_t n) { backing_.reserve(n); }
1116 void clear() noexcept { backing_.clear(); }
1117
1118 auto get_allocator() const { return backing_.get_allocator(); }
1119
1120 private:
1122};
1123
1124template <typename T, template <typename> typename HandleType>
1125 requires(std::is_convertible_v<HandleType<T>, DirectHandle<T>>)
1127 return handle;
1128}
1129
1130template <typename T>
1131std::ostream& operator<<(std::ostream& os, DirectHandle<T> handle);
1132
1133template <typename T>
1134struct is_direct_handle<DirectHandle<T>> : public std::true_type {};
1135
1136} // namespace internal
1137
1138#if defined(ENABLE_SLOW_DCHECKS) && V8_HAS_ATTRIBUTE_TRIVIAL_ABI
1139// In this configuration, DirectHandle is not trivially copyable (i.e., it is
1140// not an instance of `std::is_trivially_copyable`), because the copy
1141// constructor checks that direct handles are stack-allocated. By forcing an
1142// instance of `v8::base::is_trivially_copyable`, we allow it to be used in the
1143// place of template parameter `V` in `v8::base::ReadUnalignedValue<V>` and
1144// `v8::base::WriteUnalignedValue<V>`.
1145namespace base {
1146template <typename T>
1147struct is_trivially_copyable<::v8::internal::DirectHandle<T>>
1148 : public std::true_type {};
1149} // namespace base
1150#endif
1151
1152} // namespace v8
1153
1154#endif // V8_HANDLES_HANDLES_H_
Isolate * isolate_
DirectHandle< JSObject > obj_
#define SLOW_DCHECK(condition)
Definition checks.h:21
SourcePosition pos
static constexpr no_checking_tag do_not_check
size_t capacity() const
void erase(T *erase_start)
void pop_back(size_t count=1)
size_t size() const
T * insert(T *pos, const T &value)
void emplace_back(Args &&... args)
T & at(size_t index)
Allocator get_allocator() const
void reserve(size_t new_capacity)
void resize(size_t new_size)
constexpr size_t size() const
Definition vector.h:70
constexpr T * begin() const
Definition vector.h:96
constexpr T * end() const
Definition vector.h:103
iterator insert(const_iterator pos, InputIt first, InputIt last)
Definition handles.h:1102
void push_back(const_reference x)
Definition handles.h:1092
const_iterator rend() const noexcept
Definition handles.h:1068
void emplace_back(Args &&... args)
Definition handles.h:1088
const_iterator rbegin() const noexcept
Definition handles.h:1064
iterator insert(const_iterator pos, const_reference value)
Definition handles.h:1095
iterator insert(const_iterator pos, std::initializer_list< value_type > init)
Definition handles.h:1105
value_type * data() noexcept
Definition handles.h:1053
DirectHandleSmallVector(IsolateT *isolate, size_t n)
Definition handles.h:1034
size_t size() const noexcept
Definition handles.h:1072
internal::WrappedIterator< const element_type *, const value_type > const_iterator
Definition handles.h:1009
static constexpr size_t kInlineSize
Definition handles.h:1002
DirectHandleSmallVector(IsolateT *isolate, std::initializer_list< value_type > init)
Definition handles.h:1036
const_reference back() const
Definition handles.h:1079
reference & operator[](size_t n)
Definition handles.h:1084
const_reference front() const
Definition handles.h:1077
void erase(iterator erase_start)
Definition handles.h:1109
V8_INLINE DirectHandleSmallVector(base::Vector< const value_type > init)
Definition handles.h:1044
DirectHandleSmallVector(IsolateT *isolate)
Definition handles.h:1032
const_reference & operator[](size_t n) const
Definition handles.h:1085
const value_type * data() const noexcept
Definition handles.h:1054
internal::WrappedIterator< element_type *, value_type > iterator
Definition handles.h:1008
void resize(size_t new_size, const_reference initial_value)
Definition handles.h:1111
iterator insert(const_iterator pos, size_t count, const_reference value)
Definition handles.h:1098
const_iterator begin() const noexcept
Definition handles.h:1057
const_reference at(size_t n) const
Definition handles.h:1082
const_iterator end() const noexcept
Definition handles.h:1061
::v8::base::SmallVector< element_type, kSize > vector_type
Definition handles.h:998
DirectHandleUnchecked(const Handle< T > &other) V8_NOEXCEPT
Definition handles.h:802
DirectHandleUnchecked(const DirectHandle< T > &other) V8_NOEXCEPT
Definition handles.h:799
DirectHandleVector< T > & operator=(std::initializer_list< value_type > init)
Definition handles.h:933
void swap(DirectHandleVector< T > &other)
Definition handles.h:951
iterator insert(const_iterator pos, const DirectHandle< T > &value)
Definition handles.h:919
friend bool operator!=(const DirectHandleVector< T > &x, const DirectHandleVector< T > &y)
Definition handles.h:957
friend bool operator==(const DirectHandleVector< T > &x, const DirectHandleVector< T > &y)
Definition handles.h:953
const DirectHandle< T > & front() const
Definition handles.h:912
DirectHandle< T > * data() noexcept
Definition handles.h:916
const DirectHandle< T > & back() const
Definition handles.h:914
std::vector< element_type > vector_type
Definition handles.h:850
internal::WrappedIterator< typename vector_type::const_iterator, const value_type > const_iterator
Definition handles.h:861
iterator insert(const_iterator pos, std::initializer_list< DirectHandle< T > > init)
Definition handles.h:928
bool empty() const noexcept
Definition handles.h:901
DirectHandle< T > & at(size_t n)
Definition handles.h:908
iterator insert(const_iterator pos, InputIt first, InputIt last)
Definition handles.h:924
DirectHandleVector(IsolateT *isolate)
Definition handles.h:881
iterator begin() noexcept
Definition handles.h:893
const_iterator begin() const noexcept
Definition handles.h:894
iterator end() noexcept
Definition handles.h:897
DirectHandle< T > & front()
Definition handles.h:911
void push_back(const DirectHandle< T > &x)
Definition handles.h:940
DirectHandle< T > & operator[](size_t n)
Definition handles.h:905
internal::WrappedIterator< typename vector_type::iterator, value_type > iterator
Definition handles.h:859
const_iterator end() const noexcept
Definition handles.h:898
friend bool operator<=(const DirectHandleVector< T > &x, const DirectHandleVector< T > &y)
Definition handles.h:969
size_t size() const noexcept
Definition handles.h:900
const DirectHandle< T > & at(size_t n) const
Definition handles.h:909
DirectHandle< T > & back()
Definition handles.h:913
const DirectHandle< T > & operator[](size_t n) const
Definition handles.h:906
friend bool operator>=(const DirectHandleVector< T > &x, const DirectHandleVector< T > &y)
Definition handles.h:973
friend bool operator<(const DirectHandleVector< T > &x, const DirectHandleVector< T > &y)
Definition handles.h:961
friend bool operator>(const DirectHandleVector< T > &x, const DirectHandleVector< T > &y)
Definition handles.h:965
const DirectHandle< T > * data() const noexcept
Definition handles.h:917
void resize(size_t n, const value_type &value)
Definition handles.h:950
DirectHandleVector(IsolateT *isolate, size_t n)
Definition handles.h:883
void emplace_back(Args &&... args)
Definition handles.h:944
DirectHandleVector(IsolateT *isolate, std::initializer_list< value_type > init)
Definition handles.h:885
V8_INLINE bool is_null() const
Definition handles.h:693
static V8_INLINE const DirectHandle null()
Definition handles.h:661
V8_INLINE DirectHandle()=default
V8_INLINE bool is_identical_to(Handle< S > other) const
Definition handles.h:716
MaybeDirectHandle< T > MaybeType
Definition handles.h:724
V8_INLINE Address address() const
Definition handles.h:695
friend class DirectHandle
Definition handles.h:730
V8_INLINE DirectHandle(Tagged< T > object, LocalHeap *local_heap)
Definition handles.h:674
V8_INLINE void SetValue(Tagged< T > new_value)
Definition handles.h:707
V8_INLINE bool equals(DirectHandle< T > other) const
Definition handles.h:711
friend class MaybeDirectHandle
Definition handles.h:732
friend IndirectHandle< U > indirect_handle(DirectHandle< U >, LocalIsolate *)
friend IndirectHandle< U > indirect_handle(DirectHandle< U >, LocalHeap *)
friend IndirectHandle< U > indirect_handle(DirectHandle< U >)
V8_INLINE DirectHandle(IndirectHandle< S > handle)
Definition handles.h:683
V8_INLINE DirectHandle(Tagged< T > object, Isolate *isolate)
Definition handles.h:670
V8_INLINE DirectHandle(DirectHandle< S > handle)
Definition handles.h:678
DirectHandle(no_checking_tag do_not_check)
Definition handles.h:747
V8_INLINE IndirectHandle< T > operator->() const
Definition handles.h:691
IndirectHandle< T > handle_
Definition handles.h:753
V8_INLINE bool is_identical_to(DirectHandle< S > other) const
Definition handles.h:720
V8_INLINE DirectHandle(Tagged< T > object, LocalIsolate *isolate)
Definition handles.h:672
static V8_INLINE DirectHandle< T > New(Tagged< T > object, Isolate *isolate)
Definition handles.h:664
V8_INLINE Tagged< T > operator*() const
Definition handles.h:692
DirectHandle(const DirectHandle< T > &other, no_checking_tag do_not_check)
Definition handles.h:749
static V8_INLINE DirectHandle FromSlot(Address *slot)
Definition handles.h:687
friend DirectHandle< To > UncheckedCast(DirectHandle< From > value)
friend IndirectHandle< U > indirect_handle(DirectHandle< U >, Isolate *)
V8_INLINE ValueHelper::InternalRepresentationType repr() const
Definition handles.h:696
V8_INLINE HandleBase(Address *location)
Definition handles.h:120
V8_INLINE bool is_null() const
Definition handles.h:69
V8_INLINE Address address() const
Definition handles.h:73
V8_INLINE bool is_identical_to(const HandleBase &that) const
Definition handles-inl.h:36
V8_INLINE bool IsDereferenceAllowed() const
Definition handles.h:128
V8_INLINE ValueHelper::InternalRepresentationType repr() const
Definition handles.h:90
V8_INLINE bool is_identical_to(const DirectHandle< T > &that) const
Definition handles.h:65
V8_INLINE Address * location() const
Definition handles.h:80
HandleScope & operator=(const HandleScope &)=delete
HandleScope(const HandleScope &)=delete
V8_INLINE Handle(Address *location)
Definition handles.h:156
bool equals(Handle< T > other) const
Definition handles.h:209
V8_INLINE Tagged< T > operator*() const
Definition handles.h:192
friend class Handle
Definition handles.h:237
V8_INLINE Handle()
Definition handles.h:154
static V8_INLINE Handle< T > New(Tagged< T > object, Isolate *isolate)
Definition handles-inl.h:46
static const Handle< T > null()
Definition handles.h:206
V8_INLINE Handle(Handle< S > handle)
Definition handles.h:170
friend IndirectHandle< To > UncheckedCast(IndirectHandle< From > value)
V8_INLINE Tagged< T > operator->() const
Definition handles.h:180
void PatchValue(Tagged< T > new_value)
Definition handles.h:213
SealHandleScope(Isolate *isolate)
Definition handles.h:358
StrongRootAllocator(HeapOrIsolateT *)
V8_INLINE constexpr StorageType ptr() const
internal::Address * InternalRepresentationType
static constexpr InternalRepresentationType kEmpty
constexpr const Iterator & base() const noexcept
int start
int end
base::Vector< const DirectHandle< Object > > args
Definition execution.cc:74
int x
int n
Definition mul-fft.cc:296
V8_INLINE IndirectHandle< T > handle(Tagged< T > object, Isolate *isolate)
Definition handles-inl.h:72
constexpr Address kTaggedNullAddress
Definition handles.h:53
static constexpr bool is_maybe_weak_v
Definition tagged.h:94
V8_INLINE IndirectHandle< T > indirect_handle(DirectHandle< T > handle)
Definition handles.h:757
V8_INLINE DirectHandle< T > direct_handle(Tagged< T > object, Isolate *isolate)
static constexpr bool is_taggable_v
Definition tagged.h:316
static constexpr bool is_subtype_v
Definition tagged.h:121
std::ostream & operator<<(std::ostream &os, AtomicMemoryOrder order)
Handle< To > UncheckedCast(Handle< From > value)
Definition handles-inl.h:55
constexpr int kSystemPointerSize
Definition globals.h:410
Handle< T > IndirectHandle
Definition globals.h:1086
constexpr int kInt32Size
Definition globals.h:401
V8_ENABLE_CONSERVATIVE_STACK_SCANNING_BOOL
Definition flags.cc:470
static constexpr bool is_direct_handle_v
Definition handles.h:391
Local< T > Handle
uint32_t equals
#define V8_NOEXCEPT
#define V8_EXPORT_PRIVATE
Definition macros.h:460
static constexpr uint32_t kSizeInBytes
Definition handles.h:372
V8_INLINE bool operator()(Handle< T > lhs, Handle< T > rhs) const
Definition handles.h:220
V8_INLINE size_t operator()(Handle< T > const &handle) const
Definition handles.h:227
#define V8_INLINE
Definition v8config.h:500
#define V8_TRIVIAL_ABI
Definition v8config.h:754
#define V8_NOINLINE
Definition v8config.h:586
#define V8_NODISCARD
Definition v8config.h:693
WasmOrphanedGlobalHandle * handle_