tor-browser

The Tor Browser
git clone https://git.dasho.dev/tor-browser.git
Log | Files | Refs | README | LICENSE

RootingAPI.h (57564B)


      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/. */
      6 
      7 #ifndef js_RootingAPI_h
      8 #define js_RootingAPI_h
      9 
     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"
     15 
     16 #include <tuple>
     17 #include <type_traits>
     18 #include <utility>
     19 
     20 #include "jspubtd.h"
     21 
     22 #include "js/ComparisonOperators.h"  // JS::detail::DefineComparisonOps
     23 #include "js/GCAnnotations.h"
     24 #include "js/GCPolicyAPI.h"
     25 #include "js/GCTypeMacros.h"  // JS_FOR_EACH_PUBLIC_{,TAGGED_}GC_POINTER_TYPE
     26 #include "js/HashTable.h"
     27 #include "js/HeapAPI.h"            // StackKindCount
     28 #include "js/NativeStackLimits.h"  // JS::NativeStackLimit
     29 #include "js/ProfilingStack.h"
     30 #include "js/Realm.h"
     31 #include "js/TypeDecls.h"
     32 #include "js/UniquePtr.h"
     33 
     34 /*
     35 * [SMDOC] Stack Rooting
     36 *
     37 * Moving GC Stack Rooting
     38 *
     39 * A moving GC may change the physical location of GC allocated things, even
     40 * when they are rooted, updating all pointers to the thing to refer to its new
     41 * location. The GC must therefore know about all live pointers to a thing,
     42 * not just one of them, in order to behave correctly.
     43 *
     44 * The |Rooted| and |Handle| classes below are used to root stack locations
     45 * whose value may be held live across a call that can trigger GC. For a
     46 * code fragment such as:
     47 *
     48 * JSObject* obj = NewObject(cx);
     49 * DoSomething(cx);
     50 * ... = obj->lastProperty();
     51 *
     52 * If |DoSomething()| can trigger a GC, the stack location of |obj| must be
     53 * rooted to ensure that the GC does not move the JSObject referred to by
     54 * |obj| without updating |obj|'s location itself. This rooting must happen
     55 * regardless of whether there are other roots which ensure that the object
     56 * itself will not be collected.
     57 *
     58 * If |DoSomething()| cannot trigger a GC, and the same holds for all other
     59 * calls made between |obj|'s definitions and its last uses, then no rooting
     60 * is required.
     61 *
     62 * SpiderMonkey can trigger a GC at almost any time and in ways that are not
     63 * always clear. For example, the following innocuous-looking actions can
     64 * cause a GC: allocation of any new GC thing; JSObject::hasProperty;
     65 * JS_ReportError and friends; and ToNumber, among many others. The following
     66 * dangerous-looking actions cannot trigger a GC: js_malloc, cx->malloc_,
     67 * rt->malloc_, and friends and JS_ReportOutOfMemory.
     68 *
     69 * The following family of three classes will exactly root a stack location.
     70 * Incorrect usage of these classes will result in a compile error in almost
     71 * all cases. Therefore, it is very hard to be incorrectly rooted if you use
     72 * these classes exclusively. These classes are all templated on the type T of
     73 * the value being rooted.
     74 *
     75 * - Rooted<T> declares a variable of type T, whose value is always rooted.
     76 *   Rooted<T> may be automatically coerced to a Handle<T>, below. Rooted<T>
     77 *   should be used whenever a local variable's value may be held live across a
     78 *   call which can trigger a GC.
     79 *
     80 * - Handle<T> is a const reference to a Rooted<T>. Functions which take GC
     81 *   things or values as arguments and need to root those arguments should
     82 *   generally use handles for those arguments and avoid any explicit rooting.
     83 *   This has two benefits. First, when several such functions call each other
     84 *   then redundant rooting of multiple copies of the GC thing can be avoided.
     85 *   Second, if the caller does not pass a rooted value a compile error will be
     86 *   generated, which is quicker and easier to fix than when relying on a
     87 *   separate rooting analysis.
     88 *
     89 * - MutableHandle<T> is a non-const reference to Rooted<T>. It is used in the
     90 *   same way as Handle<T> and includes a |set(const T& v)| method to allow
     91 *   updating the value of the referenced Rooted<T>. A MutableHandle<T> can be
     92 *   created with an implicit cast from a Rooted<T>*.
     93 *
     94 * In some cases the small performance overhead of exact rooting (measured to
     95 * be a few nanoseconds on desktop) is too much. In these cases, try the
     96 * following:
     97 *
     98 * - Move all Rooted<T> above inner loops: this allows you to re-use the root
     99 *   on each iteration of the loop.
    100 *
    101 * - Pass Handle<T> through your hot call stack to avoid re-rooting costs at
    102 *   every invocation.
    103 *
    104 * The following diagram explains the list of supported, implicit type
    105 * conversions between classes of this family:
    106 *
    107 *  Rooted<T> ----> Handle<T>
    108 *     |               ^
    109 *     |               |
    110 *     |               |
    111 *     +---> MutableHandle<T>
    112 *     (via &)
    113 *
    114 * All of these types have an implicit conversion to raw pointers.
    115 */
    116 
    117 namespace js {
    118 
    119 class Nursery;
    120 
    121 // The defaulted Enable parameter for the following two types is for restricting
    122 // specializations with std::enable_if.
    123 template <typename T, typename Enable = void>
    124 struct BarrierMethods {};
    125 
    126 template <typename Element, typename Wrapper, typename Enable = void>
    127 class WrappedPtrOperations {};
    128 
    129 template <typename Element, typename Wrapper>
    130 class MutableWrappedPtrOperations
    131    : public WrappedPtrOperations<Element, Wrapper> {};
    132 
    133 template <typename T, typename Wrapper>
    134 class RootedOperations : public MutableWrappedPtrOperations<T, Wrapper> {};
    135 
    136 template <typename T, typename Wrapper>
    137 class HandleOperations : public WrappedPtrOperations<T, Wrapper> {};
    138 
    139 template <typename T, typename Wrapper>
    140 class MutableHandleOperations : public MutableWrappedPtrOperations<T, Wrapper> {
    141 };
    142 
    143 template <typename T, typename Wrapper>
    144 class HeapOperations : public MutableWrappedPtrOperations<T, Wrapper> {};
    145 
    146 // Cannot use FOR_EACH_HEAP_ABLE_GC_POINTER_TYPE, as this would import too many
    147 // macros into scope
    148 
    149 // Add a 2nd template parameter to allow conditionally enabling partial
    150 // specializations via std::enable_if.
    151 template <typename T, typename Enable = void>
    152 struct IsHeapConstructibleType : public std::false_type {};
    153 
    154 #define JS_DECLARE_IS_HEAP_CONSTRUCTIBLE_TYPE(T) \
    155  template <>                                    \
    156  struct IsHeapConstructibleType<T> : public std::true_type {};
    157 JS_FOR_EACH_PUBLIC_GC_POINTER_TYPE(JS_DECLARE_IS_HEAP_CONSTRUCTIBLE_TYPE)
    158 JS_FOR_EACH_PUBLIC_TAGGED_GC_POINTER_TYPE(JS_DECLARE_IS_HEAP_CONSTRUCTIBLE_TYPE)
    159 // Note that JS_DECLARE_IS_HEAP_CONSTRUCTIBLE_TYPE is left defined, to allow
    160 // declaring other types (eg from js/public/experimental/TypedData.h) to
    161 // be used with Heap<>.
    162 
    163 namespace gc {
    164 struct Cell;
    165 } /* namespace gc */
    166 
    167 // Important: Return a reference so passing a Rooted<T>, etc. to
    168 // something that takes a |const T&| is not a GC hazard.
    169 #define DECLARE_POINTER_CONSTREF_OPS(T)       \
    170  operator const T&() const { return get(); } \
    171  const T& operator->() const { return get(); }
    172 
    173 // Assignment operators on a base class are hidden by the implicitly defined
    174 // operator= on the derived class. Thus, define the operator= directly on the
    175 // class as we would need to manually pass it through anyway.
    176 #define DECLARE_POINTER_ASSIGN_OPS(Wrapper, T) \
    177  Wrapper& operator=(const T& p) {             \
    178    set(p);                                    \
    179    return *this;                              \
    180  }                                            \
    181  Wrapper& operator=(T&& p) {                  \
    182    set(std::move(p));                         \
    183    return *this;                              \
    184  }                                            \
    185  Wrapper& operator=(const Wrapper& other) {   \
    186    set(other.get());                          \
    187    return *this;                              \
    188  }
    189 
    190 #define DELETE_ASSIGNMENT_OPS(Wrapper, T) \
    191  template <typename S>                   \
    192  Wrapper<T>& operator=(S) = delete;      \
    193  Wrapper<T>& operator=(const Wrapper<T>&) = delete;
    194 
    195 #define DECLARE_NONPOINTER_ACCESSOR_METHODS(ptr) \
    196  const T* address() const { return &(ptr); }    \
    197  const T& get() const { return (ptr); }
    198 
    199 #define DECLARE_NONPOINTER_MUTABLE_ACCESSOR_METHODS(ptr) \
    200  T* address() { return &(ptr); }                        \
    201  T& get() { return (ptr); }
    202 
    203 } /* namespace js */
    204 
    205 namespace JS {
    206 
    207 JS_PUBLIC_API void HeapObjectPostWriteBarrier(JSObject** objp, JSObject* prev,
    208                                              JSObject* next);
    209 JS_PUBLIC_API void HeapObjectWriteBarriers(JSObject** objp, JSObject* prev,
    210                                           JSObject* next);
    211 JS_PUBLIC_API void HeapStringWriteBarriers(JSString** objp, JSString* prev,
    212                                           JSString* next);
    213 JS_PUBLIC_API void HeapBigIntWriteBarriers(JS::BigInt** bip, JS::BigInt* prev,
    214                                           JS::BigInt* next);
    215 JS_PUBLIC_API void HeapScriptWriteBarriers(JSScript** objp, JSScript* prev,
    216                                           JSScript* next);
    217 
    218 /**
    219 * SafelyInitialized<T>::create() creates a safely-initialized |T|, suitable for
    220 * use as a default value in situations requiring a safe but arbitrary |T|
    221 * value. Implemented as a static method of a struct to allow partial
    222 * specialization for subclasses via the Enable template parameter.
    223 */
    224 template <typename T, typename Enable = void>
    225 struct SafelyInitialized {
    226  static constexpr T create() {
    227    // This function wants to presume that |T()| -- which value-initializes a
    228    // |T| per C++11 [expr.type.conv]p2 -- will produce a safely-initialized,
    229    // safely-usable T that it can return.
    230 
    231    // That presumption holds for pointers, where value initialization produces
    232    // a null pointer.
    233    constexpr bool IsPointer = std::is_pointer_v<T>;
    234 
    235    // For classes and unions we *assume* that if |T|'s default constructor is
    236    // non-trivial it'll initialize correctly. (This is unideal, but C++
    237    // doesn't offer a type trait indicating whether a class's constructor is
    238    // user-defined, which better approximates our desired semantics.)
    239    constexpr bool IsNonTriviallyDefaultConstructibleClassOrUnion =
    240        (std::is_class_v<T> || std::is_union_v<T>) &&
    241        !std::is_trivially_default_constructible_v<T>;
    242 
    243    static_assert(IsPointer || IsNonTriviallyDefaultConstructibleClassOrUnion,
    244                  "T() must evaluate to a safely-initialized T");
    245 
    246    return T();
    247  }
    248 };
    249 
    250 #ifdef JS_DEBUG
    251 /**
    252 * For generational GC, assert that an object is in the tenured generation as
    253 * opposed to being in the nursery.
    254 */
    255 extern JS_PUBLIC_API void AssertGCThingMustBeTenured(JSObject* obj);
    256 extern JS_PUBLIC_API void AssertGCThingIsNotNurseryAllocable(
    257    js::gc::Cell* cell);
    258 #else
    259 inline void AssertGCThingMustBeTenured(JSObject* obj) {}
    260 inline void AssertGCThingIsNotNurseryAllocable(js::gc::Cell* cell) {}
    261 #endif
    262 
    263 /**
    264 * The Heap<T> class is a heap-stored reference to a JS GC thing for use outside
    265 * the JS engine. All members of heap classes that refer to GC things should use
    266 * Heap<T> (or possibly TenuredHeap<T>, described below).
    267 *
    268 * Heap<T> is an abstraction that hides some of the complexity required to
    269 * maintain GC invariants for the contained reference. It uses operator
    270 * overloading to provide a normal pointer interface, but adds barriers to
    271 * notify the GC of changes.
    272 *
    273 * Heap<T> implements the following barriers:
    274 *
    275 *  - Pre-write barrier (necessary for incremental GC).
    276 *  - Post-write barrier (necessary for generational GC).
    277 *  - Read barrier (necessary for cycle collector integration).
    278 *
    279 * Heap<T> may be moved or destroyed outside of GC finalization and hence may be
    280 * used in dynamic storage such as a Vector.
    281 *
    282 * Heap<T> instances must be traced when their containing object is traced to
    283 * keep the pointed-to GC thing alive.
    284 *
    285 * Heap<T> objects should only be used on the heap. GC references stored on the
    286 * C/C++ stack must use Rooted/Handle/MutableHandle instead.
    287 *
    288 * Type T must be a public GC pointer type.
    289 */
    290 template <typename T>
    291 class MOZ_NON_MEMMOVABLE Heap : public js::HeapOperations<T, Heap<T>> {
    292  static_assert(js::IsHeapConstructibleType<T>::value,
    293                "Type T must be a public GC pointer type");
    294 
    295 public:
    296  using ElementType = T;
    297 
    298  Heap() : ptr(SafelyInitialized<T>::create()) {
    299    // No barriers are required for initialization to the default value.
    300    static_assert(sizeof(T) == sizeof(Heap<T>),
    301                  "Heap<T> must be binary compatible with T.");
    302  }
    303  explicit Heap(const T& p) : ptr(p) {
    304    writeBarriers(SafelyInitialized<T>::create(), ptr);
    305  }
    306 
    307  /*
    308   * For Heap, move semantics are equivalent to copy semantics. However, we want
    309   * the copy constructor to be explicit, and an explicit move constructor
    310   * breaks common usage of move semantics, so we need to define both, even
    311   * though they are equivalent.
    312   */
    313  explicit Heap(const Heap<T>& other) : ptr(other.unbarrieredGet()) {
    314    writeBarriers(SafelyInitialized<T>::create(), ptr);
    315  }
    316  Heap(Heap<T>&& other) : ptr(other.unbarrieredGet()) {
    317    writeBarriers(SafelyInitialized<T>::create(), ptr);
    318  }
    319 
    320  Heap& operator=(Heap<T>&& other) {
    321    set(other.unbarrieredGet());
    322    other.set(SafelyInitialized<T>::create());
    323    return *this;
    324  }
    325  // Copy constructor defined by DECLARE_POINTER_ASSIGN_OPS.
    326 
    327  ~Heap() { writeBarriers(ptr, SafelyInitialized<T>::create()); }
    328 
    329  DECLARE_POINTER_CONSTREF_OPS(T);
    330  DECLARE_POINTER_ASSIGN_OPS(Heap<T>, T);
    331 
    332  void exposeToActiveJS() const { js::BarrierMethods<T>::exposeToJS(ptr); }
    333 
    334  const T& get() const {
    335    exposeToActiveJS();
    336    return ptr;
    337  }
    338  const T& unbarrieredGet() const { return ptr; }
    339 
    340  void set(const T& newPtr) {
    341    T tmp = ptr;
    342    ptr = newPtr;
    343    writeBarriers(tmp, ptr);
    344  }
    345  void unbarrieredSet(const T& newPtr) { ptr = newPtr; }
    346 
    347  T* unsafeAddress() { return &ptr; }
    348  const T* unsafeAddress() const { return &ptr; }
    349 
    350  explicit operator bool() const {
    351    return bool(js::BarrierMethods<T>::asGCThingOrNull(ptr));
    352  }
    353 
    354 private:
    355  void writeBarriers(const T& prev, const T& next) {
    356    js::BarrierMethods<T>::writeBarriers(&ptr, prev, next);
    357  }
    358 
    359  T ptr;
    360 };
    361 
    362 namespace detail {
    363 
    364 template <typename T>
    365 struct DefineComparisonOps<Heap<T>> : std::true_type {
    366  static const T& get(const Heap<T>& v) { return v.unbarrieredGet(); }
    367 };
    368 
    369 }  // namespace detail
    370 
    371 static MOZ_ALWAYS_INLINE bool ObjectIsTenured(JSObject* obj) {
    372  return !js::gc::IsInsideNursery(reinterpret_cast<js::gc::Cell*>(obj));
    373 }
    374 
    375 static MOZ_ALWAYS_INLINE bool ObjectIsTenured(const Heap<JSObject*>& obj) {
    376  return ObjectIsTenured(obj.unbarrieredGet());
    377 }
    378 
    379 static MOZ_ALWAYS_INLINE bool ObjectIsMarkedGray(JSObject* obj) {
    380  auto cell = reinterpret_cast<js::gc::Cell*>(obj);
    381  if (js::gc::IsInsideNursery(cell)) {
    382    return false;
    383  }
    384 
    385  auto tenuredCell = reinterpret_cast<js::gc::TenuredCell*>(cell);
    386  return js::gc::detail::CellIsMarkedGrayIfKnown(tenuredCell);
    387 }
    388 
    389 static MOZ_ALWAYS_INLINE bool ObjectIsMarkedGray(
    390    const JS::Heap<JSObject*>& obj) {
    391  return ObjectIsMarkedGray(obj.unbarrieredGet());
    392 }
    393 
    394 // The following *IsNotGray functions take account of the eventual
    395 // gray marking state at the end of any ongoing incremental GC by
    396 // delaying the checks if necessary.
    397 
    398 #ifdef DEBUG
    399 
    400 inline void AssertCellIsNotGray(const js::gc::Cell* maybeCell) {
    401  if (maybeCell) {
    402    js::gc::detail::AssertCellIsNotGray(maybeCell);
    403  }
    404 }
    405 
    406 inline void AssertObjectIsNotGray(JSObject* maybeObj) {
    407  AssertCellIsNotGray(reinterpret_cast<js::gc::Cell*>(maybeObj));
    408 }
    409 
    410 inline void AssertObjectIsNotGray(const JS::Heap<JSObject*>& obj) {
    411  AssertObjectIsNotGray(obj.unbarrieredGet());
    412 }
    413 
    414 #else
    415 
    416 inline void AssertCellIsNotGray(js::gc::Cell* maybeCell) {}
    417 inline void AssertObjectIsNotGray(JSObject* maybeObj) {}
    418 inline void AssertObjectIsNotGray(const JS::Heap<JSObject*>& obj) {}
    419 
    420 #endif
    421 
    422 /**
    423 * The TenuredHeap<T> class is similar to the Heap<T> class above in that it
    424 * encapsulates the GC concerns of an on-heap reference to a JS object. However,
    425 * it has two important differences:
    426 *
    427 *  1) Pointers which are statically known to only reference "tenured" objects
    428 *     can avoid the extra overhead of SpiderMonkey's post write barriers.
    429 *
    430 *  2) Objects in the "tenured" heap have stronger alignment restrictions than
    431 *     those in the "nursery", so it is possible to store flags in the lower
    432 *     bits of pointers known to be tenured. TenuredHeap wraps a normal tagged
    433 *     pointer with a nice API for accessing the flag bits and adds various
    434 *     assertions to ensure that it is not mis-used.
    435 *
    436 * GC things are said to be "tenured" when they are located in the long-lived
    437 * heap: e.g. they have gained tenure as an object by surviving past at least
    438 * one GC. For performance, SpiderMonkey allocates some things which are known
    439 * to normally be long lived directly into the tenured generation; for example,
    440 * global objects. Additionally, SpiderMonkey does not visit individual objects
    441 * when deleting non-tenured objects, so object with finalizers are also always
    442 * tenured; for instance, this includes most DOM objects.
    443 *
    444 * The considerations to keep in mind when using a TenuredHeap<T> vs a normal
    445 * Heap<T> are:
    446 *
    447 *  - It is invalid for a TenuredHeap<T> to refer to a non-tenured thing.
    448 *  - It is however valid for a Heap<T> to refer to a tenured thing.
    449 *  - It is not possible to store flag bits in a Heap<T>.
    450 */
    451 template <typename T>
    452 class TenuredHeap : public js::HeapOperations<T, TenuredHeap<T>> {
    453  static_assert(js::IsHeapConstructibleType<T>::value,
    454                "Type T must be a public GC pointer type");
    455 
    456 public:
    457  using ElementType = T;
    458 
    459  TenuredHeap() : bits(0) {
    460    static_assert(sizeof(T) == sizeof(TenuredHeap<T>),
    461                  "TenuredHeap<T> must be binary compatible with T.");
    462  }
    463 
    464  explicit TenuredHeap(T p) : bits(0) { unbarrieredSetPtr(p); }
    465  explicit TenuredHeap(const TenuredHeap<T>& p) : bits(0) {
    466    unbarrieredSetPtr(p.getPtr());
    467  }
    468 
    469  TenuredHeap<T>& operator=(T p) {
    470    setPtr(p);
    471    return *this;
    472  }
    473  TenuredHeap<T>& operator=(const TenuredHeap<T>& other) {
    474    preWriteBarrier();
    475    bits = other.bits;
    476    return *this;
    477  }
    478 
    479  ~TenuredHeap() { preWriteBarrier(); }
    480 
    481  void setPtr(T newPtr) {
    482    preWriteBarrier();
    483    unbarrieredSetPtr(newPtr);
    484  }
    485  void unbarrieredSetPtr(T newPtr) {
    486    MOZ_ASSERT((reinterpret_cast<uintptr_t>(newPtr) & flagsMask) == 0);
    487    MOZ_ASSERT(js::gc::IsCellPointerValidOrNull(newPtr));
    488    if (newPtr) {
    489      AssertGCThingMustBeTenured(newPtr);
    490    }
    491    bits = (bits & flagsMask) | reinterpret_cast<uintptr_t>(newPtr);
    492  }
    493 
    494  void setFlags(uintptr_t flagsToSet) {
    495    MOZ_ASSERT((flagsToSet & ~flagsMask) == 0);
    496    bits |= flagsToSet;
    497  }
    498 
    499  void unsetFlags(uintptr_t flagsToUnset) {
    500    MOZ_ASSERT((flagsToUnset & ~flagsMask) == 0);
    501    bits &= ~flagsToUnset;
    502  }
    503 
    504  bool hasFlag(uintptr_t flag) const {
    505    MOZ_ASSERT((flag & ~flagsMask) == 0);
    506    return (bits & flag) != 0;
    507  }
    508 
    509  T unbarrieredGetPtr() const { return reinterpret_cast<T>(bits & ~flagsMask); }
    510  uintptr_t getFlags() const { return bits & flagsMask; }
    511 
    512  void exposeToActiveJS() const {
    513    js::BarrierMethods<T>::exposeToJS(unbarrieredGetPtr());
    514  }
    515  T getPtr() const {
    516    exposeToActiveJS();
    517    return unbarrieredGetPtr();
    518  }
    519 
    520  operator T() const { return getPtr(); }
    521  T operator->() const { return getPtr(); }
    522 
    523  explicit operator bool() const {
    524    return bool(js::BarrierMethods<T>::asGCThingOrNull(unbarrieredGetPtr()));
    525  }
    526 
    527 private:
    528  enum {
    529    maskBits = 3,
    530    flagsMask = (1 << maskBits) - 1,
    531  };
    532 
    533  void preWriteBarrier() {
    534    if (T prev = unbarrieredGetPtr()) {
    535      JS::IncrementalPreWriteBarrier(JS::GCCellPtr(prev));
    536    }
    537  }
    538 
    539  uintptr_t bits;
    540 };
    541 
    542 namespace detail {
    543 
    544 template <typename T>
    545 struct DefineComparisonOps<TenuredHeap<T>> : std::true_type {
    546  static const T get(const TenuredHeap<T>& v) { return v.unbarrieredGetPtr(); }
    547 };
    548 
    549 }  // namespace detail
    550 
    551 // std::swap uses a stack temporary, which prevents classes like Heap<T>
    552 // from being declared MOZ_HEAP_CLASS.
    553 template <typename T>
    554 void swap(TenuredHeap<T>& aX, TenuredHeap<T>& aY) {
    555  T tmp = aX;
    556  aX = aY;
    557  aY = tmp;
    558 }
    559 
    560 template <typename T>
    561 void swap(Heap<T>& aX, Heap<T>& aY) {
    562  T tmp = aX;
    563  aX = aY;
    564  aY = tmp;
    565 }
    566 
    567 static MOZ_ALWAYS_INLINE bool ObjectIsMarkedGray(
    568    const JS::TenuredHeap<JSObject*>& obj) {
    569  return ObjectIsMarkedGray(obj.unbarrieredGetPtr());
    570 }
    571 
    572 template <typename T>
    573 class MutableHandle;
    574 template <typename T>
    575 class Rooted;
    576 template <typename T, size_t N = SIZE_MAX>
    577 class RootedField;
    578 template <typename T>
    579 class PersistentRooted;
    580 
    581 /**
    582 * Reference to a T that has been rooted elsewhere. This is most useful
    583 * as a parameter type, which guarantees that the T lvalue is properly
    584 * rooted. See "Move GC Stack Rooting" above.
    585 *
    586 * If you want to add additional methods to Handle for a specific
    587 * specialization, define a HandleOperations<T> specialization containing them.
    588 */
    589 template <typename T>
    590 class MOZ_NONHEAP_CLASS Handle : public js::HandleOperations<T, Handle<T>> {
    591  friend class MutableHandle<T>;
    592 
    593 public:
    594  using ElementType = T;
    595 
    596  Handle(const Handle<T>&) = default;
    597 
    598  /* Creates a handle from a handle of a type convertible to T. */
    599  template <typename S>
    600  MOZ_IMPLICIT Handle(
    601      Handle<S> handle,
    602      std::enable_if_t<std::is_convertible_v<S, T>, int> dummy = 0) {
    603    static_assert(sizeof(Handle<T>) == sizeof(T*),
    604                  "Handle must be binary compatible with T*.");
    605    ptr = reinterpret_cast<const T*>(handle.address());
    606  }
    607 
    608  MOZ_IMPLICIT Handle(decltype(nullptr)) {
    609    static_assert(std::is_pointer_v<T>,
    610                  "nullptr_t overload not valid for non-pointer types");
    611    static void* const ConstNullValue = nullptr;
    612    ptr = reinterpret_cast<const T*>(&ConstNullValue);
    613  }
    614 
    615  MOZ_IMPLICIT Handle(MutableHandle<T> handle) { ptr = handle.address(); }
    616 
    617  /*
    618   * Take care when calling this method!
    619   *
    620   * This creates a Handle from the raw location of a T.
    621   *
    622   * It should be called only if the following conditions hold:
    623   *
    624   *  1) the location of the T is guaranteed to be marked (for some reason
    625   *     other than being a Rooted), e.g., if it is guaranteed to be reachable
    626   *     from an implicit root.
    627   *
    628   *  2) the contents of the location are immutable, or at least cannot change
    629   *     for the lifetime of the handle, as its users may not expect its value
    630   *     to change underneath them.
    631   */
    632  static constexpr Handle fromMarkedLocation(const T* p) {
    633    return Handle(p, DeliberatelyChoosingThisOverload,
    634                  ImUsingThisOnlyInFromFromMarkedLocation);
    635  }
    636 
    637  /*
    638   * Construct a handle from an explicitly rooted location. This is the
    639   * normal way to create a handle, and normally happens implicitly.
    640   */
    641  template <typename S>
    642  inline MOZ_IMPLICIT Handle(
    643      const Rooted<S>& root,
    644      std::enable_if_t<std::is_convertible_v<S, T>, int> dummy = 0);
    645 
    646  template <typename S>
    647  inline MOZ_IMPLICIT Handle(
    648      const PersistentRooted<S>& root,
    649      std::enable_if_t<std::is_convertible_v<S, T>, int> dummy = 0);
    650 
    651  /* Construct a read only handle from a mutable handle. */
    652  template <typename S>
    653  inline MOZ_IMPLICIT Handle(
    654      MutableHandle<S>& root,
    655      std::enable_if_t<std::is_convertible_v<S, T>, int> dummy = 0);
    656 
    657  template <size_t N, typename S>
    658  inline MOZ_IMPLICIT Handle(
    659      const RootedField<S, N>& rootedField,
    660      std::enable_if_t<std::is_convertible_v<S, T>, int> dummy = 0);
    661 
    662  DECLARE_POINTER_CONSTREF_OPS(T);
    663  DECLARE_NONPOINTER_ACCESSOR_METHODS(*ptr);
    664 
    665 private:
    666  Handle() = default;
    667  DELETE_ASSIGNMENT_OPS(Handle, T);
    668 
    669  enum Disambiguator { DeliberatelyChoosingThisOverload = 42 };
    670  enum CallerIdentity { ImUsingThisOnlyInFromFromMarkedLocation = 17 };
    671  constexpr Handle(const T* p, Disambiguator, CallerIdentity) : ptr(p) {}
    672 
    673  const T* ptr;
    674 };
    675 
    676 namespace detail {
    677 
    678 template <typename T>
    679 struct DefineComparisonOps<Handle<T>> : std::true_type {
    680  static const T& get(const Handle<T>& v) { return v.get(); }
    681 };
    682 
    683 }  // namespace detail
    684 
    685 /**
    686 * Similar to a handle, but the underlying storage can be changed. This is
    687 * useful for outparams.
    688 *
    689 * If you want to add additional methods to MutableHandle for a specific
    690 * specialization, define a MutableHandleOperations<T> specialization containing
    691 * them.
    692 */
    693 template <typename T>
    694 class MOZ_STACK_CLASS MutableHandle
    695    : public js::MutableHandleOperations<T, MutableHandle<T>> {
    696 public:
    697  using ElementType = T;
    698 
    699  inline MOZ_IMPLICIT MutableHandle(Rooted<T>* root);
    700  template <size_t N>
    701  inline MOZ_IMPLICIT MutableHandle(RootedField<T, N>* root);
    702  inline MOZ_IMPLICIT MutableHandle(PersistentRooted<T>* root);
    703 
    704 private:
    705  // Disallow nullptr for overloading purposes.
    706  MutableHandle(decltype(nullptr)) = delete;
    707 
    708 public:
    709  MutableHandle(const MutableHandle<T>&) = default;
    710  void set(const T& v) {
    711    *ptr = v;
    712    MOZ_ASSERT(GCPolicy<T>::isValid(*ptr));
    713  }
    714  void set(T&& v) {
    715    *ptr = std::move(v);
    716    MOZ_ASSERT(GCPolicy<T>::isValid(*ptr));
    717  }
    718 
    719  /*
    720   * This may be called only if the location of the T is guaranteed
    721   * to be marked (for some reason other than being a Rooted),
    722   * e.g., if it is guaranteed to be reachable from an implicit root.
    723   *
    724   * Create a MutableHandle from a raw location of a T.
    725   */
    726  static MutableHandle fromMarkedLocation(T* p) {
    727    MutableHandle h;
    728    h.ptr = p;
    729    return h;
    730  }
    731 
    732  DECLARE_POINTER_CONSTREF_OPS(T);
    733  DECLARE_NONPOINTER_ACCESSOR_METHODS(*ptr);
    734  DECLARE_NONPOINTER_MUTABLE_ACCESSOR_METHODS(*ptr);
    735 
    736 private:
    737  MutableHandle() = default;
    738  DELETE_ASSIGNMENT_OPS(MutableHandle, T);
    739 
    740  T* ptr;
    741 };
    742 
    743 namespace detail {
    744 
    745 template <typename T>
    746 struct DefineComparisonOps<MutableHandle<T>> : std::true_type {
    747  static const T& get(const MutableHandle<T>& v) { return v.get(); }
    748 };
    749 
    750 }  // namespace detail
    751 
    752 } /* namespace JS */
    753 
    754 namespace js {
    755 
    756 namespace detail {
    757 
    758 // Default implementations for barrier methods on GC thing pointers.
    759 template <typename T>
    760 struct PtrBarrierMethodsBase {
    761  static T* initial() { return nullptr; }
    762  static gc::Cell* asGCThingOrNull(T* v) {
    763    if (!v) {
    764      return nullptr;
    765    }
    766    MOZ_ASSERT(uintptr_t(v) > 32);
    767    return reinterpret_cast<gc::Cell*>(v);
    768  }
    769  static void exposeToJS(T* t) {
    770    if (t) {
    771      js::gc::ExposeGCThingToActiveJS(JS::GCCellPtr(t));
    772    }
    773  }
    774  static void readBarrier(T* t) {
    775    if (t) {
    776      js::gc::IncrementalReadBarrier(JS::GCCellPtr(t));
    777    }
    778  }
    779 };
    780 
    781 }  // namespace detail
    782 
    783 template <typename T>
    784 struct BarrierMethods<T*> : public detail::PtrBarrierMethodsBase<T> {
    785  static void writeBarriers(T** vp, T* prev, T* next) {
    786    if (prev) {
    787      JS::IncrementalPreWriteBarrier(JS::GCCellPtr(prev));
    788    }
    789    if (next) {
    790      JS::AssertGCThingIsNotNurseryAllocable(
    791          reinterpret_cast<js::gc::Cell*>(next));
    792    }
    793  }
    794 };
    795 
    796 template <>
    797 struct BarrierMethods<JSObject*>
    798    : public detail::PtrBarrierMethodsBase<JSObject> {
    799  static void writeBarriers(JSObject** vp, JSObject* prev, JSObject* next) {
    800    JS::HeapObjectWriteBarriers(vp, prev, next);
    801  }
    802  static void postWriteBarrier(JSObject** vp, JSObject* prev, JSObject* next) {
    803    JS::HeapObjectPostWriteBarrier(vp, prev, next);
    804  }
    805  static void exposeToJS(JSObject* obj) {
    806    if (obj) {
    807      JS::ExposeObjectToActiveJS(obj);
    808    }
    809  }
    810 };
    811 
    812 template <>
    813 struct BarrierMethods<JSFunction*>
    814    : public detail::PtrBarrierMethodsBase<JSFunction> {
    815  static void writeBarriers(JSFunction** vp, JSFunction* prev,
    816                            JSFunction* next) {
    817    JS::HeapObjectWriteBarriers(reinterpret_cast<JSObject**>(vp),
    818                                reinterpret_cast<JSObject*>(prev),
    819                                reinterpret_cast<JSObject*>(next));
    820  }
    821  static void exposeToJS(JSFunction* fun) {
    822    if (fun) {
    823      JS::ExposeObjectToActiveJS(reinterpret_cast<JSObject*>(fun));
    824    }
    825  }
    826 };
    827 
    828 template <>
    829 struct BarrierMethods<JSString*>
    830    : public detail::PtrBarrierMethodsBase<JSString> {
    831  static void writeBarriers(JSString** vp, JSString* prev, JSString* next) {
    832    JS::HeapStringWriteBarriers(vp, prev, next);
    833  }
    834 };
    835 
    836 template <>
    837 struct BarrierMethods<JSScript*>
    838    : public detail::PtrBarrierMethodsBase<JSScript> {
    839  static void writeBarriers(JSScript** vp, JSScript* prev, JSScript* next) {
    840    JS::HeapScriptWriteBarriers(vp, prev, next);
    841  }
    842 };
    843 
    844 template <>
    845 struct BarrierMethods<JS::BigInt*>
    846    : public detail::PtrBarrierMethodsBase<JS::BigInt> {
    847  static void writeBarriers(JS::BigInt** vp, JS::BigInt* prev,
    848                            JS::BigInt* next) {
    849    JS::HeapBigIntWriteBarriers(vp, prev, next);
    850  }
    851 };
    852 
    853 // Provide hash codes for Cell kinds that may be relocated and, thus, not have
    854 // a stable address to use as the base for a hash code. Instead of the address,
    855 // this hasher uses Cell::getUniqueId to provide exact matches and as a base
    856 // for generating hash codes.
    857 //
    858 // Note: this hasher, like PointerHasher can "hash" a nullptr. While a nullptr
    859 // would not likely be a useful key, there are some cases where being able to
    860 // hash a nullptr is useful, either on purpose or because of bugs:
    861 // (1) existence checks where the key may happen to be null and (2) some
    862 // aggregate Lookup kinds embed a JSObject* that is frequently null and do not
    863 // null test before dispatching to the hasher.
    864 template <typename T>
    865 struct JS_PUBLIC_API StableCellHasher {
    866  using Key = T;
    867  using Lookup = T;
    868 
    869  static bool maybeGetHash(const Lookup& l, mozilla::HashNumber* hashOut);
    870  static bool ensureHash(const Lookup& l, HashNumber* hashOut);
    871  static HashNumber hash(const Lookup& l);
    872  static bool match(const Key& k, const Lookup& l);
    873  // The rekey hash policy method is not provided since you dont't need to
    874  // rekey any more when using this policy.
    875 };
    876 
    877 template <typename T>
    878 struct JS_PUBLIC_API StableCellHasher<JS::Heap<T>> {
    879  using Key = JS::Heap<T>;
    880  using Lookup = T;
    881 
    882  static bool maybeGetHash(const Lookup& l, HashNumber* hashOut) {
    883    return StableCellHasher<T>::maybeGetHash(l, hashOut);
    884  }
    885  static bool ensureHash(const Lookup& l, HashNumber* hashOut) {
    886    return StableCellHasher<T>::ensureHash(l, hashOut);
    887  }
    888  static HashNumber hash(const Lookup& l) {
    889    return StableCellHasher<T>::hash(l);
    890  }
    891  static bool match(const Key& k, const Lookup& l) {
    892    return StableCellHasher<T>::match(k.unbarrieredGet(), l);
    893  }
    894 };
    895 
    896 }  // namespace js
    897 
    898 namespace mozilla {
    899 
    900 template <typename T>
    901 struct FallibleHashMethods<js::StableCellHasher<T>> {
    902  template <typename Lookup>
    903  static bool maybeGetHash(Lookup&& l, HashNumber* hashOut) {
    904    return js::StableCellHasher<T>::maybeGetHash(std::forward<Lookup>(l),
    905                                                 hashOut);
    906  }
    907  template <typename Lookup>
    908  static bool ensureHash(Lookup&& l, HashNumber* hashOut) {
    909    return js::StableCellHasher<T>::ensureHash(std::forward<Lookup>(l),
    910                                               hashOut);
    911  }
    912 };
    913 
    914 }  // namespace mozilla
    915 
    916 namespace js {
    917 
    918 struct VirtualTraceable {
    919  virtual ~VirtualTraceable() = default;
    920  virtual void trace(JSTracer* trc, const char* name) = 0;
    921 };
    922 
    923 class StackRootedBase {
    924 public:
    925  StackRootedBase* previous() { return prev; }
    926 
    927 protected:
    928  StackRootedBase** stack;
    929  StackRootedBase* prev;
    930 
    931  template <typename T>
    932  auto* derived() {
    933    return static_cast<JS::Rooted<T>*>(this);
    934  }
    935 };
    936 
    937 class PersistentRootedBase
    938    : protected mozilla::LinkedListElement<PersistentRootedBase> {
    939 protected:
    940  friend class mozilla::LinkedList<PersistentRootedBase>;
    941  friend class mozilla::LinkedListElement<PersistentRootedBase>;
    942 
    943  template <typename T>
    944  auto* derived() {
    945    return static_cast<JS::PersistentRooted<T>*>(this);
    946  }
    947 };
    948 
    949 struct StackRootedTraceableBase : public StackRootedBase,
    950                                  public VirtualTraceable {};
    951 
    952 class PersistentRootedTraceableBase : public PersistentRootedBase,
    953                                      public VirtualTraceable {};
    954 
    955 template <typename Base, typename T>
    956 class TypedRootedGCThingBase : public Base {
    957 public:
    958  void trace(JSTracer* trc, const char* name);
    959 };
    960 
    961 template <typename Base, typename T>
    962 class TypedRootedTraceableBase : public Base {
    963 public:
    964  void trace(JSTracer* trc, const char* name) override {
    965    auto* self = this->template derived<T>();
    966    JS::GCPolicy<T>::trace(trc, self->address(), name);
    967  }
    968 };
    969 
    970 template <typename T>
    971 struct RootedTraceableTraits {
    972  using StackBase = TypedRootedTraceableBase<StackRootedTraceableBase, T>;
    973  using PersistentBase =
    974      TypedRootedTraceableBase<PersistentRootedTraceableBase, T>;
    975 };
    976 
    977 template <typename T>
    978 struct RootedGCThingTraits {
    979  using StackBase = TypedRootedGCThingBase<StackRootedBase, T>;
    980  using PersistentBase = TypedRootedGCThingBase<PersistentRootedBase, T>;
    981 };
    982 
    983 } /* namespace js */
    984 
    985 namespace JS {
    986 
    987 class JS_PUBLIC_API AutoGCRooter;
    988 
    989 enum class AutoGCRooterKind : uint8_t {
    990  WrapperVector, /* js::AutoWrapperVector */
    991  Wrapper,       /* js::AutoWrapperRooter */
    992  Custom,        /* js::CustomAutoRooter */
    993 
    994  Limit
    995 };
    996 
    997 using RootedListHeads = mozilla::EnumeratedArray<RootKind, js::StackRootedBase*,
    998                                                 size_t(RootKind::Limit)>;
    999 
   1000 using AutoRooterListHeads =
   1001    mozilla::EnumeratedArray<AutoGCRooterKind, AutoGCRooter*,
   1002                             size_t(AutoGCRooterKind::Limit)>;
   1003 
   1004 // Superclass of JSContext which can be used for rooting data in use by the
   1005 // current thread but that does not provide all the functions of a JSContext.
   1006 class RootingContext {
   1007  // Stack GC roots for Rooted GC heap pointers.
   1008  RootedListHeads stackRoots_;
   1009  template <typename T>
   1010  friend class Rooted;
   1011 
   1012  // Stack GC roots for AutoFooRooter classes.
   1013  AutoRooterListHeads autoGCRooters_;
   1014  friend class AutoGCRooter;
   1015 
   1016  // Gecko profiling metadata.
   1017  // This isn't really rooting related. It's only here because we want
   1018  // GetContextProfilingStackIfEnabled to be inlineable into non-JS code, and
   1019  // we didn't want to add another superclass of JSContext just for this.
   1020  js::GeckoProfilerThread geckoProfiler_;
   1021 
   1022 public:
   1023  explicit RootingContext(js::Nursery* nursery);
   1024 
   1025  void traceStackRoots(JSTracer* trc);
   1026 
   1027  /* Implemented in gc/RootMarking.cpp. */
   1028  void traceAllGCRooters(JSTracer* trc);
   1029  void traceWrapperGCRooters(JSTracer* trc);
   1030  static void traceGCRooterList(JSTracer* trc, AutoGCRooter* head);
   1031 
   1032  void checkNoGCRooters();
   1033 
   1034  js::GeckoProfilerThread& geckoProfiler() { return geckoProfiler_; }
   1035 
   1036  js::Nursery& nursery() const {
   1037    MOZ_ASSERT(nursery_);
   1038    return *nursery_;
   1039  }
   1040 
   1041 protected:
   1042  // The remaining members in this class should only be accessed through
   1043  // JSContext pointers. They are unrelated to rooting and are in place so
   1044  // that inlined API functions can directly access the data.
   1045 
   1046  /* The nursery. Null for non-main-thread contexts. */
   1047  js::Nursery* nursery_;
   1048 
   1049  /* The current zone. */
   1050  Zone* zone_;
   1051 
   1052  /* The current realm. */
   1053  Realm* realm_;
   1054 
   1055 public:
   1056  /* Limit pointer for checking native stack consumption. */
   1057  JS::NativeStackLimit nativeStackLimit[StackKindCount];
   1058 
   1059 #ifdef __wasi__
   1060  // For WASI we can't catch call-stack overflows with stack-pointer checks, so
   1061  // we count recursion depth with RAII based AutoCheckRecursionLimit.
   1062  uint32_t wasiRecursionDepth = 0u;
   1063 
   1064  static constexpr uint32_t wasiRecursionDepthLimit = 350u;
   1065 #endif  // __wasi__
   1066 
   1067  static const RootingContext* get(const JSContext* cx) {
   1068    return reinterpret_cast<const RootingContext*>(cx);
   1069  }
   1070 
   1071  static RootingContext* get(JSContext* cx) {
   1072    return reinterpret_cast<RootingContext*>(cx);
   1073  }
   1074 
   1075  friend JS::Realm* js::GetContextRealm(const JSContext* cx);
   1076  friend JS::Zone* js::GetContextZone(const JSContext* cx);
   1077 };
   1078 
   1079 class JS_PUBLIC_API AutoGCRooter {
   1080 public:
   1081  using Kind = AutoGCRooterKind;
   1082 
   1083  AutoGCRooter(JSContext* cx, Kind kind)
   1084      : AutoGCRooter(JS::RootingContext::get(cx), kind) {}
   1085  AutoGCRooter(RootingContext* cx, Kind kind)
   1086      : down(cx->autoGCRooters_[kind]),
   1087        stackTop(&cx->autoGCRooters_[kind]),
   1088        kind_(kind) {
   1089    MOZ_ASSERT(this != *stackTop);
   1090    *stackTop = this;
   1091  }
   1092 
   1093  ~AutoGCRooter() {
   1094    MOZ_ASSERT(this == *stackTop);
   1095    *stackTop = down;
   1096  }
   1097 
   1098  void trace(JSTracer* trc);
   1099 
   1100 private:
   1101  friend class RootingContext;
   1102 
   1103  AutoGCRooter* const down;
   1104  AutoGCRooter** const stackTop;
   1105 
   1106  /*
   1107   * Discriminates actual subclass of this being used. The meaning is
   1108   * indicated by the corresponding value in the Kind enum.
   1109   */
   1110  Kind kind_;
   1111 
   1112  /* No copy or assignment semantics. */
   1113  AutoGCRooter(AutoGCRooter& ida) = delete;
   1114  void operator=(AutoGCRooter& ida) = delete;
   1115 } JS_HAZ_ROOTED_BASE;
   1116 
   1117 /**
   1118 * Custom rooting behavior for internal and external clients.
   1119 *
   1120 * Deprecated. Where possible, use Rooted<> instead.
   1121 */
   1122 class MOZ_RAII JS_PUBLIC_API CustomAutoRooter : private AutoGCRooter {
   1123 public:
   1124  template <typename CX>
   1125  explicit CustomAutoRooter(const CX& cx)
   1126      : AutoGCRooter(cx, AutoGCRooter::Kind::Custom) {}
   1127 
   1128  friend void AutoGCRooter::trace(JSTracer* trc);
   1129 
   1130 protected:
   1131  virtual ~CustomAutoRooter() = default;
   1132 
   1133  /** Supplied by derived class to trace roots. */
   1134  virtual void trace(JSTracer* trc) = 0;
   1135 };
   1136 
   1137 namespace detail {
   1138 
   1139 template <typename T>
   1140 constexpr bool IsTraceable_v =
   1141    MapTypeToRootKind<T>::kind == JS::RootKind::Traceable;
   1142 
   1143 template <typename T>
   1144 using RootedTraits =
   1145    std::conditional_t<IsTraceable_v<T>, js::RootedTraceableTraits<T>,
   1146                       js::RootedGCThingTraits<T>>;
   1147 
   1148 } /* namespace detail */
   1149 
   1150 /**
   1151 * Local variable of type T whose value is always rooted. This is typically
   1152 * used for local variables, or for non-rooted values being passed to a
   1153 * function that requires a handle, e.g. Foo(Root<T>(cx, x)).
   1154 *
   1155 * If you want to add additional methods to Rooted for a specific
   1156 * specialization, define a RootedOperations<T> specialization containing them.
   1157 */
   1158 template <typename T>
   1159 class MOZ_RAII Rooted : public detail::RootedTraits<T>::StackBase,
   1160                        public js::RootedOperations<T, Rooted<T>> {
   1161  // Intentionally store a pointer into the stack.
   1162 #if !defined(__clang__) && defined(__GNUC__) && __GNUC__ >= 12
   1163 #  pragma GCC diagnostic push
   1164 #  pragma GCC diagnostic ignored "-Wdangling-pointer"
   1165 #endif
   1166  inline void registerWithRootLists(RootedListHeads& roots) {
   1167    this->stack = &roots[JS::MapTypeToRootKind<T>::kind];
   1168    this->prev = *this->stack;
   1169    *this->stack = this;
   1170  }
   1171 #if !defined(__clang__) && defined(__GNUC__) && __GNUC__ >= 12
   1172 #  pragma GCC diagnostic pop
   1173 #endif
   1174 
   1175  inline RootedListHeads& rootLists(RootingContext* cx) {
   1176    return cx->stackRoots_;
   1177  }
   1178  inline RootedListHeads& rootLists(JSContext* cx) {
   1179    return rootLists(RootingContext::get(cx));
   1180  }
   1181 
   1182 public:
   1183  using ElementType = T;
   1184 
   1185  // Construct an empty Rooted holding a safely initialized but empty T.
   1186  // Requires T to have a copy constructor in order to copy the safely
   1187  // initialized value.
   1188  //
   1189  // Note that for SFINAE to reject this method, the 2nd template parameter must
   1190  // depend on RootingContext somehow even though we really only care about T.
   1191  template <typename RootingContext,
   1192            typename = std::enable_if_t<std::is_copy_constructible_v<T>,
   1193                                        RootingContext>>
   1194  explicit Rooted(const RootingContext& cx)
   1195      : ptr(SafelyInitialized<T>::create()) {
   1196    registerWithRootLists(rootLists(cx));
   1197  }
   1198 
   1199  // Provide an initial value. Requires T to be constructible from the given
   1200  // argument.
   1201  template <typename RootingContext, typename S>
   1202  Rooted(const RootingContext& cx, S&& initial)
   1203      : ptr(std::forward<S>(initial)) {
   1204    MOZ_ASSERT(GCPolicy<T>::isValid(ptr));
   1205    registerWithRootLists(rootLists(cx));
   1206  }
   1207 
   1208  // (Traceables only) Construct the contained value from the given arguments.
   1209  // Constructs in-place, so T does not need to be copyable or movable.
   1210  //
   1211  // Note that a copyable Traceable passed only a RootingContext will
   1212  // choose the above SafelyInitialized<T> constructor, because otherwise
   1213  // identical functions with parameter packs are considered less specialized.
   1214  //
   1215  // The SFINAE type must again depend on an inferred template parameter.
   1216  template <
   1217      typename RootingContext, typename... CtorArgs,
   1218      typename = std::enable_if_t<detail::IsTraceable_v<T>, RootingContext>>
   1219  explicit Rooted(const RootingContext& cx, CtorArgs&&... args)
   1220      : ptr(std::forward<CtorArgs>(args)...) {
   1221    MOZ_ASSERT(GCPolicy<T>::isValid(ptr));
   1222    registerWithRootLists(rootLists(cx));
   1223  }
   1224 
   1225  ~Rooted() {
   1226    MOZ_ASSERT(*this->stack == this);
   1227    *this->stack = this->prev;
   1228  }
   1229 
   1230  /*
   1231   * This method is public for Rooted so that Codegen.py can use a Rooted
   1232   * interchangeably with a MutableHandleValue.
   1233   */
   1234  void set(const T& value) {
   1235    ptr = value;
   1236    MOZ_ASSERT(GCPolicy<T>::isValid(ptr));
   1237  }
   1238  void set(T&& value) {
   1239    ptr = std::move(value);
   1240    MOZ_ASSERT(GCPolicy<T>::isValid(ptr));
   1241  }
   1242 
   1243  DECLARE_POINTER_CONSTREF_OPS(T);
   1244  DECLARE_POINTER_ASSIGN_OPS(Rooted<T>, T);
   1245 
   1246  T& get() { return ptr; }
   1247  const T& get() const { return ptr; }
   1248 
   1249  T* address() { return &ptr; }
   1250  const T* address() const { return &ptr; }
   1251 
   1252  static constexpr size_t offsetOfPtr() { return offsetof(Rooted, ptr); }
   1253 
   1254 private:
   1255  T ptr;
   1256 
   1257  Rooted(const Rooted&) = delete;
   1258 } JS_HAZ_ROOTED;
   1259 
   1260 namespace detail {
   1261 
   1262 template <typename T>
   1263 struct DefineComparisonOps<Rooted<T>> : std::true_type {
   1264  static const T& get(const Rooted<T>& v) { return v.get(); }
   1265 };
   1266 
   1267 template <typename T, typename... Ts>
   1268 struct IndexOfType {};
   1269 
   1270 template <typename T, typename... Ts>
   1271 struct IndexOfType<T, T, Ts...> : public std::integral_constant<size_t, 0> {};
   1272 
   1273 template <typename T, typename U, typename... Ts>
   1274 struct IndexOfType<T, U, Ts...>
   1275    : public std::integral_constant<size_t, IndexOfType<T, Ts...>::value + 1> {
   1276 };
   1277 
   1278 template <typename T, typename... Ts>
   1279 constexpr size_t IndexOfTypeV = IndexOfType<T, Ts...>::value;
   1280 
   1281 }  // namespace detail
   1282 
   1283 template <typename... Fs>
   1284 class RootedTuple {
   1285  using Tuple = std::tuple<Fs...>;
   1286 
   1287  Rooted<Tuple> fields;
   1288 
   1289 #ifdef DEBUG
   1290  bool inUse[std::tuple_size_v<Tuple>] = {};
   1291 
   1292  bool* setFieldInUse(size_t index) {
   1293    MOZ_ASSERT(index < std::size(inUse));
   1294    bool& flag = inUse[index];
   1295    MOZ_ASSERT(!flag,
   1296               "Field of RootedTuple already in use by another RootedField");
   1297    flag = true;
   1298    return &flag;
   1299  }
   1300 #endif
   1301 
   1302  template <typename T, size_t N>
   1303  friend class RootedField;
   1304 
   1305 public:
   1306  template <typename RootingContext>
   1307  explicit RootedTuple(const RootingContext& cx) : fields(cx) {}
   1308  template <typename RootingContext>
   1309  explicit RootedTuple(const RootingContext& cx, const Fs&... fs)
   1310      : fields(cx, fs...) {}
   1311 };
   1312 
   1313 // Reference to a field in a RootedTuple. This is a drop-in replacement for an
   1314 // individual Rooted.
   1315 //
   1316 // This is very similar to a MutableHandle but with two differences: it has an
   1317 // assignment operator so doesn't require set() to be called and its address
   1318 // converts to a MutableHandle in the same way as a Rooted.
   1319 //
   1320 // The field is specified by the type parameter, optionally disambiguated by
   1321 // supplying the field index too.
   1322 //
   1323 // Used like this:
   1324 //
   1325 //   RootedTuple<JSObject*, JSString*> roots(cx);
   1326 //   RootedField<JSObject*> obj(roots);
   1327 //   RootedField<JSString*> str(roots);
   1328 //
   1329 // or:
   1330 //
   1331 //   RootedTuple<JString*, JSObject*, JSObject*> roots(cx);
   1332 //   RootedField<JString*, 0> str(roots);
   1333 //   RootedField<JSObject*, 1> obj1(roots);
   1334 //   RootedField<JSObject*, 2> obj2(roots);
   1335 template <typename T, size_t N /* = SIZE_MAX */>
   1336 class MOZ_RAII RootedField : public js::RootedOperations<T, RootedField<T, N>> {
   1337  T* ptr;
   1338  friend class Handle<T>;
   1339  friend class MutableHandle<T>;
   1340 
   1341 #ifdef DEBUG
   1342  bool* inUseFlag = nullptr;
   1343 #endif
   1344 
   1345 public:
   1346  using ElementType = T;
   1347 
   1348  template <typename... Fs>
   1349  explicit RootedField(RootedTuple<Fs...>& rootedTuple) {
   1350    using Tuple = std::tuple<Fs...>;
   1351    if constexpr (N == SIZE_MAX) {
   1352      ptr = &std::get<T>(rootedTuple.fields.get());
   1353    } else {
   1354      static_assert(N < std::tuple_size_v<Tuple>);
   1355      static_assert(std::is_same_v<T, std::tuple_element_t<N, Tuple>>);
   1356      ptr = &std::get<N>(rootedTuple.fields.get());
   1357    }
   1358 #ifdef DEBUG
   1359    size_t index = N;
   1360    if constexpr (N == SIZE_MAX) {
   1361      index = detail::IndexOfTypeV<T, Fs...>;
   1362    }
   1363    inUseFlag = rootedTuple.setFieldInUse(index);
   1364 #endif
   1365  }
   1366  template <typename... Fs, typename S>
   1367  explicit RootedField(RootedTuple<Fs...>& rootedTuple, S&& value)
   1368      : RootedField(rootedTuple) {
   1369    *ptr = std::forward<S>(value);
   1370  }
   1371 
   1372 #ifdef DEBUG
   1373  ~RootedField() {
   1374    MOZ_ASSERT(*inUseFlag);
   1375    *inUseFlag = false;
   1376  }
   1377 #endif
   1378 
   1379  T& get() { return *ptr; }
   1380  const T& get() const { return *ptr; }
   1381  void set(const T& value) {
   1382    *ptr = value;
   1383    MOZ_ASSERT(GCPolicy<T>::isValid(*ptr));
   1384  }
   1385  void set(T&& value) {
   1386    *ptr = std::move(value);
   1387    MOZ_ASSERT(GCPolicy<T>::isValid(*ptr));
   1388  }
   1389 
   1390  using WrapperT = RootedField<T, N>;
   1391  DECLARE_POINTER_CONSTREF_OPS(T);
   1392  DECLARE_POINTER_ASSIGN_OPS(WrapperT, T);
   1393  // DECLARE_NONPOINTER_ACCESSOR_METHODS(*ptr);
   1394  // DECLARE_NONPOINTER_MUTABLE_ACCESSOR_METHODS(*ptr);
   1395 
   1396 private:
   1397  RootedField() = delete;
   1398  RootedField(const RootedField& other) = delete;
   1399 };
   1400 
   1401 namespace detail {
   1402 template <size_t N, typename T>
   1403 struct DefineComparisonOps<JS::RootedField<T, N>> : std::true_type {
   1404  static const T& get(const JS::RootedField<T, N>& v) { return v.get(); }
   1405 };
   1406 }  // namespace detail
   1407 
   1408 } /* namespace JS */
   1409 
   1410 namespace js {
   1411 
   1412 /*
   1413 * Inlinable accessors for JSContext.
   1414 *
   1415 * - These must not be available on the more restricted superclasses of
   1416 *   JSContext, so we can't simply define them on RootingContext.
   1417 *
   1418 * - They're perfectly ordinary JSContext functionality, so ought to be
   1419 *   usable without resorting to jsfriendapi.h, and when JSContext is an
   1420 *   incomplete type.
   1421 */
   1422 inline JS::Realm* GetContextRealm(const JSContext* cx) {
   1423  return JS::RootingContext::get(cx)->realm_;
   1424 }
   1425 
   1426 inline JS::Compartment* GetContextCompartment(const JSContext* cx) {
   1427  if (JS::Realm* realm = GetContextRealm(cx)) {
   1428    return GetCompartmentForRealm(realm);
   1429  }
   1430  return nullptr;
   1431 }
   1432 
   1433 inline JS::Zone* GetContextZone(const JSContext* cx) {
   1434  return JS::RootingContext::get(cx)->zone_;
   1435 }
   1436 
   1437 inline ProfilingStack* GetContextProfilingStackIfEnabled(JSContext* cx) {
   1438  return JS::RootingContext::get(cx)
   1439      ->geckoProfiler()
   1440      .getProfilingStackIfEnabled();
   1441 }
   1442 
   1443 /**
   1444 * Augment the generic Rooted<T> interface when T = JSObject* with
   1445 * class-querying and downcasting operations.
   1446 *
   1447 * Given a Rooted<JSObject*> obj, one can view
   1448 *   Handle<StringObject*> h = obj.as<StringObject*>();
   1449 * as an optimization of
   1450 *   Rooted<StringObject*> rooted(cx, &obj->as<StringObject*>());
   1451 *   Handle<StringObject*> h = rooted;
   1452 */
   1453 template <typename Container>
   1454 class RootedOperations<JSObject*, Container>
   1455    : public MutableWrappedPtrOperations<JSObject*, Container> {
   1456 public:
   1457  template <class U>
   1458  JS::Handle<U*> as() const;
   1459 };
   1460 
   1461 /**
   1462 * Augment the generic Handle<T> interface when T = JSObject* with
   1463 * downcasting operations.
   1464 *
   1465 * Given a Handle<JSObject*> obj, one can view
   1466 *   Handle<StringObject*> h = obj.as<StringObject*>();
   1467 * as an optimization of
   1468 *   Rooted<StringObject*> rooted(cx, &obj->as<StringObject*>());
   1469 *   Handle<StringObject*> h = rooted;
   1470 */
   1471 template <typename Container>
   1472 class HandleOperations<JSObject*, Container>
   1473    : public WrappedPtrOperations<JSObject*, Container> {
   1474 public:
   1475  template <class U>
   1476  JS::Handle<U*> as() const;
   1477 };
   1478 
   1479 } /* namespace js */
   1480 
   1481 namespace JS {
   1482 
   1483 template <typename T>
   1484 template <typename S>
   1485 inline Handle<T>::Handle(
   1486    const Rooted<S>& root,
   1487    std::enable_if_t<std::is_convertible_v<S, T>, int> dummy) {
   1488  ptr = reinterpret_cast<const T*>(root.address());
   1489 }
   1490 
   1491 template <typename T>
   1492 template <typename S>
   1493 inline Handle<T>::Handle(
   1494    const PersistentRooted<S>& root,
   1495    std::enable_if_t<std::is_convertible_v<S, T>, int> dummy) {
   1496  ptr = reinterpret_cast<const T*>(root.address());
   1497 }
   1498 
   1499 template <typename T>
   1500 template <typename S>
   1501 inline Handle<T>::Handle(
   1502    MutableHandle<S>& root,
   1503    std::enable_if_t<std::is_convertible_v<S, T>, int> dummy) {
   1504  ptr = reinterpret_cast<const T*>(root.address());
   1505 }
   1506 
   1507 template <typename T>
   1508 template <size_t N, typename S>
   1509 inline Handle<T>::Handle(
   1510    const RootedField<S, N>& rootedField,
   1511    std::enable_if_t<std::is_convertible_v<S, T>, int> dummy) {
   1512  ptr = reinterpret_cast<const T*>(rootedField.ptr);
   1513 }
   1514 
   1515 template <typename T>
   1516 inline MutableHandle<T>::MutableHandle(Rooted<T>* root) {
   1517  static_assert(sizeof(MutableHandle<T>) == sizeof(T*),
   1518                "MutableHandle must be binary compatible with T*.");
   1519  ptr = root->address();
   1520 }
   1521 
   1522 template <typename T>
   1523 template <size_t N>
   1524 inline MutableHandle<T>::MutableHandle(RootedField<T, N>* rootedField) {
   1525  ptr = rootedField->ptr;
   1526 }
   1527 
   1528 template <typename T>
   1529 inline MutableHandle<T>::MutableHandle(PersistentRooted<T>* root) {
   1530  static_assert(sizeof(MutableHandle<T>) == sizeof(T*),
   1531                "MutableHandle must be binary compatible with T*.");
   1532  ptr = root->address();
   1533 }
   1534 
   1535 JS_PUBLIC_API void AddPersistentRoot(RootingContext* cx, RootKind kind,
   1536                                     js::PersistentRootedBase* root);
   1537 
   1538 JS_PUBLIC_API void AddPersistentRoot(JSRuntime* rt, RootKind kind,
   1539                                     js::PersistentRootedBase* root);
   1540 
   1541 /**
   1542 * A copyable, assignable global GC root type with arbitrary lifetime, an
   1543 * infallible constructor, and automatic unrooting on destruction.
   1544 *
   1545 * These roots can be used in heap-allocated data structures, so they are not
   1546 * associated with any particular JSContext or stack. They are registered with
   1547 * the JSRuntime itself, without locking. Initialization may take place on
   1548 * construction, or in two phases if the no-argument constructor is called
   1549 * followed by init().
   1550 *
   1551 * Note that you must not use an PersistentRooted in an object owned by a JS
   1552 * object:
   1553 *
   1554 * Whenever one object whose lifetime is decided by the GC refers to another
   1555 * such object, that edge must be traced only if the owning JS object is traced.
   1556 * This applies not only to JS objects (which obviously are managed by the GC)
   1557 * but also to C++ objects owned by JS objects.
   1558 *
   1559 * If you put a PersistentRooted in such a C++ object, that is almost certainly
   1560 * a leak. When a GC begins, the referent of the PersistentRooted is treated as
   1561 * live, unconditionally (because a PersistentRooted is a *root*), even if the
   1562 * JS object that owns it is unreachable. If there is any path from that
   1563 * referent back to the JS object, then the C++ object containing the
   1564 * PersistentRooted will not be destructed, and the whole blob of objects will
   1565 * not be freed, even if there are no references to them from the outside.
   1566 *
   1567 * In the context of Firefox, this is a severe restriction: almost everything in
   1568 * Firefox is owned by some JS object or another, so using PersistentRooted in
   1569 * such objects would introduce leaks. For these kinds of edges, Heap<T> or
   1570 * TenuredHeap<T> would be better types. It's up to the implementor of the type
   1571 * containing Heap<T> or TenuredHeap<T> members to make sure their referents get
   1572 * marked when the object itself is marked.
   1573 */
   1574 template <typename T>
   1575 class PersistentRooted : public detail::RootedTraits<T>::PersistentBase,
   1576                         public js::RootedOperations<T, PersistentRooted<T>> {
   1577  void registerWithRootLists(RootingContext* cx) {
   1578    MOZ_ASSERT(!initialized());
   1579    JS::RootKind kind = JS::MapTypeToRootKind<T>::kind;
   1580    AddPersistentRoot(cx, kind, this);
   1581  }
   1582 
   1583  void registerWithRootLists(JSRuntime* rt) {
   1584    MOZ_ASSERT(!initialized());
   1585    JS::RootKind kind = JS::MapTypeToRootKind<T>::kind;
   1586    AddPersistentRoot(rt, kind, this);
   1587  }
   1588 
   1589  // Used when JSContext type is incomplete and so it is not known to inherit
   1590  // from RootingContext.
   1591  void registerWithRootLists(JSContext* cx) {
   1592    registerWithRootLists(RootingContext::get(cx));
   1593  }
   1594 
   1595 public:
   1596  using ElementType = T;
   1597 
   1598  PersistentRooted() : ptr(SafelyInitialized<T>::create()) {}
   1599 
   1600  template <
   1601      typename RootHolder,
   1602      typename = std::enable_if_t<std::is_copy_constructible_v<T>, RootHolder>>
   1603  explicit PersistentRooted(const RootHolder& cx)
   1604      : ptr(SafelyInitialized<T>::create()) {
   1605    registerWithRootLists(cx);
   1606  }
   1607 
   1608  template <
   1609      typename RootHolder, typename U,
   1610      typename = std::enable_if_t<std::is_constructible_v<T, U>, RootHolder>>
   1611  PersistentRooted(const RootHolder& cx, U&& initial)
   1612      : ptr(std::forward<U>(initial)) {
   1613    registerWithRootLists(cx);
   1614  }
   1615 
   1616  template <typename RootHolder, typename... CtorArgs,
   1617            typename = std::enable_if_t<detail::IsTraceable_v<T>, RootHolder>>
   1618  explicit PersistentRooted(const RootHolder& cx, CtorArgs... args)
   1619      : ptr(std::forward<CtorArgs>(args)...) {
   1620    registerWithRootLists(cx);
   1621  }
   1622 
   1623  PersistentRooted(const PersistentRooted& rhs) : ptr(rhs.ptr) {
   1624    /*
   1625     * Copy construction takes advantage of the fact that the original
   1626     * is already inserted, and simply adds itself to whatever list the
   1627     * original was on - no JSRuntime pointer needed.
   1628     *
   1629     * This requires mutating rhs's links, but those should be 'mutable'
   1630     * anyway. C++ doesn't let us declare mutable base classes.
   1631     */
   1632    const_cast<PersistentRooted&>(rhs).setNext(this);
   1633  }
   1634 
   1635  bool initialized() const { return this->isInList(); }
   1636 
   1637  void init(RootingContext* cx) { init(cx, SafelyInitialized<T>::create()); }
   1638  void init(JSContext* cx) { init(RootingContext::get(cx)); }
   1639 
   1640  template <typename U>
   1641  void init(RootingContext* cx, U&& initial) {
   1642    ptr = std::forward<U>(initial);
   1643    registerWithRootLists(cx);
   1644  }
   1645  template <typename U>
   1646  void init(JSContext* cx, U&& initial) {
   1647    ptr = std::forward<U>(initial);
   1648    registerWithRootLists(RootingContext::get(cx));
   1649  }
   1650 
   1651  void reset() {
   1652    if (initialized()) {
   1653      set(SafelyInitialized<T>::create());
   1654      this->remove();
   1655    }
   1656  }
   1657 
   1658  DECLARE_POINTER_CONSTREF_OPS(T);
   1659  DECLARE_POINTER_ASSIGN_OPS(PersistentRooted<T>, T);
   1660 
   1661  T& get() { return ptr; }
   1662  const T& get() const { return ptr; }
   1663 
   1664  T* address() {
   1665    MOZ_ASSERT(initialized());
   1666    return &ptr;
   1667  }
   1668  const T* address() const { return &ptr; }
   1669 
   1670  template <typename U>
   1671  void set(U&& value) {
   1672    MOZ_ASSERT(initialized());
   1673    ptr = std::forward<U>(value);
   1674  }
   1675 
   1676 private:
   1677  T ptr;
   1678 } JS_HAZ_ROOTED;
   1679 
   1680 namespace detail {
   1681 
   1682 template <typename T>
   1683 struct DefineComparisonOps<PersistentRooted<T>> : std::true_type {
   1684  static const T& get(const PersistentRooted<T>& v) { return v.get(); }
   1685 };
   1686 
   1687 }  // namespace detail
   1688 
   1689 } /* namespace JS */
   1690 
   1691 namespace js {
   1692 
   1693 template <typename T, typename D, typename Container>
   1694 class WrappedPtrOperations<UniquePtr<T, D>, Container> {
   1695  const UniquePtr<T, D>& uniquePtr() const {
   1696    return static_cast<const Container*>(this)->get();
   1697  }
   1698 
   1699 public:
   1700  explicit operator bool() const { return !!uniquePtr(); }
   1701  T* get() const { return uniquePtr().get(); }
   1702  T* operator->() const { return get(); }
   1703  T& operator*() const { return *uniquePtr(); }
   1704 };
   1705 
   1706 template <typename T, typename D, typename Container>
   1707 class MutableWrappedPtrOperations<UniquePtr<T, D>, Container>
   1708    : public WrappedPtrOperations<UniquePtr<T, D>, Container> {
   1709  UniquePtr<T, D>& uniquePtr() { return static_cast<Container*>(this)->get(); }
   1710 
   1711 public:
   1712  [[nodiscard]] typename UniquePtr<T, D>::pointer release() {
   1713    return uniquePtr().release();
   1714  }
   1715  void reset(T* ptr = T()) { uniquePtr().reset(ptr); }
   1716 };
   1717 
   1718 template <typename T, typename Container>
   1719 class WrappedPtrOperations<mozilla::Maybe<T>, Container> {
   1720  const mozilla::Maybe<T>& maybe() const {
   1721    return static_cast<const Container*>(this)->get();
   1722  }
   1723 
   1724 public:
   1725  // This only supports a subset of Maybe's interface.
   1726  bool isSome() const { return maybe().isSome(); }
   1727  bool isNothing() const { return maybe().isNothing(); }
   1728  const T value() const { return maybe().value(); }
   1729  const T* operator->() const { return maybe().ptr(); }
   1730  const T& operator*() const { return maybe().ref(); }
   1731 };
   1732 
   1733 template <typename T, typename Container>
   1734 class MutableWrappedPtrOperations<mozilla::Maybe<T>, Container>
   1735    : public WrappedPtrOperations<mozilla::Maybe<T>, Container> {
   1736  mozilla::Maybe<T>& maybe() { return static_cast<Container*>(this)->get(); }
   1737 
   1738 public:
   1739  // This only supports a subset of Maybe's interface.
   1740  T* operator->() { return maybe().ptr(); }
   1741  T& operator*() { return maybe().ref(); }
   1742  void reset() { return maybe().reset(); }
   1743 };
   1744 
   1745 namespace gc {
   1746 
   1747 template <typename T, typename TraceCallbacks>
   1748 void CallTraceCallbackOnNonHeap(T* v, const TraceCallbacks& aCallbacks,
   1749                                const char* aName, void* aClosure) {
   1750  static_assert(sizeof(T) == sizeof(JS::Heap<T>),
   1751                "T and Heap<T> must be compatible.");
   1752  MOZ_ASSERT(v);
   1753  mozilla::DebugOnly<Cell*> cell = BarrierMethods<T>::asGCThingOrNull(*v);
   1754  MOZ_ASSERT(cell);
   1755  MOZ_ASSERT(!IsInsideNursery(cell));
   1756  JS::Heap<T>* asHeapT = reinterpret_cast<JS::Heap<T>*>(v);
   1757  aCallbacks.Trace(asHeapT, aName, aClosure);
   1758 }
   1759 
   1760 } /* namespace gc */
   1761 
   1762 template <typename Wrapper, typename T1, typename T2>
   1763 class WrappedPtrOperations<std::pair<T1, T2>, Wrapper> {
   1764  const std::pair<T1, T2>& pair() const {
   1765    return static_cast<const Wrapper*>(this)->get();
   1766  }
   1767 
   1768 public:
   1769  const T1& first() const { return pair().first; }
   1770  const T2& second() const { return pair().second; }
   1771 };
   1772 
   1773 template <typename Wrapper, typename T1, typename T2>
   1774 class MutableWrappedPtrOperations<std::pair<T1, T2>, Wrapper>
   1775    : public WrappedPtrOperations<std::pair<T1, T2>, Wrapper> {
   1776  std::pair<T1, T2>& pair() { return static_cast<Wrapper*>(this)->get(); }
   1777 
   1778 public:
   1779  T1& first() { return pair().first; }
   1780  T2& second() { return pair().second; }
   1781 };
   1782 
   1783 } /* namespace js */
   1784 
   1785 #endif /* js_RootingAPI_h */