Bug 1856126 [wpt PR 42137] - LoAF: ensure scripts are added after microtask checkpoin...
[gecko.git] / js / public / RootingAPI.h
blob1224ee087ecebccbc28e0c753cbe816b8213d690
1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*-
2 * vim: set ts=8 sts=2 et sw=2 tw=80:
3 * This Source Code Form is subject to the terms of the Mozilla Public
4 * License, v. 2.0. If a copy of the MPL was not distributed with this
5 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
7 #ifndef js_RootingAPI_h
8 #define js_RootingAPI_h
10 #include "mozilla/Attributes.h"
11 #include "mozilla/DebugOnly.h"
12 #include "mozilla/EnumeratedArray.h"
13 #include "mozilla/LinkedList.h"
14 #include "mozilla/Maybe.h"
16 #include <type_traits>
17 #include <utility>
19 #include "jspubtd.h"
21 #include "js/ComparisonOperators.h" // JS::detail::DefineComparisonOps
22 #include "js/GCAnnotations.h"
23 #include "js/GCPolicyAPI.h"
24 #include "js/GCTypeMacros.h" // JS_FOR_EACH_PUBLIC_{,TAGGED_}GC_POINTER_TYPE
25 #include "js/HashTable.h"
26 #include "js/HeapAPI.h" // StackKindCount
27 #include "js/ProfilingStack.h"
28 #include "js/Realm.h"
29 #include "js/Stack.h" // JS::NativeStackLimit
30 #include "js/TypeDecls.h"
31 #include "js/UniquePtr.h"
34 * [SMDOC] Stack Rooting
36 * Moving GC Stack Rooting
38 * A moving GC may change the physical location of GC allocated things, even
39 * when they are rooted, updating all pointers to the thing to refer to its new
40 * location. The GC must therefore know about all live pointers to a thing,
41 * not just one of them, in order to behave correctly.
43 * The |Rooted| and |Handle| classes below are used to root stack locations
44 * whose value may be held live across a call that can trigger GC. For a
45 * code fragment such as:
47 * JSObject* obj = NewObject(cx);
48 * DoSomething(cx);
49 * ... = obj->lastProperty();
51 * If |DoSomething()| can trigger a GC, the stack location of |obj| must be
52 * rooted to ensure that the GC does not move the JSObject referred to by
53 * |obj| without updating |obj|'s location itself. This rooting must happen
54 * regardless of whether there are other roots which ensure that the object
55 * itself will not be collected.
57 * If |DoSomething()| cannot trigger a GC, and the same holds for all other
58 * calls made between |obj|'s definitions and its last uses, then no rooting
59 * is required.
61 * SpiderMonkey can trigger a GC at almost any time and in ways that are not
62 * always clear. For example, the following innocuous-looking actions can
63 * cause a GC: allocation of any new GC thing; JSObject::hasProperty;
64 * JS_ReportError and friends; and ToNumber, among many others. The following
65 * dangerous-looking actions cannot trigger a GC: js_malloc, cx->malloc_,
66 * rt->malloc_, and friends and JS_ReportOutOfMemory.
68 * The following family of three classes will exactly root a stack location.
69 * Incorrect usage of these classes will result in a compile error in almost
70 * all cases. Therefore, it is very hard to be incorrectly rooted if you use
71 * these classes exclusively. These classes are all templated on the type T of
72 * the value being rooted.
74 * - Rooted<T> declares a variable of type T, whose value is always rooted.
75 * Rooted<T> may be automatically coerced to a Handle<T>, below. Rooted<T>
76 * should be used whenever a local variable's value may be held live across a
77 * call which can trigger a GC.
79 * - Handle<T> is a const reference to a Rooted<T>. Functions which take GC
80 * things or values as arguments and need to root those arguments should
81 * generally use handles for those arguments and avoid any explicit rooting.
82 * This has two benefits. First, when several such functions call each other
83 * then redundant rooting of multiple copies of the GC thing can be avoided.
84 * Second, if the caller does not pass a rooted value a compile error will be
85 * generated, which is quicker and easier to fix than when relying on a
86 * separate rooting analysis.
88 * - MutableHandle<T> is a non-const reference to Rooted<T>. It is used in the
89 * same way as Handle<T> and includes a |set(const T& v)| method to allow
90 * updating the value of the referenced Rooted<T>. A MutableHandle<T> can be
91 * created with an implicit cast from a Rooted<T>*.
93 * In some cases the small performance overhead of exact rooting (measured to
94 * be a few nanoseconds on desktop) is too much. In these cases, try the
95 * following:
97 * - Move all Rooted<T> above inner loops: this allows you to re-use the root
98 * on each iteration of the loop.
100 * - Pass Handle<T> through your hot call stack to avoid re-rooting costs at
101 * every invocation.
103 * The following diagram explains the list of supported, implicit type
104 * conversions between classes of this family:
106 * Rooted<T> ----> Handle<T>
107 * | ^
108 * | |
109 * | |
110 * +---> MutableHandle<T>
111 * (via &)
113 * All of these types have an implicit conversion to raw pointers.
116 namespace js {
118 class Nursery;
120 // The defaulted Enable parameter for the following two types is for restricting
121 // specializations with std::enable_if.
122 template <typename T, typename Enable = void>
123 struct BarrierMethods {};
125 template <typename Element, typename Wrapper, typename Enable = void>
126 class WrappedPtrOperations {};
128 template <typename Element, typename Wrapper>
129 class MutableWrappedPtrOperations
130 : public WrappedPtrOperations<Element, Wrapper> {};
132 template <typename T, typename Wrapper>
133 class RootedOperations : public MutableWrappedPtrOperations<T, Wrapper> {};
135 template <typename T, typename Wrapper>
136 class HandleOperations : public WrappedPtrOperations<T, Wrapper> {};
138 template <typename T, typename Wrapper>
139 class MutableHandleOperations : public MutableWrappedPtrOperations<T, Wrapper> {
142 template <typename T, typename Wrapper>
143 class HeapOperations : public MutableWrappedPtrOperations<T, Wrapper> {};
145 // Cannot use FOR_EACH_HEAP_ABLE_GC_POINTER_TYPE, as this would import too many
146 // macros into scope
148 // Add a 2nd template parameter to allow conditionally enabling partial
149 // specializations via std::enable_if.
150 template <typename T, typename Enable = void>
151 struct IsHeapConstructibleType : public std::false_type {};
153 #define JS_DECLARE_IS_HEAP_CONSTRUCTIBLE_TYPE(T) \
154 template <> \
155 struct IsHeapConstructibleType<T> : public std::true_type {};
156 JS_FOR_EACH_PUBLIC_GC_POINTER_TYPE(JS_DECLARE_IS_HEAP_CONSTRUCTIBLE_TYPE)
157 JS_FOR_EACH_PUBLIC_TAGGED_GC_POINTER_TYPE(JS_DECLARE_IS_HEAP_CONSTRUCTIBLE_TYPE)
158 // Note that JS_DECLARE_IS_HEAP_CONSTRUCTIBLE_TYPE is left defined, to allow
159 // declaring other types (eg from js/public/experimental/TypedData.h) to
160 // be used with Heap<>.
162 namespace gc {
163 struct Cell;
164 } /* namespace gc */
166 // Important: Return a reference so passing a Rooted<T>, etc. to
167 // something that takes a |const T&| is not a GC hazard.
168 #define DECLARE_POINTER_CONSTREF_OPS(T) \
169 operator const T&() const { return get(); } \
170 const T& operator->() const { return get(); }
172 // Assignment operators on a base class are hidden by the implicitly defined
173 // operator= on the derived class. Thus, define the operator= directly on the
174 // class as we would need to manually pass it through anyway.
175 #define DECLARE_POINTER_ASSIGN_OPS(Wrapper, T) \
176 Wrapper<T>& operator=(const T& p) { \
177 set(p); \
178 return *this; \
180 Wrapper<T>& operator=(T&& p) { \
181 set(std::move(p)); \
182 return *this; \
184 Wrapper<T>& operator=(const Wrapper<T>& other) { \
185 set(other.get()); \
186 return *this; \
189 #define DELETE_ASSIGNMENT_OPS(Wrapper, T) \
190 template <typename S> \
191 Wrapper<T>& operator=(S) = delete; \
192 Wrapper<T>& operator=(const Wrapper<T>&) = delete;
194 #define DECLARE_NONPOINTER_ACCESSOR_METHODS(ptr) \
195 const T* address() const { return &(ptr); } \
196 const T& get() const { return (ptr); }
198 #define DECLARE_NONPOINTER_MUTABLE_ACCESSOR_METHODS(ptr) \
199 T* address() { return &(ptr); } \
200 T& get() { return (ptr); }
202 } /* namespace js */
204 namespace JS {
206 JS_PUBLIC_API void HeapObjectPostWriteBarrier(JSObject** objp, JSObject* prev,
207 JSObject* next);
208 JS_PUBLIC_API void HeapStringPostWriteBarrier(JSString** objp, JSString* prev,
209 JSString* next);
210 JS_PUBLIC_API void HeapBigIntPostWriteBarrier(JS::BigInt** bip,
211 JS::BigInt* prev,
212 JS::BigInt* next);
213 JS_PUBLIC_API void HeapObjectWriteBarriers(JSObject** objp, JSObject* prev,
214 JSObject* next);
215 JS_PUBLIC_API void HeapStringWriteBarriers(JSString** objp, JSString* prev,
216 JSString* next);
217 JS_PUBLIC_API void HeapBigIntWriteBarriers(JS::BigInt** bip, JS::BigInt* prev,
218 JS::BigInt* next);
219 JS_PUBLIC_API void HeapScriptWriteBarriers(JSScript** objp, JSScript* prev,
220 JSScript* next);
223 * SafelyInitialized<T>::create() creates a safely-initialized |T|, suitable for
224 * use as a default value in situations requiring a safe but arbitrary |T|
225 * value. Implemented as a static method of a struct to allow partial
226 * specialization for subclasses via the Enable template parameter.
228 template <typename T, typename Enable = void>
229 struct SafelyInitialized {
230 static T create() {
231 // This function wants to presume that |T()| -- which value-initializes a
232 // |T| per C++11 [expr.type.conv]p2 -- will produce a safely-initialized,
233 // safely-usable T that it can return.
235 #if defined(XP_WIN) || defined(XP_MACOSX) || \
236 (defined(XP_UNIX) && !defined(__clang__))
238 // That presumption holds for pointers, where value initialization produces
239 // a null pointer.
240 constexpr bool IsPointer = std::is_pointer_v<T>;
242 // For classes and unions we *assume* that if |T|'s default constructor is
243 // non-trivial it'll initialize correctly. (This is unideal, but C++
244 // doesn't offer a type trait indicating whether a class's constructor is
245 // user-defined, which better approximates our desired semantics.)
246 constexpr bool IsNonTriviallyDefaultConstructibleClassOrUnion =
247 (std::is_class_v<T> ||
248 std::is_union_v<T>)&&!std::is_trivially_default_constructible_v<T>;
250 static_assert(IsPointer || IsNonTriviallyDefaultConstructibleClassOrUnion,
251 "T() must evaluate to a safely-initialized T");
253 #endif
255 return T();
259 #ifdef JS_DEBUG
261 * For generational GC, assert that an object is in the tenured generation as
262 * opposed to being in the nursery.
264 extern JS_PUBLIC_API void AssertGCThingMustBeTenured(JSObject* obj);
265 extern JS_PUBLIC_API void AssertGCThingIsNotNurseryAllocable(
266 js::gc::Cell* cell);
267 #else
268 inline void AssertGCThingMustBeTenured(JSObject* obj) {}
269 inline void AssertGCThingIsNotNurseryAllocable(js::gc::Cell* cell) {}
270 #endif
273 * The Heap<T> class is a heap-stored reference to a JS GC thing for use outside
274 * the JS engine. All members of heap classes that refer to GC things should use
275 * Heap<T> (or possibly TenuredHeap<T>, described below).
277 * Heap<T> is an abstraction that hides some of the complexity required to
278 * maintain GC invariants for the contained reference. It uses operator
279 * overloading to provide a normal pointer interface, but adds barriers to
280 * notify the GC of changes.
282 * Heap<T> implements the following barriers:
284 * - Post-write barrier (necessary for generational GC).
285 * - Read barrier (necessary for incremental GC and cycle collector
286 * integration).
288 * Note Heap<T> does not have a pre-write barrier as used internally in the
289 * engine. The read barrier is used to mark anything read from a Heap<T> during
290 * an incremental GC.
292 * Heap<T> may be moved or destroyed outside of GC finalization and hence may be
293 * used in dynamic storage such as a Vector.
295 * Heap<T> instances must be traced when their containing object is traced to
296 * keep the pointed-to GC thing alive.
298 * Heap<T> objects should only be used on the heap. GC references stored on the
299 * C/C++ stack must use Rooted/Handle/MutableHandle instead.
301 * Type T must be a public GC pointer type.
303 template <typename T>
304 class MOZ_NON_MEMMOVABLE Heap : public js::HeapOperations<T, Heap<T>> {
305 // Please note: this can actually also be used by nsXBLMaybeCompiled<T>, for
306 // legacy reasons.
307 static_assert(js::IsHeapConstructibleType<T>::value,
308 "Type T must be a public GC pointer type");
310 public:
311 using ElementType = T;
313 Heap() : ptr(SafelyInitialized<T>::create()) {
314 // No barriers are required for initialization to the default value.
315 static_assert(sizeof(T) == sizeof(Heap<T>),
316 "Heap<T> must be binary compatible with T.");
318 explicit Heap(const T& p) : ptr(p) {
319 postWriteBarrier(SafelyInitialized<T>::create(), ptr);
323 * For Heap, move semantics are equivalent to copy semantics. However, we want
324 * the copy constructor to be explicit, and an explicit move constructor
325 * breaks common usage of move semantics, so we need to define both, even
326 * though they are equivalent.
328 explicit Heap(const Heap<T>& other) : ptr(other.getWithoutExpose()) {
329 postWriteBarrier(SafelyInitialized<T>::create(), ptr);
331 Heap(Heap<T>&& other) : ptr(other.getWithoutExpose()) {
332 postWriteBarrier(SafelyInitialized<T>::create(), ptr);
335 Heap& operator=(Heap<T>&& other) {
336 set(other.getWithoutExpose());
337 other.set(SafelyInitialized<T>::create());
338 return *this;
341 ~Heap() { postWriteBarrier(ptr, SafelyInitialized<T>::create()); }
343 DECLARE_POINTER_CONSTREF_OPS(T);
344 DECLARE_POINTER_ASSIGN_OPS(Heap, T);
346 const T* address() const { return &ptr; }
348 void exposeToActiveJS() const { js::BarrierMethods<T>::exposeToJS(ptr); }
350 const T& get() const {
351 exposeToActiveJS();
352 return ptr;
354 const T& getWithoutExpose() const {
355 js::BarrierMethods<T>::readBarrier(ptr);
356 return ptr;
358 const T& unbarrieredGet() const { return ptr; }
360 void set(const T& newPtr) {
361 T tmp = ptr;
362 ptr = newPtr;
363 postWriteBarrier(tmp, ptr);
366 T* unsafeGet() { return &ptr; }
368 void unbarrieredSet(const T& newPtr) { ptr = newPtr; }
370 explicit operator bool() const {
371 return bool(js::BarrierMethods<T>::asGCThingOrNull(ptr));
373 explicit operator bool() {
374 return bool(js::BarrierMethods<T>::asGCThingOrNull(ptr));
377 private:
378 void postWriteBarrier(const T& prev, const T& next) {
379 js::BarrierMethods<T>::postWriteBarrier(&ptr, prev, next);
382 T ptr;
385 namespace detail {
387 template <typename T>
388 struct DefineComparisonOps<Heap<T>> : std::true_type {
389 static const T& get(const Heap<T>& v) { return v.unbarrieredGet(); }
392 } // namespace detail
394 static MOZ_ALWAYS_INLINE bool ObjectIsTenured(JSObject* obj) {
395 return !js::gc::IsInsideNursery(reinterpret_cast<js::gc::Cell*>(obj));
398 static MOZ_ALWAYS_INLINE bool ObjectIsTenured(const Heap<JSObject*>& obj) {
399 return ObjectIsTenured(obj.unbarrieredGet());
402 static MOZ_ALWAYS_INLINE bool ObjectIsMarkedGray(JSObject* obj) {
403 auto cell = reinterpret_cast<js::gc::Cell*>(obj);
404 if (js::gc::IsInsideNursery(cell)) {
405 return false;
408 auto tenuredCell = reinterpret_cast<js::gc::TenuredCell*>(cell);
409 return js::gc::detail::CellIsMarkedGrayIfKnown(tenuredCell);
412 static MOZ_ALWAYS_INLINE bool ObjectIsMarkedGray(
413 const JS::Heap<JSObject*>& obj) {
414 return ObjectIsMarkedGray(obj.unbarrieredGet());
417 // The following *IsNotGray functions take account of the eventual
418 // gray marking state at the end of any ongoing incremental GC by
419 // delaying the checks if necessary.
421 #ifdef DEBUG
423 inline void AssertCellIsNotGray(const js::gc::Cell* maybeCell) {
424 if (maybeCell) {
425 js::gc::detail::AssertCellIsNotGray(maybeCell);
429 inline void AssertObjectIsNotGray(JSObject* maybeObj) {
430 AssertCellIsNotGray(reinterpret_cast<js::gc::Cell*>(maybeObj));
433 inline void AssertObjectIsNotGray(const JS::Heap<JSObject*>& obj) {
434 AssertObjectIsNotGray(obj.unbarrieredGet());
437 #else
439 inline void AssertCellIsNotGray(js::gc::Cell* maybeCell) {}
440 inline void AssertObjectIsNotGray(JSObject* maybeObj) {}
441 inline void AssertObjectIsNotGray(const JS::Heap<JSObject*>& obj) {}
443 #endif
446 * The TenuredHeap<T> class is similar to the Heap<T> class above in that it
447 * encapsulates the GC concerns of an on-heap reference to a JS object. However,
448 * it has two important differences:
450 * 1) Pointers which are statically known to only reference "tenured" objects
451 * can avoid the extra overhead of SpiderMonkey's write barriers.
453 * 2) Objects in the "tenured" heap have stronger alignment restrictions than
454 * those in the "nursery", so it is possible to store flags in the lower
455 * bits of pointers known to be tenured. TenuredHeap wraps a normal tagged
456 * pointer with a nice API for accessing the flag bits and adds various
457 * assertions to ensure that it is not mis-used.
459 * GC things are said to be "tenured" when they are located in the long-lived
460 * heap: e.g. they have gained tenure as an object by surviving past at least
461 * one GC. For performance, SpiderMonkey allocates some things which are known
462 * to normally be long lived directly into the tenured generation; for example,
463 * global objects. Additionally, SpiderMonkey does not visit individual objects
464 * when deleting non-tenured objects, so object with finalizers are also always
465 * tenured; for instance, this includes most DOM objects.
467 * The considerations to keep in mind when using a TenuredHeap<T> vs a normal
468 * Heap<T> are:
470 * - It is invalid for a TenuredHeap<T> to refer to a non-tenured thing.
471 * - It is however valid for a Heap<T> to refer to a tenured thing.
472 * - It is not possible to store flag bits in a Heap<T>.
474 template <typename T>
475 class TenuredHeap : public js::HeapOperations<T, TenuredHeap<T>> {
476 public:
477 using ElementType = T;
479 TenuredHeap() : bits(0) {
480 static_assert(sizeof(T) == sizeof(TenuredHeap<T>),
481 "TenuredHeap<T> must be binary compatible with T.");
483 explicit TenuredHeap(T p) : bits(0) { setPtr(p); }
484 explicit TenuredHeap(const TenuredHeap<T>& p) : bits(0) {
485 setPtr(p.getPtr());
488 void setPtr(T newPtr) {
489 MOZ_ASSERT((reinterpret_cast<uintptr_t>(newPtr) & flagsMask) == 0);
490 MOZ_ASSERT(js::gc::IsCellPointerValidOrNull(newPtr));
491 if (newPtr) {
492 AssertGCThingMustBeTenured(newPtr);
494 bits = (bits & flagsMask) | reinterpret_cast<uintptr_t>(newPtr);
497 void setFlags(uintptr_t flagsToSet) {
498 MOZ_ASSERT((flagsToSet & ~flagsMask) == 0);
499 bits |= flagsToSet;
502 void unsetFlags(uintptr_t flagsToUnset) {
503 MOZ_ASSERT((flagsToUnset & ~flagsMask) == 0);
504 bits &= ~flagsToUnset;
507 bool hasFlag(uintptr_t flag) const {
508 MOZ_ASSERT((flag & ~flagsMask) == 0);
509 return (bits & flag) != 0;
512 T unbarrieredGetPtr() const { return reinterpret_cast<T>(bits & ~flagsMask); }
513 uintptr_t getFlags() const { return bits & flagsMask; }
515 void exposeToActiveJS() const {
516 js::BarrierMethods<T>::exposeToJS(unbarrieredGetPtr());
518 T getPtr() const {
519 exposeToActiveJS();
520 return unbarrieredGetPtr();
523 operator T() const { return getPtr(); }
524 T operator->() const { return getPtr(); }
526 explicit operator bool() const {
527 return bool(js::BarrierMethods<T>::asGCThingOrNull(unbarrieredGetPtr()));
529 explicit operator bool() {
530 return bool(js::BarrierMethods<T>::asGCThingOrNull(unbarrieredGetPtr()));
533 TenuredHeap<T>& operator=(T p) {
534 setPtr(p);
535 return *this;
538 TenuredHeap<T>& operator=(const TenuredHeap<T>& other) {
539 bits = other.bits;
540 return *this;
543 private:
544 enum {
545 maskBits = 3,
546 flagsMask = (1 << maskBits) - 1,
549 uintptr_t bits;
552 namespace detail {
554 template <typename T>
555 struct DefineComparisonOps<TenuredHeap<T>> : std::true_type {
556 static const T get(const TenuredHeap<T>& v) { return v.unbarrieredGetPtr(); }
559 } // namespace detail
561 // std::swap uses a stack temporary, which prevents classes like Heap<T>
562 // from being declared MOZ_HEAP_CLASS.
563 template <typename T>
564 void swap(TenuredHeap<T>& aX, TenuredHeap<T>& aY) {
565 T tmp = aX;
566 aX = aY;
567 aY = tmp;
570 template <typename T>
571 void swap(Heap<T>& aX, Heap<T>& aY) {
572 T tmp = aX;
573 aX = aY;
574 aY = tmp;
577 static MOZ_ALWAYS_INLINE bool ObjectIsMarkedGray(
578 const JS::TenuredHeap<JSObject*>& obj) {
579 return ObjectIsMarkedGray(obj.unbarrieredGetPtr());
582 template <typename T>
583 class MutableHandle;
584 template <typename T>
585 class Rooted;
586 template <typename T>
587 class PersistentRooted;
590 * Reference to a T that has been rooted elsewhere. This is most useful
591 * as a parameter type, which guarantees that the T lvalue is properly
592 * rooted. See "Move GC Stack Rooting" above.
594 * If you want to add additional methods to Handle for a specific
595 * specialization, define a HandleOperations<T> specialization containing them.
597 template <typename T>
598 class MOZ_NONHEAP_CLASS Handle : public js::HandleOperations<T, Handle<T>> {
599 friend class MutableHandle<T>;
601 public:
602 using ElementType = T;
604 Handle(const Handle<T>&) = default;
606 /* Creates a handle from a handle of a type convertible to T. */
607 template <typename S>
608 MOZ_IMPLICIT Handle(
609 Handle<S> handle,
610 std::enable_if_t<std::is_convertible_v<S, T>, int> dummy = 0) {
611 static_assert(sizeof(Handle<T>) == sizeof(T*),
612 "Handle must be binary compatible with T*.");
613 ptr = reinterpret_cast<const T*>(handle.address());
616 MOZ_IMPLICIT Handle(decltype(nullptr)) {
617 static_assert(std::is_pointer_v<T>,
618 "nullptr_t overload not valid for non-pointer types");
619 static void* const ConstNullValue = nullptr;
620 ptr = reinterpret_cast<const T*>(&ConstNullValue);
623 MOZ_IMPLICIT Handle(MutableHandle<T> handle) { ptr = handle.address(); }
626 * Take care when calling this method!
628 * This creates a Handle from the raw location of a T.
630 * It should be called only if the following conditions hold:
632 * 1) the location of the T is guaranteed to be marked (for some reason
633 * other than being a Rooted), e.g., if it is guaranteed to be reachable
634 * from an implicit root.
636 * 2) the contents of the location are immutable, or at least cannot change
637 * for the lifetime of the handle, as its users may not expect its value
638 * to change underneath them.
640 static constexpr Handle fromMarkedLocation(const T* p) {
641 return Handle(p, DeliberatelyChoosingThisOverload,
642 ImUsingThisOnlyInFromFromMarkedLocation);
646 * Construct a handle from an explicitly rooted location. This is the
647 * normal way to create a handle, and normally happens implicitly.
649 template <typename S>
650 inline MOZ_IMPLICIT Handle(
651 const Rooted<S>& root,
652 std::enable_if_t<std::is_convertible_v<S, T>, int> dummy = 0);
654 template <typename S>
655 inline MOZ_IMPLICIT Handle(
656 const PersistentRooted<S>& root,
657 std::enable_if_t<std::is_convertible_v<S, T>, int> dummy = 0);
659 /* Construct a read only handle from a mutable handle. */
660 template <typename S>
661 inline MOZ_IMPLICIT Handle(
662 MutableHandle<S>& root,
663 std::enable_if_t<std::is_convertible_v<S, T>, int> dummy = 0);
665 DECLARE_POINTER_CONSTREF_OPS(T);
666 DECLARE_NONPOINTER_ACCESSOR_METHODS(*ptr);
668 private:
669 Handle() = default;
670 DELETE_ASSIGNMENT_OPS(Handle, T);
672 enum Disambiguator { DeliberatelyChoosingThisOverload = 42 };
673 enum CallerIdentity { ImUsingThisOnlyInFromFromMarkedLocation = 17 };
674 constexpr Handle(const T* p, Disambiguator, CallerIdentity) : ptr(p) {}
676 const T* ptr;
679 namespace detail {
681 template <typename T>
682 struct DefineComparisonOps<Handle<T>> : std::true_type {
683 static const T& get(const Handle<T>& v) { return v.get(); }
686 } // namespace detail
689 * Similar to a handle, but the underlying storage can be changed. This is
690 * useful for outparams.
692 * If you want to add additional methods to MutableHandle for a specific
693 * specialization, define a MutableHandleOperations<T> specialization containing
694 * them.
696 template <typename T>
697 class MOZ_STACK_CLASS MutableHandle
698 : public js::MutableHandleOperations<T, MutableHandle<T>> {
699 public:
700 using ElementType = T;
702 inline MOZ_IMPLICIT MutableHandle(Rooted<T>* root);
703 inline MOZ_IMPLICIT MutableHandle(PersistentRooted<T>* root);
705 private:
706 // Disallow nullptr for overloading purposes.
707 MutableHandle(decltype(nullptr)) = delete;
709 public:
710 MutableHandle(const MutableHandle<T>&) = default;
711 void set(const T& v) {
712 *ptr = v;
713 MOZ_ASSERT(GCPolicy<T>::isValid(*ptr));
715 void set(T&& v) {
716 *ptr = std::move(v);
717 MOZ_ASSERT(GCPolicy<T>::isValid(*ptr));
721 * This may be called only if the location of the T is guaranteed
722 * to be marked (for some reason other than being a Rooted),
723 * e.g., if it is guaranteed to be reachable from an implicit root.
725 * Create a MutableHandle from a raw location of a T.
727 static MutableHandle fromMarkedLocation(T* p) {
728 MutableHandle h;
729 h.ptr = p;
730 return h;
733 DECLARE_POINTER_CONSTREF_OPS(T);
734 DECLARE_NONPOINTER_ACCESSOR_METHODS(*ptr);
735 DECLARE_NONPOINTER_MUTABLE_ACCESSOR_METHODS(*ptr);
737 private:
738 MutableHandle() = default;
739 DELETE_ASSIGNMENT_OPS(MutableHandle, T);
741 T* ptr;
744 namespace detail {
746 template <typename T>
747 struct DefineComparisonOps<MutableHandle<T>> : std::true_type {
748 static const T& get(const MutableHandle<T>& v) { return v.get(); }
751 } // namespace detail
753 } /* namespace JS */
755 namespace js {
757 namespace detail {
759 // Default implementations for barrier methods on GC thing pointers.
760 template <typename T>
761 struct PtrBarrierMethodsBase {
762 static T* initial() { return nullptr; }
763 static gc::Cell* asGCThingOrNull(T* v) {
764 if (!v) {
765 return nullptr;
767 MOZ_ASSERT(uintptr_t(v) > 32);
768 return reinterpret_cast<gc::Cell*>(v);
770 static void exposeToJS(T* t) {
771 if (t) {
772 js::gc::ExposeGCThingToActiveJS(JS::GCCellPtr(t));
775 static void readBarrier(T* t) {
776 if (t) {
777 js::gc::IncrementalReadBarrier(JS::GCCellPtr(t));
782 } // namespace detail
784 template <typename T>
785 struct BarrierMethods<T*> : public detail::PtrBarrierMethodsBase<T> {
786 static void postWriteBarrier(T** vp, T* prev, T* next) {
787 if (next) {
788 JS::AssertGCThingIsNotNurseryAllocable(
789 reinterpret_cast<js::gc::Cell*>(next));
794 template <>
795 struct BarrierMethods<JSObject*>
796 : public detail::PtrBarrierMethodsBase<JSObject> {
797 static void postWriteBarrier(JSObject** vp, JSObject* prev, JSObject* next) {
798 JS::HeapObjectPostWriteBarrier(vp, prev, next);
800 static void exposeToJS(JSObject* obj) {
801 if (obj) {
802 JS::ExposeObjectToActiveJS(obj);
807 template <>
808 struct BarrierMethods<JSFunction*>
809 : public detail::PtrBarrierMethodsBase<JSFunction> {
810 static void postWriteBarrier(JSFunction** vp, JSFunction* prev,
811 JSFunction* next) {
812 JS::HeapObjectPostWriteBarrier(reinterpret_cast<JSObject**>(vp),
813 reinterpret_cast<JSObject*>(prev),
814 reinterpret_cast<JSObject*>(next));
816 static void exposeToJS(JSFunction* fun) {
817 if (fun) {
818 JS::ExposeObjectToActiveJS(reinterpret_cast<JSObject*>(fun));
823 template <>
824 struct BarrierMethods<JSString*>
825 : public detail::PtrBarrierMethodsBase<JSString> {
826 static void postWriteBarrier(JSString** vp, JSString* prev, JSString* next) {
827 JS::HeapStringPostWriteBarrier(vp, prev, next);
831 template <>
832 struct BarrierMethods<JS::BigInt*>
833 : public detail::PtrBarrierMethodsBase<JS::BigInt> {
834 static void postWriteBarrier(JS::BigInt** vp, JS::BigInt* prev,
835 JS::BigInt* next) {
836 JS::HeapBigIntPostWriteBarrier(vp, prev, next);
840 // Provide hash codes for Cell kinds that may be relocated and, thus, not have
841 // a stable address to use as the base for a hash code. Instead of the address,
842 // this hasher uses Cell::getUniqueId to provide exact matches and as a base
843 // for generating hash codes.
845 // Note: this hasher, like PointerHasher can "hash" a nullptr. While a nullptr
846 // would not likely be a useful key, there are some cases where being able to
847 // hash a nullptr is useful, either on purpose or because of bugs:
848 // (1) existence checks where the key may happen to be null and (2) some
849 // aggregate Lookup kinds embed a JSObject* that is frequently null and do not
850 // null test before dispatching to the hasher.
851 template <typename T>
852 struct JS_PUBLIC_API StableCellHasher {
853 using Key = T;
854 using Lookup = T;
856 static bool maybeGetHash(const Lookup& l, mozilla::HashNumber* hashOut);
857 static bool ensureHash(const Lookup& l, HashNumber* hashOut);
858 static HashNumber hash(const Lookup& l);
859 static bool match(const Key& k, const Lookup& l);
860 // The rekey hash policy method is not provided since you dont't need to
861 // rekey any more when using this policy.
864 template <typename T>
865 struct JS_PUBLIC_API StableCellHasher<JS::Heap<T>> {
866 using Key = JS::Heap<T>;
867 using Lookup = T;
869 static bool maybeGetHash(const Lookup& l, HashNumber* hashOut) {
870 return StableCellHasher<T>::maybeGetHash(l, hashOut);
872 static bool ensureHash(const Lookup& l, HashNumber* hashOut) {
873 return StableCellHasher<T>::ensureHash(l, hashOut);
875 static HashNumber hash(const Lookup& l) {
876 return StableCellHasher<T>::hash(l);
878 static bool match(const Key& k, const Lookup& l) {
879 return StableCellHasher<T>::match(k.unbarrieredGet(), l);
883 } // namespace js
885 namespace mozilla {
887 template <typename T>
888 struct FallibleHashMethods<js::StableCellHasher<T>> {
889 template <typename Lookup>
890 static bool maybeGetHash(Lookup&& l, HashNumber* hashOut) {
891 return js::StableCellHasher<T>::maybeGetHash(std::forward<Lookup>(l),
892 hashOut);
894 template <typename Lookup>
895 static bool ensureHash(Lookup&& l, HashNumber* hashOut) {
896 return js::StableCellHasher<T>::ensureHash(std::forward<Lookup>(l),
897 hashOut);
901 } // namespace mozilla
903 namespace js {
905 struct VirtualTraceable {
906 virtual ~VirtualTraceable() = default;
907 virtual void trace(JSTracer* trc, const char* name) = 0;
910 class StackRootedBase {
911 public:
912 StackRootedBase* previous() { return prev; }
914 protected:
915 StackRootedBase** stack;
916 StackRootedBase* prev;
918 template <typename T>
919 auto* derived() {
920 return static_cast<JS::Rooted<T>*>(this);
924 class PersistentRootedBase
925 : protected mozilla::LinkedListElement<PersistentRootedBase> {
926 protected:
927 friend class mozilla::LinkedList<PersistentRootedBase>;
928 friend class mozilla::LinkedListElement<PersistentRootedBase>;
930 template <typename T>
931 auto* derived() {
932 return static_cast<JS::PersistentRooted<T>*>(this);
936 struct StackRootedTraceableBase : public StackRootedBase,
937 public VirtualTraceable {};
939 class PersistentRootedTraceableBase : public PersistentRootedBase,
940 public VirtualTraceable {};
942 template <typename Base, typename T>
943 class TypedRootedGCThingBase : public Base {
944 public:
945 void trace(JSTracer* trc, const char* name);
948 template <typename Base, typename T>
949 class TypedRootedTraceableBase : public Base {
950 public:
951 void trace(JSTracer* trc, const char* name) override {
952 auto* self = this->template derived<T>();
953 JS::GCPolicy<T>::trace(trc, self->address(), name);
957 template <typename T>
958 struct RootedTraceableTraits {
959 using StackBase = TypedRootedTraceableBase<StackRootedTraceableBase, T>;
960 using PersistentBase =
961 TypedRootedTraceableBase<PersistentRootedTraceableBase, T>;
964 template <typename T>
965 struct RootedGCThingTraits {
966 using StackBase = TypedRootedGCThingBase<StackRootedBase, T>;
967 using PersistentBase = TypedRootedGCThingBase<PersistentRootedBase, T>;
970 } /* namespace js */
972 namespace JS {
974 class JS_PUBLIC_API AutoGCRooter;
976 enum class AutoGCRooterKind : uint8_t {
977 WrapperVector, /* js::AutoWrapperVector */
978 Wrapper, /* js::AutoWrapperRooter */
979 Custom, /* js::CustomAutoRooter */
981 Limit
984 using RootedListHeads =
985 mozilla::EnumeratedArray<RootKind, RootKind::Limit, js::StackRootedBase*>;
987 using AutoRooterListHeads =
988 mozilla::EnumeratedArray<AutoGCRooterKind, AutoGCRooterKind::Limit,
989 AutoGCRooter*>;
991 // Superclass of JSContext which can be used for rooting data in use by the
992 // current thread but that does not provide all the functions of a JSContext.
993 class RootingContext {
994 // Stack GC roots for Rooted GC heap pointers.
995 RootedListHeads stackRoots_;
996 template <typename T>
997 friend class Rooted;
999 // Stack GC roots for AutoFooRooter classes.
1000 AutoRooterListHeads autoGCRooters_;
1001 friend class AutoGCRooter;
1003 // Gecko profiling metadata.
1004 // This isn't really rooting related. It's only here because we want
1005 // GetContextProfilingStackIfEnabled to be inlineable into non-JS code, and
1006 // we didn't want to add another superclass of JSContext just for this.
1007 js::GeckoProfilerThread geckoProfiler_;
1009 public:
1010 explicit RootingContext(js::Nursery* nursery);
1012 void traceStackRoots(JSTracer* trc);
1014 /* Implemented in gc/RootMarking.cpp. */
1015 void traceAllGCRooters(JSTracer* trc);
1016 void traceWrapperGCRooters(JSTracer* trc);
1017 static void traceGCRooterList(JSTracer* trc, AutoGCRooter* head);
1019 void checkNoGCRooters();
1021 js::GeckoProfilerThread& geckoProfiler() { return geckoProfiler_; }
1023 JS::Zone* zoneUnchecked() const { return zone_; }
1025 js::Nursery& nursery() const {
1026 MOZ_ASSERT(nursery_);
1027 return *nursery_;
1030 protected:
1031 // The remaining members in this class should only be accessed through
1032 // JSContext pointers. They are unrelated to rooting and are in place so
1033 // that inlined API functions can directly access the data.
1035 /* The nursery. Null for non-main-thread contexts. */
1036 js::Nursery* nursery_;
1038 /* The current zone. */
1039 Zone* zone_;
1041 /* The current realm. */
1042 Realm* realm_;
1044 public:
1045 /* Limit pointer for checking native stack consumption. */
1046 JS::NativeStackLimit nativeStackLimit[StackKindCount];
1048 #ifdef __wasi__
1049 // For WASI we can't catch call-stack overflows with stack-pointer checks, so
1050 // we count recursion depth with RAII based AutoCheckRecursionLimit.
1051 uint32_t wasiRecursionDepth = 0u;
1053 static constexpr uint32_t wasiRecursionDepthLimit = 350u;
1054 #endif // __wasi__
1056 static const RootingContext* get(const JSContext* cx) {
1057 return reinterpret_cast<const RootingContext*>(cx);
1060 static RootingContext* get(JSContext* cx) {
1061 return reinterpret_cast<RootingContext*>(cx);
1064 friend JS::Realm* js::GetContextRealm(const JSContext* cx);
1065 friend JS::Zone* js::GetContextZone(const JSContext* cx);
1068 class JS_PUBLIC_API AutoGCRooter {
1069 public:
1070 using Kind = AutoGCRooterKind;
1072 AutoGCRooter(JSContext* cx, Kind kind)
1073 : AutoGCRooter(JS::RootingContext::get(cx), kind) {}
1074 AutoGCRooter(RootingContext* cx, Kind kind)
1075 : down(cx->autoGCRooters_[kind]),
1076 stackTop(&cx->autoGCRooters_[kind]),
1077 kind_(kind) {
1078 MOZ_ASSERT(this != *stackTop);
1079 *stackTop = this;
1082 ~AutoGCRooter() {
1083 MOZ_ASSERT(this == *stackTop);
1084 *stackTop = down;
1087 void trace(JSTracer* trc);
1089 private:
1090 friend class RootingContext;
1092 AutoGCRooter* const down;
1093 AutoGCRooter** const stackTop;
1096 * Discriminates actual subclass of this being used. The meaning is
1097 * indicated by the corresponding value in the Kind enum.
1099 Kind kind_;
1101 /* No copy or assignment semantics. */
1102 AutoGCRooter(AutoGCRooter& ida) = delete;
1103 void operator=(AutoGCRooter& ida) = delete;
1104 } JS_HAZ_ROOTED_BASE;
1107 * Custom rooting behavior for internal and external clients.
1109 * Deprecated. Where possible, use Rooted<> instead.
1111 class MOZ_RAII JS_PUBLIC_API CustomAutoRooter : private AutoGCRooter {
1112 public:
1113 template <typename CX>
1114 explicit CustomAutoRooter(const CX& cx)
1115 : AutoGCRooter(cx, AutoGCRooter::Kind::Custom) {}
1117 friend void AutoGCRooter::trace(JSTracer* trc);
1119 protected:
1120 virtual ~CustomAutoRooter() = default;
1122 /** Supplied by derived class to trace roots. */
1123 virtual void trace(JSTracer* trc) = 0;
1126 namespace detail {
1128 template <typename T>
1129 constexpr bool IsTraceable_v =
1130 MapTypeToRootKind<T>::kind == JS::RootKind::Traceable;
1132 template <typename T>
1133 using RootedTraits =
1134 std::conditional_t<IsTraceable_v<T>, js::RootedTraceableTraits<T>,
1135 js::RootedGCThingTraits<T>>;
1137 } /* namespace detail */
1140 * Local variable of type T whose value is always rooted. This is typically
1141 * used for local variables, or for non-rooted values being passed to a
1142 * function that requires a handle, e.g. Foo(Root<T>(cx, x)).
1144 * If you want to add additional methods to Rooted for a specific
1145 * specialization, define a RootedOperations<T> specialization containing them.
1147 template <typename T>
1148 class MOZ_RAII Rooted : public detail::RootedTraits<T>::StackBase,
1149 public js::RootedOperations<T, Rooted<T>> {
1150 inline void registerWithRootLists(RootedListHeads& roots) {
1151 this->stack = &roots[JS::MapTypeToRootKind<T>::kind];
1152 this->prev = *this->stack;
1153 *this->stack = this;
1156 inline RootedListHeads& rootLists(RootingContext* cx) {
1157 return cx->stackRoots_;
1159 inline RootedListHeads& rootLists(JSContext* cx) {
1160 return rootLists(RootingContext::get(cx));
1163 public:
1164 using ElementType = T;
1166 // Construct an empty Rooted holding a safely initialized but empty T.
1167 // Requires T to have a copy constructor in order to copy the safely
1168 // initialized value.
1170 // Note that for SFINAE to reject this method, the 2nd template parameter must
1171 // depend on RootingContext somehow even though we really only care about T.
1172 template <typename RootingContext,
1173 typename = std::enable_if_t<std::is_copy_constructible_v<T>,
1174 RootingContext>>
1175 explicit Rooted(const RootingContext& cx)
1176 : ptr(SafelyInitialized<T>::create()) {
1177 registerWithRootLists(rootLists(cx));
1180 // Provide an initial value. Requires T to be constructible from the given
1181 // argument.
1182 template <typename RootingContext, typename S>
1183 Rooted(const RootingContext& cx, S&& initial)
1184 : ptr(std::forward<S>(initial)) {
1185 MOZ_ASSERT(GCPolicy<T>::isValid(ptr));
1186 registerWithRootLists(rootLists(cx));
1189 // (Traceables only) Construct the contained value from the given arguments.
1190 // Constructs in-place, so T does not need to be copyable or movable.
1192 // Note that a copyable Traceable passed only a RootingContext will
1193 // choose the above SafelyInitialized<T> constructor, because otherwise
1194 // identical functions with parameter packs are considered less specialized.
1196 // The SFINAE type must again depend on an inferred template parameter.
1197 template <
1198 typename RootingContext, typename... CtorArgs,
1199 typename = std::enable_if_t<detail::IsTraceable_v<T>, RootingContext>>
1200 explicit Rooted(const RootingContext& cx, CtorArgs... args)
1201 : ptr(std::forward<CtorArgs>(args)...) {
1202 MOZ_ASSERT(GCPolicy<T>::isValid(ptr));
1203 registerWithRootLists(rootLists(cx));
1206 ~Rooted() {
1207 MOZ_ASSERT(*this->stack == this);
1208 *this->stack = this->prev;
1212 * This method is public for Rooted so that Codegen.py can use a Rooted
1213 * interchangeably with a MutableHandleValue.
1215 void set(const T& value) {
1216 ptr = value;
1217 MOZ_ASSERT(GCPolicy<T>::isValid(ptr));
1219 void set(T&& value) {
1220 ptr = std::move(value);
1221 MOZ_ASSERT(GCPolicy<T>::isValid(ptr));
1224 DECLARE_POINTER_CONSTREF_OPS(T);
1225 DECLARE_POINTER_ASSIGN_OPS(Rooted, T);
1227 T& get() { return ptr; }
1228 const T& get() const { return ptr; }
1230 T* address() { return &ptr; }
1231 const T* address() const { return &ptr; }
1233 private:
1234 T ptr;
1236 Rooted(const Rooted&) = delete;
1237 } JS_HAZ_ROOTED;
1239 namespace detail {
1241 template <typename T>
1242 struct DefineComparisonOps<Rooted<T>> : std::true_type {
1243 static const T& get(const Rooted<T>& v) { return v.get(); }
1246 } // namespace detail
1248 } /* namespace JS */
1250 namespace js {
1253 * Inlinable accessors for JSContext.
1255 * - These must not be available on the more restricted superclasses of
1256 * JSContext, so we can't simply define them on RootingContext.
1258 * - They're perfectly ordinary JSContext functionality, so ought to be
1259 * usable without resorting to jsfriendapi.h, and when JSContext is an
1260 * incomplete type.
1262 inline JS::Realm* GetContextRealm(const JSContext* cx) {
1263 return JS::RootingContext::get(cx)->realm_;
1266 inline JS::Compartment* GetContextCompartment(const JSContext* cx) {
1267 if (JS::Realm* realm = GetContextRealm(cx)) {
1268 return GetCompartmentForRealm(realm);
1270 return nullptr;
1273 inline JS::Zone* GetContextZone(const JSContext* cx) {
1274 return JS::RootingContext::get(cx)->zone_;
1277 inline ProfilingStack* GetContextProfilingStackIfEnabled(JSContext* cx) {
1278 return JS::RootingContext::get(cx)
1279 ->geckoProfiler()
1280 .getProfilingStackIfEnabled();
1284 * Augment the generic Rooted<T> interface when T = JSObject* with
1285 * class-querying and downcasting operations.
1287 * Given a Rooted<JSObject*> obj, one can view
1288 * Handle<StringObject*> h = obj.as<StringObject*>();
1289 * as an optimization of
1290 * Rooted<StringObject*> rooted(cx, &obj->as<StringObject*>());
1291 * Handle<StringObject*> h = rooted;
1293 template <typename Container>
1294 class RootedOperations<JSObject*, Container>
1295 : public MutableWrappedPtrOperations<JSObject*, Container> {
1296 public:
1297 template <class U>
1298 JS::Handle<U*> as() const;
1302 * Augment the generic Handle<T> interface when T = JSObject* with
1303 * downcasting operations.
1305 * Given a Handle<JSObject*> obj, one can view
1306 * Handle<StringObject*> h = obj.as<StringObject*>();
1307 * as an optimization of
1308 * Rooted<StringObject*> rooted(cx, &obj->as<StringObject*>());
1309 * Handle<StringObject*> h = rooted;
1311 template <typename Container>
1312 class HandleOperations<JSObject*, Container>
1313 : public WrappedPtrOperations<JSObject*, Container> {
1314 public:
1315 template <class U>
1316 JS::Handle<U*> as() const;
1319 } /* namespace js */
1321 namespace JS {
1323 template <typename T>
1324 template <typename S>
1325 inline Handle<T>::Handle(
1326 const Rooted<S>& root,
1327 std::enable_if_t<std::is_convertible_v<S, T>, int> dummy) {
1328 ptr = reinterpret_cast<const T*>(root.address());
1331 template <typename T>
1332 template <typename S>
1333 inline Handle<T>::Handle(
1334 const PersistentRooted<S>& root,
1335 std::enable_if_t<std::is_convertible_v<S, T>, int> dummy) {
1336 ptr = reinterpret_cast<const T*>(root.address());
1339 template <typename T>
1340 template <typename S>
1341 inline Handle<T>::Handle(
1342 MutableHandle<S>& root,
1343 std::enable_if_t<std::is_convertible_v<S, T>, int> dummy) {
1344 ptr = reinterpret_cast<const T*>(root.address());
1347 template <typename T>
1348 inline MutableHandle<T>::MutableHandle(Rooted<T>* root) {
1349 static_assert(sizeof(MutableHandle<T>) == sizeof(T*),
1350 "MutableHandle must be binary compatible with T*.");
1351 ptr = root->address();
1354 template <typename T>
1355 inline MutableHandle<T>::MutableHandle(PersistentRooted<T>* root) {
1356 static_assert(sizeof(MutableHandle<T>) == sizeof(T*),
1357 "MutableHandle must be binary compatible with T*.");
1358 ptr = root->address();
1361 JS_PUBLIC_API void AddPersistentRoot(RootingContext* cx, RootKind kind,
1362 js::PersistentRootedBase* root);
1364 JS_PUBLIC_API void AddPersistentRoot(JSRuntime* rt, RootKind kind,
1365 js::PersistentRootedBase* root);
1368 * A copyable, assignable global GC root type with arbitrary lifetime, an
1369 * infallible constructor, and automatic unrooting on destruction.
1371 * These roots can be used in heap-allocated data structures, so they are not
1372 * associated with any particular JSContext or stack. They are registered with
1373 * the JSRuntime itself, without locking. Initialization may take place on
1374 * construction, or in two phases if the no-argument constructor is called
1375 * followed by init().
1377 * Note that you must not use an PersistentRooted in an object owned by a JS
1378 * object:
1380 * Whenever one object whose lifetime is decided by the GC refers to another
1381 * such object, that edge must be traced only if the owning JS object is traced.
1382 * This applies not only to JS objects (which obviously are managed by the GC)
1383 * but also to C++ objects owned by JS objects.
1385 * If you put a PersistentRooted in such a C++ object, that is almost certainly
1386 * a leak. When a GC begins, the referent of the PersistentRooted is treated as
1387 * live, unconditionally (because a PersistentRooted is a *root*), even if the
1388 * JS object that owns it is unreachable. If there is any path from that
1389 * referent back to the JS object, then the C++ object containing the
1390 * PersistentRooted will not be destructed, and the whole blob of objects will
1391 * not be freed, even if there are no references to them from the outside.
1393 * In the context of Firefox, this is a severe restriction: almost everything in
1394 * Firefox is owned by some JS object or another, so using PersistentRooted in
1395 * such objects would introduce leaks. For these kinds of edges, Heap<T> or
1396 * TenuredHeap<T> would be better types. It's up to the implementor of the type
1397 * containing Heap<T> or TenuredHeap<T> members to make sure their referents get
1398 * marked when the object itself is marked.
1400 template <typename T>
1401 class PersistentRooted : public detail::RootedTraits<T>::PersistentBase,
1402 public js::RootedOperations<T, PersistentRooted<T>> {
1403 void registerWithRootLists(RootingContext* cx) {
1404 MOZ_ASSERT(!initialized());
1405 JS::RootKind kind = JS::MapTypeToRootKind<T>::kind;
1406 AddPersistentRoot(cx, kind, this);
1409 void registerWithRootLists(JSRuntime* rt) {
1410 MOZ_ASSERT(!initialized());
1411 JS::RootKind kind = JS::MapTypeToRootKind<T>::kind;
1412 AddPersistentRoot(rt, kind, this);
1415 // Used when JSContext type is incomplete and so it is not known to inherit
1416 // from RootingContext.
1417 void registerWithRootLists(JSContext* cx) {
1418 registerWithRootLists(RootingContext::get(cx));
1421 public:
1422 using ElementType = T;
1424 PersistentRooted() : ptr(SafelyInitialized<T>::create()) {}
1426 template <
1427 typename RootHolder,
1428 typename = std::enable_if_t<std::is_copy_constructible_v<T>, RootHolder>>
1429 explicit PersistentRooted(const RootHolder& cx)
1430 : ptr(SafelyInitialized<T>::create()) {
1431 registerWithRootLists(cx);
1434 template <
1435 typename RootHolder, typename U,
1436 typename = std::enable_if_t<std::is_constructible_v<T, U>, RootHolder>>
1437 PersistentRooted(const RootHolder& cx, U&& initial)
1438 : ptr(std::forward<U>(initial)) {
1439 registerWithRootLists(cx);
1442 template <typename RootHolder, typename... CtorArgs,
1443 typename = std::enable_if_t<detail::IsTraceable_v<T>, RootHolder>>
1444 explicit PersistentRooted(const RootHolder& cx, CtorArgs... args)
1445 : ptr(std::forward<CtorArgs>(args)...) {
1446 registerWithRootLists(cx);
1449 PersistentRooted(const PersistentRooted& rhs) : ptr(rhs.ptr) {
1451 * Copy construction takes advantage of the fact that the original
1452 * is already inserted, and simply adds itself to whatever list the
1453 * original was on - no JSRuntime pointer needed.
1455 * This requires mutating rhs's links, but those should be 'mutable'
1456 * anyway. C++ doesn't let us declare mutable base classes.
1458 const_cast<PersistentRooted&>(rhs).setNext(this);
1461 bool initialized() const { return this->isInList(); }
1463 void init(RootingContext* cx) { init(cx, SafelyInitialized<T>::create()); }
1464 void init(JSContext* cx) { init(RootingContext::get(cx)); }
1466 template <typename U>
1467 void init(RootingContext* cx, U&& initial) {
1468 ptr = std::forward<U>(initial);
1469 registerWithRootLists(cx);
1471 template <typename U>
1472 void init(JSContext* cx, U&& initial) {
1473 ptr = std::forward<U>(initial);
1474 registerWithRootLists(RootingContext::get(cx));
1477 void reset() {
1478 if (initialized()) {
1479 set(SafelyInitialized<T>::create());
1480 this->remove();
1484 DECLARE_POINTER_CONSTREF_OPS(T);
1485 DECLARE_POINTER_ASSIGN_OPS(PersistentRooted, T);
1487 T& get() { return ptr; }
1488 const T& get() const { return ptr; }
1490 T* address() {
1491 MOZ_ASSERT(initialized());
1492 return &ptr;
1494 const T* address() const { return &ptr; }
1496 template <typename U>
1497 void set(U&& value) {
1498 MOZ_ASSERT(initialized());
1499 ptr = std::forward<U>(value);
1502 private:
1503 T ptr;
1504 } JS_HAZ_ROOTED;
1506 namespace detail {
1508 template <typename T>
1509 struct DefineComparisonOps<PersistentRooted<T>> : std::true_type {
1510 static const T& get(const PersistentRooted<T>& v) { return v.get(); }
1513 } // namespace detail
1515 } /* namespace JS */
1517 namespace js {
1519 template <typename T, typename D, typename Container>
1520 class WrappedPtrOperations<UniquePtr<T, D>, Container> {
1521 const UniquePtr<T, D>& uniquePtr() const {
1522 return static_cast<const Container*>(this)->get();
1525 public:
1526 explicit operator bool() const { return !!uniquePtr(); }
1527 T* get() const { return uniquePtr().get(); }
1528 T* operator->() const { return get(); }
1529 T& operator*() const { return *uniquePtr(); }
1532 template <typename T, typename D, typename Container>
1533 class MutableWrappedPtrOperations<UniquePtr<T, D>, Container>
1534 : public WrappedPtrOperations<UniquePtr<T, D>, Container> {
1535 UniquePtr<T, D>& uniquePtr() { return static_cast<Container*>(this)->get(); }
1537 public:
1538 [[nodiscard]] typename UniquePtr<T, D>::Pointer release() {
1539 return uniquePtr().release();
1541 void reset(T* ptr = T()) { uniquePtr().reset(ptr); }
1544 template <typename T, typename Container>
1545 class WrappedPtrOperations<mozilla::Maybe<T>, Container> {
1546 const mozilla::Maybe<T>& maybe() const {
1547 return static_cast<const Container*>(this)->get();
1550 public:
1551 // This only supports a subset of Maybe's interface.
1552 bool isSome() const { return maybe().isSome(); }
1553 bool isNothing() const { return maybe().isNothing(); }
1554 const T value() const { return maybe().value(); }
1555 const T* operator->() const { return maybe().ptr(); }
1556 const T& operator*() const { return maybe().ref(); }
1559 template <typename T, typename Container>
1560 class MutableWrappedPtrOperations<mozilla::Maybe<T>, Container>
1561 : public WrappedPtrOperations<mozilla::Maybe<T>, Container> {
1562 mozilla::Maybe<T>& maybe() { return static_cast<Container*>(this)->get(); }
1564 public:
1565 // This only supports a subset of Maybe's interface.
1566 T* operator->() { return maybe().ptr(); }
1567 T& operator*() { return maybe().ref(); }
1568 void reset() { return maybe().reset(); }
1571 namespace gc {
1573 template <typename T, typename TraceCallbacks>
1574 void CallTraceCallbackOnNonHeap(T* v, const TraceCallbacks& aCallbacks,
1575 const char* aName, void* aClosure) {
1576 static_assert(sizeof(T) == sizeof(JS::Heap<T>),
1577 "T and Heap<T> must be compatible.");
1578 MOZ_ASSERT(v);
1579 mozilla::DebugOnly<Cell*> cell = BarrierMethods<T>::asGCThingOrNull(*v);
1580 MOZ_ASSERT(cell);
1581 MOZ_ASSERT(!IsInsideNursery(cell));
1582 JS::Heap<T>* asHeapT = reinterpret_cast<JS::Heap<T>*>(v);
1583 aCallbacks.Trace(asHeapT, aName, aClosure);
1586 } /* namespace gc */
1588 template <typename Wrapper, typename T1, typename T2>
1589 class WrappedPtrOperations<std::pair<T1, T2>, Wrapper> {
1590 const std::pair<T1, T2>& pair() const {
1591 return static_cast<const Wrapper*>(this)->get();
1594 public:
1595 const T1& first() const { return pair().first; }
1596 const T2& second() const { return pair().second; }
1599 template <typename Wrapper, typename T1, typename T2>
1600 class MutableWrappedPtrOperations<std::pair<T1, T2>, Wrapper>
1601 : public WrappedPtrOperations<std::pair<T1, T2>, Wrapper> {
1602 std::pair<T1, T2>& pair() { return static_cast<Wrapper*>(this)->get(); }
1604 public:
1605 T1& first() { return pair().first; }
1606 T2& second() { return pair().second; }
1609 } /* namespace js */
1611 #endif /* js_RootingAPI_h */