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 */