Bug 1869092 - Fix timeouts in browser_PanelMultiView.js. r=twisniewski,test-only
[gecko.git] / js / public / RootingAPI.h
blob471c72dc423c24737fc3580c5eb38685d878c324
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::Nursery& nursery() const {
1024 MOZ_ASSERT(nursery_);
1025 return *nursery_;
1028 protected:
1029 // The remaining members in this class should only be accessed through
1030 // JSContext pointers. They are unrelated to rooting and are in place so
1031 // that inlined API functions can directly access the data.
1033 /* The nursery. Null for non-main-thread contexts. */
1034 js::Nursery* nursery_;
1036 /* The current zone. */
1037 Zone* zone_;
1039 /* The current realm. */
1040 Realm* realm_;
1042 public:
1043 /* Limit pointer for checking native stack consumption. */
1044 JS::NativeStackLimit nativeStackLimit[StackKindCount];
1046 #ifdef __wasi__
1047 // For WASI we can't catch call-stack overflows with stack-pointer checks, so
1048 // we count recursion depth with RAII based AutoCheckRecursionLimit.
1049 uint32_t wasiRecursionDepth = 0u;
1051 static constexpr uint32_t wasiRecursionDepthLimit = 350u;
1052 #endif // __wasi__
1054 static const RootingContext* get(const JSContext* cx) {
1055 return reinterpret_cast<const RootingContext*>(cx);
1058 static RootingContext* get(JSContext* cx) {
1059 return reinterpret_cast<RootingContext*>(cx);
1062 friend JS::Realm* js::GetContextRealm(const JSContext* cx);
1063 friend JS::Zone* js::GetContextZone(const JSContext* cx);
1066 class JS_PUBLIC_API AutoGCRooter {
1067 public:
1068 using Kind = AutoGCRooterKind;
1070 AutoGCRooter(JSContext* cx, Kind kind)
1071 : AutoGCRooter(JS::RootingContext::get(cx), kind) {}
1072 AutoGCRooter(RootingContext* cx, Kind kind)
1073 : down(cx->autoGCRooters_[kind]),
1074 stackTop(&cx->autoGCRooters_[kind]),
1075 kind_(kind) {
1076 MOZ_ASSERT(this != *stackTop);
1077 *stackTop = this;
1080 ~AutoGCRooter() {
1081 MOZ_ASSERT(this == *stackTop);
1082 *stackTop = down;
1085 void trace(JSTracer* trc);
1087 private:
1088 friend class RootingContext;
1090 AutoGCRooter* const down;
1091 AutoGCRooter** const stackTop;
1094 * Discriminates actual subclass of this being used. The meaning is
1095 * indicated by the corresponding value in the Kind enum.
1097 Kind kind_;
1099 /* No copy or assignment semantics. */
1100 AutoGCRooter(AutoGCRooter& ida) = delete;
1101 void operator=(AutoGCRooter& ida) = delete;
1102 } JS_HAZ_ROOTED_BASE;
1105 * Custom rooting behavior for internal and external clients.
1107 * Deprecated. Where possible, use Rooted<> instead.
1109 class MOZ_RAII JS_PUBLIC_API CustomAutoRooter : private AutoGCRooter {
1110 public:
1111 template <typename CX>
1112 explicit CustomAutoRooter(const CX& cx)
1113 : AutoGCRooter(cx, AutoGCRooter::Kind::Custom) {}
1115 friend void AutoGCRooter::trace(JSTracer* trc);
1117 protected:
1118 virtual ~CustomAutoRooter() = default;
1120 /** Supplied by derived class to trace roots. */
1121 virtual void trace(JSTracer* trc) = 0;
1124 namespace detail {
1126 template <typename T>
1127 constexpr bool IsTraceable_v =
1128 MapTypeToRootKind<T>::kind == JS::RootKind::Traceable;
1130 template <typename T>
1131 using RootedTraits =
1132 std::conditional_t<IsTraceable_v<T>, js::RootedTraceableTraits<T>,
1133 js::RootedGCThingTraits<T>>;
1135 } /* namespace detail */
1138 * Local variable of type T whose value is always rooted. This is typically
1139 * used for local variables, or for non-rooted values being passed to a
1140 * function that requires a handle, e.g. Foo(Root<T>(cx, x)).
1142 * If you want to add additional methods to Rooted for a specific
1143 * specialization, define a RootedOperations<T> specialization containing them.
1145 template <typename T>
1146 class MOZ_RAII Rooted : public detail::RootedTraits<T>::StackBase,
1147 public js::RootedOperations<T, Rooted<T>> {
1148 inline void registerWithRootLists(RootedListHeads& roots) {
1149 this->stack = &roots[JS::MapTypeToRootKind<T>::kind];
1150 this->prev = *this->stack;
1151 *this->stack = this;
1154 inline RootedListHeads& rootLists(RootingContext* cx) {
1155 return cx->stackRoots_;
1157 inline RootedListHeads& rootLists(JSContext* cx) {
1158 return rootLists(RootingContext::get(cx));
1161 public:
1162 using ElementType = T;
1164 // Construct an empty Rooted holding a safely initialized but empty T.
1165 // Requires T to have a copy constructor in order to copy the safely
1166 // initialized value.
1168 // Note that for SFINAE to reject this method, the 2nd template parameter must
1169 // depend on RootingContext somehow even though we really only care about T.
1170 template <typename RootingContext,
1171 typename = std::enable_if_t<std::is_copy_constructible_v<T>,
1172 RootingContext>>
1173 explicit Rooted(const RootingContext& cx)
1174 : ptr(SafelyInitialized<T>::create()) {
1175 registerWithRootLists(rootLists(cx));
1178 // Provide an initial value. Requires T to be constructible from the given
1179 // argument.
1180 template <typename RootingContext, typename S>
1181 Rooted(const RootingContext& cx, S&& initial)
1182 : ptr(std::forward<S>(initial)) {
1183 MOZ_ASSERT(GCPolicy<T>::isValid(ptr));
1184 registerWithRootLists(rootLists(cx));
1187 // (Traceables only) Construct the contained value from the given arguments.
1188 // Constructs in-place, so T does not need to be copyable or movable.
1190 // Note that a copyable Traceable passed only a RootingContext will
1191 // choose the above SafelyInitialized<T> constructor, because otherwise
1192 // identical functions with parameter packs are considered less specialized.
1194 // The SFINAE type must again depend on an inferred template parameter.
1195 template <
1196 typename RootingContext, typename... CtorArgs,
1197 typename = std::enable_if_t<detail::IsTraceable_v<T>, RootingContext>>
1198 explicit Rooted(const RootingContext& cx, CtorArgs... args)
1199 : ptr(std::forward<CtorArgs>(args)...) {
1200 MOZ_ASSERT(GCPolicy<T>::isValid(ptr));
1201 registerWithRootLists(rootLists(cx));
1204 ~Rooted() {
1205 MOZ_ASSERT(*this->stack == this);
1206 *this->stack = this->prev;
1210 * This method is public for Rooted so that Codegen.py can use a Rooted
1211 * interchangeably with a MutableHandleValue.
1213 void set(const T& value) {
1214 ptr = value;
1215 MOZ_ASSERT(GCPolicy<T>::isValid(ptr));
1217 void set(T&& value) {
1218 ptr = std::move(value);
1219 MOZ_ASSERT(GCPolicy<T>::isValid(ptr));
1222 DECLARE_POINTER_CONSTREF_OPS(T);
1223 DECLARE_POINTER_ASSIGN_OPS(Rooted, T);
1225 T& get() { return ptr; }
1226 const T& get() const { return ptr; }
1228 T* address() { return &ptr; }
1229 const T* address() const { return &ptr; }
1231 private:
1232 T ptr;
1234 Rooted(const Rooted&) = delete;
1235 } JS_HAZ_ROOTED;
1237 namespace detail {
1239 template <typename T>
1240 struct DefineComparisonOps<Rooted<T>> : std::true_type {
1241 static const T& get(const Rooted<T>& v) { return v.get(); }
1244 } // namespace detail
1246 } /* namespace JS */
1248 namespace js {
1251 * Inlinable accessors for JSContext.
1253 * - These must not be available on the more restricted superclasses of
1254 * JSContext, so we can't simply define them on RootingContext.
1256 * - They're perfectly ordinary JSContext functionality, so ought to be
1257 * usable without resorting to jsfriendapi.h, and when JSContext is an
1258 * incomplete type.
1260 inline JS::Realm* GetContextRealm(const JSContext* cx) {
1261 return JS::RootingContext::get(cx)->realm_;
1264 inline JS::Compartment* GetContextCompartment(const JSContext* cx) {
1265 if (JS::Realm* realm = GetContextRealm(cx)) {
1266 return GetCompartmentForRealm(realm);
1268 return nullptr;
1271 inline JS::Zone* GetContextZone(const JSContext* cx) {
1272 return JS::RootingContext::get(cx)->zone_;
1275 inline ProfilingStack* GetContextProfilingStackIfEnabled(JSContext* cx) {
1276 return JS::RootingContext::get(cx)
1277 ->geckoProfiler()
1278 .getProfilingStackIfEnabled();
1282 * Augment the generic Rooted<T> interface when T = JSObject* with
1283 * class-querying and downcasting operations.
1285 * Given a Rooted<JSObject*> obj, one can view
1286 * Handle<StringObject*> h = obj.as<StringObject*>();
1287 * as an optimization of
1288 * Rooted<StringObject*> rooted(cx, &obj->as<StringObject*>());
1289 * Handle<StringObject*> h = rooted;
1291 template <typename Container>
1292 class RootedOperations<JSObject*, Container>
1293 : public MutableWrappedPtrOperations<JSObject*, Container> {
1294 public:
1295 template <class U>
1296 JS::Handle<U*> as() const;
1300 * Augment the generic Handle<T> interface when T = JSObject* with
1301 * downcasting operations.
1303 * Given a Handle<JSObject*> obj, one can view
1304 * Handle<StringObject*> h = obj.as<StringObject*>();
1305 * as an optimization of
1306 * Rooted<StringObject*> rooted(cx, &obj->as<StringObject*>());
1307 * Handle<StringObject*> h = rooted;
1309 template <typename Container>
1310 class HandleOperations<JSObject*, Container>
1311 : public WrappedPtrOperations<JSObject*, Container> {
1312 public:
1313 template <class U>
1314 JS::Handle<U*> as() const;
1317 } /* namespace js */
1319 namespace JS {
1321 template <typename T>
1322 template <typename S>
1323 inline Handle<T>::Handle(
1324 const Rooted<S>& root,
1325 std::enable_if_t<std::is_convertible_v<S, T>, int> dummy) {
1326 ptr = reinterpret_cast<const T*>(root.address());
1329 template <typename T>
1330 template <typename S>
1331 inline Handle<T>::Handle(
1332 const PersistentRooted<S>& root,
1333 std::enable_if_t<std::is_convertible_v<S, T>, int> dummy) {
1334 ptr = reinterpret_cast<const T*>(root.address());
1337 template <typename T>
1338 template <typename S>
1339 inline Handle<T>::Handle(
1340 MutableHandle<S>& root,
1341 std::enable_if_t<std::is_convertible_v<S, T>, int> dummy) {
1342 ptr = reinterpret_cast<const T*>(root.address());
1345 template <typename T>
1346 inline MutableHandle<T>::MutableHandle(Rooted<T>* root) {
1347 static_assert(sizeof(MutableHandle<T>) == sizeof(T*),
1348 "MutableHandle must be binary compatible with T*.");
1349 ptr = root->address();
1352 template <typename T>
1353 inline MutableHandle<T>::MutableHandle(PersistentRooted<T>* root) {
1354 static_assert(sizeof(MutableHandle<T>) == sizeof(T*),
1355 "MutableHandle must be binary compatible with T*.");
1356 ptr = root->address();
1359 JS_PUBLIC_API void AddPersistentRoot(RootingContext* cx, RootKind kind,
1360 js::PersistentRootedBase* root);
1362 JS_PUBLIC_API void AddPersistentRoot(JSRuntime* rt, RootKind kind,
1363 js::PersistentRootedBase* root);
1366 * A copyable, assignable global GC root type with arbitrary lifetime, an
1367 * infallible constructor, and automatic unrooting on destruction.
1369 * These roots can be used in heap-allocated data structures, so they are not
1370 * associated with any particular JSContext or stack. They are registered with
1371 * the JSRuntime itself, without locking. Initialization may take place on
1372 * construction, or in two phases if the no-argument constructor is called
1373 * followed by init().
1375 * Note that you must not use an PersistentRooted in an object owned by a JS
1376 * object:
1378 * Whenever one object whose lifetime is decided by the GC refers to another
1379 * such object, that edge must be traced only if the owning JS object is traced.
1380 * This applies not only to JS objects (which obviously are managed by the GC)
1381 * but also to C++ objects owned by JS objects.
1383 * If you put a PersistentRooted in such a C++ object, that is almost certainly
1384 * a leak. When a GC begins, the referent of the PersistentRooted is treated as
1385 * live, unconditionally (because a PersistentRooted is a *root*), even if the
1386 * JS object that owns it is unreachable. If there is any path from that
1387 * referent back to the JS object, then the C++ object containing the
1388 * PersistentRooted will not be destructed, and the whole blob of objects will
1389 * not be freed, even if there are no references to them from the outside.
1391 * In the context of Firefox, this is a severe restriction: almost everything in
1392 * Firefox is owned by some JS object or another, so using PersistentRooted in
1393 * such objects would introduce leaks. For these kinds of edges, Heap<T> or
1394 * TenuredHeap<T> would be better types. It's up to the implementor of the type
1395 * containing Heap<T> or TenuredHeap<T> members to make sure their referents get
1396 * marked when the object itself is marked.
1398 template <typename T>
1399 class PersistentRooted : public detail::RootedTraits<T>::PersistentBase,
1400 public js::RootedOperations<T, PersistentRooted<T>> {
1401 void registerWithRootLists(RootingContext* cx) {
1402 MOZ_ASSERT(!initialized());
1403 JS::RootKind kind = JS::MapTypeToRootKind<T>::kind;
1404 AddPersistentRoot(cx, kind, this);
1407 void registerWithRootLists(JSRuntime* rt) {
1408 MOZ_ASSERT(!initialized());
1409 JS::RootKind kind = JS::MapTypeToRootKind<T>::kind;
1410 AddPersistentRoot(rt, kind, this);
1413 // Used when JSContext type is incomplete and so it is not known to inherit
1414 // from RootingContext.
1415 void registerWithRootLists(JSContext* cx) {
1416 registerWithRootLists(RootingContext::get(cx));
1419 public:
1420 using ElementType = T;
1422 PersistentRooted() : ptr(SafelyInitialized<T>::create()) {}
1424 template <
1425 typename RootHolder,
1426 typename = std::enable_if_t<std::is_copy_constructible_v<T>, RootHolder>>
1427 explicit PersistentRooted(const RootHolder& cx)
1428 : ptr(SafelyInitialized<T>::create()) {
1429 registerWithRootLists(cx);
1432 template <
1433 typename RootHolder, typename U,
1434 typename = std::enable_if_t<std::is_constructible_v<T, U>, RootHolder>>
1435 PersistentRooted(const RootHolder& cx, U&& initial)
1436 : ptr(std::forward<U>(initial)) {
1437 registerWithRootLists(cx);
1440 template <typename RootHolder, typename... CtorArgs,
1441 typename = std::enable_if_t<detail::IsTraceable_v<T>, RootHolder>>
1442 explicit PersistentRooted(const RootHolder& cx, CtorArgs... args)
1443 : ptr(std::forward<CtorArgs>(args)...) {
1444 registerWithRootLists(cx);
1447 PersistentRooted(const PersistentRooted& rhs) : ptr(rhs.ptr) {
1449 * Copy construction takes advantage of the fact that the original
1450 * is already inserted, and simply adds itself to whatever list the
1451 * original was on - no JSRuntime pointer needed.
1453 * This requires mutating rhs's links, but those should be 'mutable'
1454 * anyway. C++ doesn't let us declare mutable base classes.
1456 const_cast<PersistentRooted&>(rhs).setNext(this);
1459 bool initialized() const { return this->isInList(); }
1461 void init(RootingContext* cx) { init(cx, SafelyInitialized<T>::create()); }
1462 void init(JSContext* cx) { init(RootingContext::get(cx)); }
1464 template <typename U>
1465 void init(RootingContext* cx, U&& initial) {
1466 ptr = std::forward<U>(initial);
1467 registerWithRootLists(cx);
1469 template <typename U>
1470 void init(JSContext* cx, U&& initial) {
1471 ptr = std::forward<U>(initial);
1472 registerWithRootLists(RootingContext::get(cx));
1475 void reset() {
1476 if (initialized()) {
1477 set(SafelyInitialized<T>::create());
1478 this->remove();
1482 DECLARE_POINTER_CONSTREF_OPS(T);
1483 DECLARE_POINTER_ASSIGN_OPS(PersistentRooted, T);
1485 T& get() { return ptr; }
1486 const T& get() const { return ptr; }
1488 T* address() {
1489 MOZ_ASSERT(initialized());
1490 return &ptr;
1492 const T* address() const { return &ptr; }
1494 template <typename U>
1495 void set(U&& value) {
1496 MOZ_ASSERT(initialized());
1497 ptr = std::forward<U>(value);
1500 private:
1501 T ptr;
1502 } JS_HAZ_ROOTED;
1504 namespace detail {
1506 template <typename T>
1507 struct DefineComparisonOps<PersistentRooted<T>> : std::true_type {
1508 static const T& get(const PersistentRooted<T>& v) { return v.get(); }
1511 } // namespace detail
1513 } /* namespace JS */
1515 namespace js {
1517 template <typename T, typename D, typename Container>
1518 class WrappedPtrOperations<UniquePtr<T, D>, Container> {
1519 const UniquePtr<T, D>& uniquePtr() const {
1520 return static_cast<const Container*>(this)->get();
1523 public:
1524 explicit operator bool() const { return !!uniquePtr(); }
1525 T* get() const { return uniquePtr().get(); }
1526 T* operator->() const { return get(); }
1527 T& operator*() const { return *uniquePtr(); }
1530 template <typename T, typename D, typename Container>
1531 class MutableWrappedPtrOperations<UniquePtr<T, D>, Container>
1532 : public WrappedPtrOperations<UniquePtr<T, D>, Container> {
1533 UniquePtr<T, D>& uniquePtr() { return static_cast<Container*>(this)->get(); }
1535 public:
1536 [[nodiscard]] typename UniquePtr<T, D>::Pointer release() {
1537 return uniquePtr().release();
1539 void reset(T* ptr = T()) { uniquePtr().reset(ptr); }
1542 template <typename T, typename Container>
1543 class WrappedPtrOperations<mozilla::Maybe<T>, Container> {
1544 const mozilla::Maybe<T>& maybe() const {
1545 return static_cast<const Container*>(this)->get();
1548 public:
1549 // This only supports a subset of Maybe's interface.
1550 bool isSome() const { return maybe().isSome(); }
1551 bool isNothing() const { return maybe().isNothing(); }
1552 const T value() const { return maybe().value(); }
1553 const T* operator->() const { return maybe().ptr(); }
1554 const T& operator*() const { return maybe().ref(); }
1557 template <typename T, typename Container>
1558 class MutableWrappedPtrOperations<mozilla::Maybe<T>, Container>
1559 : public WrappedPtrOperations<mozilla::Maybe<T>, Container> {
1560 mozilla::Maybe<T>& maybe() { return static_cast<Container*>(this)->get(); }
1562 public:
1563 // This only supports a subset of Maybe's interface.
1564 T* operator->() { return maybe().ptr(); }
1565 T& operator*() { return maybe().ref(); }
1566 void reset() { return maybe().reset(); }
1569 namespace gc {
1571 template <typename T, typename TraceCallbacks>
1572 void CallTraceCallbackOnNonHeap(T* v, const TraceCallbacks& aCallbacks,
1573 const char* aName, void* aClosure) {
1574 static_assert(sizeof(T) == sizeof(JS::Heap<T>),
1575 "T and Heap<T> must be compatible.");
1576 MOZ_ASSERT(v);
1577 mozilla::DebugOnly<Cell*> cell = BarrierMethods<T>::asGCThingOrNull(*v);
1578 MOZ_ASSERT(cell);
1579 MOZ_ASSERT(!IsInsideNursery(cell));
1580 JS::Heap<T>* asHeapT = reinterpret_cast<JS::Heap<T>*>(v);
1581 aCallbacks.Trace(asHeapT, aName, aClosure);
1584 } /* namespace gc */
1586 template <typename Wrapper, typename T1, typename T2>
1587 class WrappedPtrOperations<std::pair<T1, T2>, Wrapper> {
1588 const std::pair<T1, T2>& pair() const {
1589 return static_cast<const Wrapper*>(this)->get();
1592 public:
1593 const T1& first() const { return pair().first; }
1594 const T2& second() const { return pair().second; }
1597 template <typename Wrapper, typename T1, typename T2>
1598 class MutableWrappedPtrOperations<std::pair<T1, T2>, Wrapper>
1599 : public WrappedPtrOperations<std::pair<T1, T2>, Wrapper> {
1600 std::pair<T1, T2>& pair() { return static_cast<Wrapper*>(this)->get(); }
1602 public:
1603 T1& first() { return pair().first; }
1604 T2& second() { return pair().second; }
1607 } /* namespace js */
1609 #endif /* js_RootingAPI_h */