js/public/RootingAPI.h

Fri, 16 Jan 2015 18:13:44 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Fri, 16 Jan 2015 18:13:44 +0100
branch
TOR_BUG_9701
changeset 14
925c144e1f1f
permissions
-rw-r--r--

Integrate suggestion from review to improve consistency with existing code.

michael@0 1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
michael@0 2 * vim: set ts=8 sts=4 et sw=4 tw=99:
michael@0 3 * This Source Code Form is subject to the terms of the Mozilla Public
michael@0 4 * License, v. 2.0. If a copy of the MPL was not distributed with this
michael@0 5 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
michael@0 6
michael@0 7 #ifndef js_RootingAPI_h
michael@0 8 #define js_RootingAPI_h
michael@0 9
michael@0 10 #include "mozilla/Attributes.h"
michael@0 11 #include "mozilla/GuardObjects.h"
michael@0 12 #include "mozilla/LinkedList.h"
michael@0 13 #include "mozilla/NullPtr.h"
michael@0 14 #include "mozilla/TypeTraits.h"
michael@0 15
michael@0 16 #include "jspubtd.h"
michael@0 17
michael@0 18 #include "js/TypeDecls.h"
michael@0 19 #include "js/Utility.h"
michael@0 20
michael@0 21 /*
michael@0 22 * Moving GC Stack Rooting
michael@0 23 *
michael@0 24 * A moving GC may change the physical location of GC allocated things, even
michael@0 25 * when they are rooted, updating all pointers to the thing to refer to its new
michael@0 26 * location. The GC must therefore know about all live pointers to a thing,
michael@0 27 * not just one of them, in order to behave correctly.
michael@0 28 *
michael@0 29 * The |Rooted| and |Handle| classes below are used to root stack locations
michael@0 30 * whose value may be held live across a call that can trigger GC. For a
michael@0 31 * code fragment such as:
michael@0 32 *
michael@0 33 * JSObject *obj = NewObject(cx);
michael@0 34 * DoSomething(cx);
michael@0 35 * ... = obj->lastProperty();
michael@0 36 *
michael@0 37 * If |DoSomething()| can trigger a GC, the stack location of |obj| must be
michael@0 38 * rooted to ensure that the GC does not move the JSObject referred to by
michael@0 39 * |obj| without updating |obj|'s location itself. This rooting must happen
michael@0 40 * regardless of whether there are other roots which ensure that the object
michael@0 41 * itself will not be collected.
michael@0 42 *
michael@0 43 * If |DoSomething()| cannot trigger a GC, and the same holds for all other
michael@0 44 * calls made between |obj|'s definitions and its last uses, then no rooting
michael@0 45 * is required.
michael@0 46 *
michael@0 47 * SpiderMonkey can trigger a GC at almost any time and in ways that are not
michael@0 48 * always clear. For example, the following innocuous-looking actions can
michael@0 49 * cause a GC: allocation of any new GC thing; JSObject::hasProperty;
michael@0 50 * JS_ReportError and friends; and ToNumber, among many others. The following
michael@0 51 * dangerous-looking actions cannot trigger a GC: js_malloc, cx->malloc_,
michael@0 52 * rt->malloc_, and friends and JS_ReportOutOfMemory.
michael@0 53 *
michael@0 54 * The following family of three classes will exactly root a stack location.
michael@0 55 * Incorrect usage of these classes will result in a compile error in almost
michael@0 56 * all cases. Therefore, it is very hard to be incorrectly rooted if you use
michael@0 57 * these classes exclusively. These classes are all templated on the type T of
michael@0 58 * the value being rooted.
michael@0 59 *
michael@0 60 * - Rooted<T> declares a variable of type T, whose value is always rooted.
michael@0 61 * Rooted<T> may be automatically coerced to a Handle<T>, below. Rooted<T>
michael@0 62 * should be used whenever a local variable's value may be held live across a
michael@0 63 * call which can trigger a GC.
michael@0 64 *
michael@0 65 * - Handle<T> is a const reference to a Rooted<T>. Functions which take GC
michael@0 66 * things or values as arguments and need to root those arguments should
michael@0 67 * generally use handles for those arguments and avoid any explicit rooting.
michael@0 68 * This has two benefits. First, when several such functions call each other
michael@0 69 * then redundant rooting of multiple copies of the GC thing can be avoided.
michael@0 70 * Second, if the caller does not pass a rooted value a compile error will be
michael@0 71 * generated, which is quicker and easier to fix than when relying on a
michael@0 72 * separate rooting analysis.
michael@0 73 *
michael@0 74 * - MutableHandle<T> is a non-const reference to Rooted<T>. It is used in the
michael@0 75 * same way as Handle<T> and includes a |set(const T &v)| method to allow
michael@0 76 * updating the value of the referenced Rooted<T>. A MutableHandle<T> can be
michael@0 77 * created from a Rooted<T> by using |Rooted<T>::operator&()|.
michael@0 78 *
michael@0 79 * In some cases the small performance overhead of exact rooting (measured to
michael@0 80 * be a few nanoseconds on desktop) is too much. In these cases, try the
michael@0 81 * following:
michael@0 82 *
michael@0 83 * - Move all Rooted<T> above inner loops: this allows you to re-use the root
michael@0 84 * on each iteration of the loop.
michael@0 85 *
michael@0 86 * - Pass Handle<T> through your hot call stack to avoid re-rooting costs at
michael@0 87 * every invocation.
michael@0 88 *
michael@0 89 * The following diagram explains the list of supported, implicit type
michael@0 90 * conversions between classes of this family:
michael@0 91 *
michael@0 92 * Rooted<T> ----> Handle<T>
michael@0 93 * | ^
michael@0 94 * | |
michael@0 95 * | |
michael@0 96 * +---> MutableHandle<T>
michael@0 97 * (via &)
michael@0 98 *
michael@0 99 * All of these types have an implicit conversion to raw pointers.
michael@0 100 */
michael@0 101
michael@0 102 namespace js {
michael@0 103
michael@0 104 class ScriptSourceObject;
michael@0 105
michael@0 106 template <typename T>
michael@0 107 struct GCMethods {};
michael@0 108
michael@0 109 template <typename T>
michael@0 110 class RootedBase {};
michael@0 111
michael@0 112 template <typename T>
michael@0 113 class HandleBase {};
michael@0 114
michael@0 115 template <typename T>
michael@0 116 class MutableHandleBase {};
michael@0 117
michael@0 118 template <typename T>
michael@0 119 class HeapBase {};
michael@0 120
michael@0 121 /*
michael@0 122 * js::NullPtr acts like a nullptr pointer in contexts that require a Handle.
michael@0 123 *
michael@0 124 * Handle provides an implicit constructor for js::NullPtr so that, given:
michael@0 125 * foo(Handle<JSObject*> h);
michael@0 126 * callers can simply write:
michael@0 127 * foo(js::NullPtr());
michael@0 128 * which avoids creating a Rooted<JSObject*> just to pass nullptr.
michael@0 129 *
michael@0 130 * This is the SpiderMonkey internal variant. js::NullPtr should be used in
michael@0 131 * preference to JS::NullPtr to avoid the GOT access required for JS_PUBLIC_API
michael@0 132 * symbols.
michael@0 133 */
michael@0 134 struct NullPtr
michael@0 135 {
michael@0 136 static void * const constNullValue;
michael@0 137 };
michael@0 138
michael@0 139 namespace gc {
michael@0 140 struct Cell;
michael@0 141 template<typename T>
michael@0 142 struct PersistentRootedMarker;
michael@0 143 } /* namespace gc */
michael@0 144
michael@0 145 } /* namespace js */
michael@0 146
michael@0 147 namespace JS {
michael@0 148
michael@0 149 template <typename T> class Rooted;
michael@0 150 template <typename T> class PersistentRooted;
michael@0 151
michael@0 152 /* This is exposing internal state of the GC for inlining purposes. */
michael@0 153 JS_FRIEND_API(bool) isGCEnabled();
michael@0 154
michael@0 155 /*
michael@0 156 * JS::NullPtr acts like a nullptr pointer in contexts that require a Handle.
michael@0 157 *
michael@0 158 * Handle provides an implicit constructor for JS::NullPtr so that, given:
michael@0 159 * foo(Handle<JSObject*> h);
michael@0 160 * callers can simply write:
michael@0 161 * foo(JS::NullPtr());
michael@0 162 * which avoids creating a Rooted<JSObject*> just to pass nullptr.
michael@0 163 */
michael@0 164 struct JS_PUBLIC_API(NullPtr)
michael@0 165 {
michael@0 166 static void * const constNullValue;
michael@0 167 };
michael@0 168
michael@0 169 /*
michael@0 170 * The Heap<T> class is a heap-stored reference to a JS GC thing. All members of
michael@0 171 * heap classes that refer to GC things should use Heap<T> (or possibly
michael@0 172 * TenuredHeap<T>, described below).
michael@0 173 *
michael@0 174 * Heap<T> is an abstraction that hides some of the complexity required to
michael@0 175 * maintain GC invariants for the contained reference. It uses operator
michael@0 176 * overloading to provide a normal pointer interface, but notifies the GC every
michael@0 177 * time the value it contains is updated. This is necessary for generational GC,
michael@0 178 * which keeps track of all pointers into the nursery.
michael@0 179 *
michael@0 180 * Heap<T> instances must be traced when their containing object is traced to
michael@0 181 * keep the pointed-to GC thing alive.
michael@0 182 *
michael@0 183 * Heap<T> objects should only be used on the heap. GC references stored on the
michael@0 184 * C/C++ stack must use Rooted/Handle/MutableHandle instead.
michael@0 185 *
michael@0 186 * Type T must be one of: JS::Value, jsid, JSObject*, JSString*, JSScript*
michael@0 187 */
michael@0 188 template <typename T>
michael@0 189 class Heap : public js::HeapBase<T>
michael@0 190 {
michael@0 191 public:
michael@0 192 Heap() {
michael@0 193 static_assert(sizeof(T) == sizeof(Heap<T>),
michael@0 194 "Heap<T> must be binary compatible with T.");
michael@0 195 init(js::GCMethods<T>::initial());
michael@0 196 }
michael@0 197 explicit Heap(T p) { init(p); }
michael@0 198
michael@0 199 /*
michael@0 200 * For Heap, move semantics are equivalent to copy semantics. In C++, a
michael@0 201 * copy constructor taking const-ref is the way to get a single function
michael@0 202 * that will be used for both lvalue and rvalue copies, so we can simply
michael@0 203 * omit the rvalue variant.
michael@0 204 */
michael@0 205 explicit Heap(const Heap<T> &p) { init(p.ptr); }
michael@0 206
michael@0 207 ~Heap() {
michael@0 208 if (js::GCMethods<T>::needsPostBarrier(ptr))
michael@0 209 relocate();
michael@0 210 }
michael@0 211
michael@0 212 bool operator==(const Heap<T> &other) { return ptr == other.ptr; }
michael@0 213 bool operator!=(const Heap<T> &other) { return ptr != other.ptr; }
michael@0 214
michael@0 215 bool operator==(const T &other) const { return ptr == other; }
michael@0 216 bool operator!=(const T &other) const { return ptr != other; }
michael@0 217
michael@0 218 operator T() const { return ptr; }
michael@0 219 T operator->() const { return ptr; }
michael@0 220 const T *address() const { return &ptr; }
michael@0 221 const T &get() const { return ptr; }
michael@0 222
michael@0 223 T *unsafeGet() { return &ptr; }
michael@0 224
michael@0 225 Heap<T> &operator=(T p) {
michael@0 226 set(p);
michael@0 227 return *this;
michael@0 228 }
michael@0 229
michael@0 230 Heap<T> &operator=(const Heap<T>& other) {
michael@0 231 set(other.get());
michael@0 232 return *this;
michael@0 233 }
michael@0 234
michael@0 235 void set(T newPtr) {
michael@0 236 MOZ_ASSERT(!js::GCMethods<T>::poisoned(newPtr));
michael@0 237 if (js::GCMethods<T>::needsPostBarrier(newPtr)) {
michael@0 238 ptr = newPtr;
michael@0 239 post();
michael@0 240 } else if (js::GCMethods<T>::needsPostBarrier(ptr)) {
michael@0 241 relocate(); /* Called before overwriting ptr. */
michael@0 242 ptr = newPtr;
michael@0 243 } else {
michael@0 244 ptr = newPtr;
michael@0 245 }
michael@0 246 }
michael@0 247
michael@0 248 /*
michael@0 249 * Set the pointer to a value which will cause a crash if it is
michael@0 250 * dereferenced.
michael@0 251 */
michael@0 252 void setToCrashOnTouch() {
michael@0 253 ptr = reinterpret_cast<T>(crashOnTouchPointer);
michael@0 254 }
michael@0 255
michael@0 256 bool isSetToCrashOnTouch() {
michael@0 257 return ptr == crashOnTouchPointer;
michael@0 258 }
michael@0 259
michael@0 260 private:
michael@0 261 void init(T newPtr) {
michael@0 262 MOZ_ASSERT(!js::GCMethods<T>::poisoned(newPtr));
michael@0 263 ptr = newPtr;
michael@0 264 if (js::GCMethods<T>::needsPostBarrier(ptr))
michael@0 265 post();
michael@0 266 }
michael@0 267
michael@0 268 void post() {
michael@0 269 #ifdef JSGC_GENERATIONAL
michael@0 270 MOZ_ASSERT(js::GCMethods<T>::needsPostBarrier(ptr));
michael@0 271 js::GCMethods<T>::postBarrier(&ptr);
michael@0 272 #endif
michael@0 273 }
michael@0 274
michael@0 275 void relocate() {
michael@0 276 #ifdef JSGC_GENERATIONAL
michael@0 277 js::GCMethods<T>::relocate(&ptr);
michael@0 278 #endif
michael@0 279 }
michael@0 280
michael@0 281 enum {
michael@0 282 crashOnTouchPointer = 1
michael@0 283 };
michael@0 284
michael@0 285 T ptr;
michael@0 286 };
michael@0 287
michael@0 288 #ifdef JS_DEBUG
michael@0 289 /*
michael@0 290 * For generational GC, assert that an object is in the tenured generation as
michael@0 291 * opposed to being in the nursery.
michael@0 292 */
michael@0 293 extern JS_FRIEND_API(void)
michael@0 294 AssertGCThingMustBeTenured(JSObject* obj);
michael@0 295 #else
michael@0 296 inline void
michael@0 297 AssertGCThingMustBeTenured(JSObject *obj) {}
michael@0 298 #endif
michael@0 299
michael@0 300 /*
michael@0 301 * The TenuredHeap<T> class is similar to the Heap<T> class above in that it
michael@0 302 * encapsulates the GC concerns of an on-heap reference to a JS object. However,
michael@0 303 * it has two important differences:
michael@0 304 *
michael@0 305 * 1) Pointers which are statically known to only reference "tenured" objects
michael@0 306 * can avoid the extra overhead of SpiderMonkey's write barriers.
michael@0 307 *
michael@0 308 * 2) Objects in the "tenured" heap have stronger alignment restrictions than
michael@0 309 * those in the "nursery", so it is possible to store flags in the lower
michael@0 310 * bits of pointers known to be tenured. TenuredHeap wraps a normal tagged
michael@0 311 * pointer with a nice API for accessing the flag bits and adds various
michael@0 312 * assertions to ensure that it is not mis-used.
michael@0 313 *
michael@0 314 * GC things are said to be "tenured" when they are located in the long-lived
michael@0 315 * heap: e.g. they have gained tenure as an object by surviving past at least
michael@0 316 * one GC. For performance, SpiderMonkey allocates some things which are known
michael@0 317 * to normally be long lived directly into the tenured generation; for example,
michael@0 318 * global objects. Additionally, SpiderMonkey does not visit individual objects
michael@0 319 * when deleting non-tenured objects, so object with finalizers are also always
michael@0 320 * tenured; for instance, this includes most DOM objects.
michael@0 321 *
michael@0 322 * The considerations to keep in mind when using a TenuredHeap<T> vs a normal
michael@0 323 * Heap<T> are:
michael@0 324 *
michael@0 325 * - It is invalid for a TenuredHeap<T> to refer to a non-tenured thing.
michael@0 326 * - It is however valid for a Heap<T> to refer to a tenured thing.
michael@0 327 * - It is not possible to store flag bits in a Heap<T>.
michael@0 328 */
michael@0 329 template <typename T>
michael@0 330 class TenuredHeap : public js::HeapBase<T>
michael@0 331 {
michael@0 332 public:
michael@0 333 TenuredHeap() : bits(0) {
michael@0 334 static_assert(sizeof(T) == sizeof(TenuredHeap<T>),
michael@0 335 "TenuredHeap<T> must be binary compatible with T.");
michael@0 336 }
michael@0 337 explicit TenuredHeap(T p) : bits(0) { setPtr(p); }
michael@0 338 explicit TenuredHeap(const TenuredHeap<T> &p) : bits(0) { setPtr(p.getPtr()); }
michael@0 339
michael@0 340 bool operator==(const TenuredHeap<T> &other) { return bits == other.bits; }
michael@0 341 bool operator!=(const TenuredHeap<T> &other) { return bits != other.bits; }
michael@0 342
michael@0 343 void setPtr(T newPtr) {
michael@0 344 MOZ_ASSERT((reinterpret_cast<uintptr_t>(newPtr) & flagsMask) == 0);
michael@0 345 MOZ_ASSERT(!js::GCMethods<T>::poisoned(newPtr));
michael@0 346 if (newPtr)
michael@0 347 AssertGCThingMustBeTenured(newPtr);
michael@0 348 bits = (bits & flagsMask) | reinterpret_cast<uintptr_t>(newPtr);
michael@0 349 }
michael@0 350
michael@0 351 void setFlags(uintptr_t flagsToSet) {
michael@0 352 MOZ_ASSERT((flagsToSet & ~flagsMask) == 0);
michael@0 353 bits |= flagsToSet;
michael@0 354 }
michael@0 355
michael@0 356 void unsetFlags(uintptr_t flagsToUnset) {
michael@0 357 MOZ_ASSERT((flagsToUnset & ~flagsMask) == 0);
michael@0 358 bits &= ~flagsToUnset;
michael@0 359 }
michael@0 360
michael@0 361 bool hasFlag(uintptr_t flag) const {
michael@0 362 MOZ_ASSERT((flag & ~flagsMask) == 0);
michael@0 363 return (bits & flag) != 0;
michael@0 364 }
michael@0 365
michael@0 366 T getPtr() const { return reinterpret_cast<T>(bits & ~flagsMask); }
michael@0 367 uintptr_t getFlags() const { return bits & flagsMask; }
michael@0 368
michael@0 369 operator T() const { return getPtr(); }
michael@0 370 T operator->() const { return getPtr(); }
michael@0 371
michael@0 372 TenuredHeap<T> &operator=(T p) {
michael@0 373 setPtr(p);
michael@0 374 return *this;
michael@0 375 }
michael@0 376
michael@0 377 TenuredHeap<T> &operator=(const TenuredHeap<T>& other) {
michael@0 378 bits = other.bits;
michael@0 379 return *this;
michael@0 380 }
michael@0 381
michael@0 382 private:
michael@0 383 enum {
michael@0 384 maskBits = 3,
michael@0 385 flagsMask = (1 << maskBits) - 1,
michael@0 386 };
michael@0 387
michael@0 388 uintptr_t bits;
michael@0 389 };
michael@0 390
michael@0 391 /*
michael@0 392 * Reference to a T that has been rooted elsewhere. This is most useful
michael@0 393 * as a parameter type, which guarantees that the T lvalue is properly
michael@0 394 * rooted. See "Move GC Stack Rooting" above.
michael@0 395 *
michael@0 396 * If you want to add additional methods to Handle for a specific
michael@0 397 * specialization, define a HandleBase<T> specialization containing them.
michael@0 398 */
michael@0 399 template <typename T>
michael@0 400 class MOZ_NONHEAP_CLASS Handle : public js::HandleBase<T>
michael@0 401 {
michael@0 402 friend class JS::MutableHandle<T>;
michael@0 403
michael@0 404 public:
michael@0 405 /* Creates a handle from a handle of a type convertible to T. */
michael@0 406 template <typename S>
michael@0 407 Handle(Handle<S> handle,
michael@0 408 typename mozilla::EnableIf<mozilla::IsConvertible<S, T>::value, int>::Type dummy = 0)
michael@0 409 {
michael@0 410 static_assert(sizeof(Handle<T>) == sizeof(T *),
michael@0 411 "Handle must be binary compatible with T*.");
michael@0 412 ptr = reinterpret_cast<const T *>(handle.address());
michael@0 413 }
michael@0 414
michael@0 415 /* Create a handle for a nullptr pointer. */
michael@0 416 Handle(js::NullPtr) {
michael@0 417 static_assert(mozilla::IsPointer<T>::value,
michael@0 418 "js::NullPtr overload not valid for non-pointer types");
michael@0 419 ptr = reinterpret_cast<const T *>(&js::NullPtr::constNullValue);
michael@0 420 }
michael@0 421
michael@0 422 /* Create a handle for a nullptr pointer. */
michael@0 423 Handle(JS::NullPtr) {
michael@0 424 static_assert(mozilla::IsPointer<T>::value,
michael@0 425 "JS::NullPtr overload not valid for non-pointer types");
michael@0 426 ptr = reinterpret_cast<const T *>(&JS::NullPtr::constNullValue);
michael@0 427 }
michael@0 428
michael@0 429 Handle(MutableHandle<T> handle) {
michael@0 430 ptr = handle.address();
michael@0 431 }
michael@0 432
michael@0 433 /*
michael@0 434 * Take care when calling this method!
michael@0 435 *
michael@0 436 * This creates a Handle from the raw location of a T.
michael@0 437 *
michael@0 438 * It should be called only if the following conditions hold:
michael@0 439 *
michael@0 440 * 1) the location of the T is guaranteed to be marked (for some reason
michael@0 441 * other than being a Rooted), e.g., if it is guaranteed to be reachable
michael@0 442 * from an implicit root.
michael@0 443 *
michael@0 444 * 2) the contents of the location are immutable, or at least cannot change
michael@0 445 * for the lifetime of the handle, as its users may not expect its value
michael@0 446 * to change underneath them.
michael@0 447 */
michael@0 448 static MOZ_CONSTEXPR Handle fromMarkedLocation(const T *p) {
michael@0 449 return Handle(p, DeliberatelyChoosingThisOverload,
michael@0 450 ImUsingThisOnlyInFromFromMarkedLocation);
michael@0 451 }
michael@0 452
michael@0 453 /*
michael@0 454 * Construct a handle from an explicitly rooted location. This is the
michael@0 455 * normal way to create a handle, and normally happens implicitly.
michael@0 456 */
michael@0 457 template <typename S>
michael@0 458 inline
michael@0 459 Handle(const Rooted<S> &root,
michael@0 460 typename mozilla::EnableIf<mozilla::IsConvertible<S, T>::value, int>::Type dummy = 0);
michael@0 461
michael@0 462 template <typename S>
michael@0 463 inline
michael@0 464 Handle(const PersistentRooted<S> &root,
michael@0 465 typename mozilla::EnableIf<mozilla::IsConvertible<S, T>::value, int>::Type dummy = 0);
michael@0 466
michael@0 467 /* Construct a read only handle from a mutable handle. */
michael@0 468 template <typename S>
michael@0 469 inline
michael@0 470 Handle(MutableHandle<S> &root,
michael@0 471 typename mozilla::EnableIf<mozilla::IsConvertible<S, T>::value, int>::Type dummy = 0);
michael@0 472
michael@0 473 const T *address() const { return ptr; }
michael@0 474 const T& get() const { return *ptr; }
michael@0 475
michael@0 476 /*
michael@0 477 * Return a reference so passing a Handle<T> to something that
michael@0 478 * takes a |const T&| is not a GC hazard.
michael@0 479 */
michael@0 480 operator const T&() const { return get(); }
michael@0 481 T operator->() const { return get(); }
michael@0 482
michael@0 483 bool operator!=(const T &other) const { return *ptr != other; }
michael@0 484 bool operator==(const T &other) const { return *ptr == other; }
michael@0 485
michael@0 486 /* Change this handle to point to the same rooted location RHS does. */
michael@0 487 void repoint(const Handle &rhs) { ptr = rhs.address(); }
michael@0 488
michael@0 489 private:
michael@0 490 Handle() {}
michael@0 491
michael@0 492 enum Disambiguator { DeliberatelyChoosingThisOverload = 42 };
michael@0 493 enum CallerIdentity { ImUsingThisOnlyInFromFromMarkedLocation = 17 };
michael@0 494 MOZ_CONSTEXPR Handle(const T *p, Disambiguator, CallerIdentity) : ptr(p) {}
michael@0 495
michael@0 496 const T *ptr;
michael@0 497
michael@0 498 template <typename S> void operator=(S) MOZ_DELETE;
michael@0 499 void operator=(Handle) MOZ_DELETE;
michael@0 500 };
michael@0 501
michael@0 502 /*
michael@0 503 * Similar to a handle, but the underlying storage can be changed. This is
michael@0 504 * useful for outparams.
michael@0 505 *
michael@0 506 * If you want to add additional methods to MutableHandle for a specific
michael@0 507 * specialization, define a MutableHandleBase<T> specialization containing
michael@0 508 * them.
michael@0 509 */
michael@0 510 template <typename T>
michael@0 511 class MOZ_STACK_CLASS MutableHandle : public js::MutableHandleBase<T>
michael@0 512 {
michael@0 513 public:
michael@0 514 inline MutableHandle(Rooted<T> *root);
michael@0 515 inline MutableHandle(PersistentRooted<T> *root);
michael@0 516
michael@0 517 private:
michael@0 518 // Disallow true nullptr and emulated nullptr (gcc 4.4/4.5, __null, appears
michael@0 519 // as int/long [32/64-bit]) for overloading purposes.
michael@0 520 template<typename N>
michael@0 521 MutableHandle(N,
michael@0 522 typename mozilla::EnableIf<mozilla::IsNullPointer<N>::value ||
michael@0 523 mozilla::IsSame<N, int>::value ||
michael@0 524 mozilla::IsSame<N, long>::value,
michael@0 525 int>::Type dummy = 0)
michael@0 526 MOZ_DELETE;
michael@0 527
michael@0 528 public:
michael@0 529 void set(T v) {
michael@0 530 MOZ_ASSERT(!js::GCMethods<T>::poisoned(v));
michael@0 531 *ptr = v;
michael@0 532 }
michael@0 533
michael@0 534 /*
michael@0 535 * This may be called only if the location of the T is guaranteed
michael@0 536 * to be marked (for some reason other than being a Rooted),
michael@0 537 * e.g., if it is guaranteed to be reachable from an implicit root.
michael@0 538 *
michael@0 539 * Create a MutableHandle from a raw location of a T.
michael@0 540 */
michael@0 541 static MutableHandle fromMarkedLocation(T *p) {
michael@0 542 MutableHandle h;
michael@0 543 h.ptr = p;
michael@0 544 return h;
michael@0 545 }
michael@0 546
michael@0 547 T *address() const { return ptr; }
michael@0 548 const T& get() const { return *ptr; }
michael@0 549
michael@0 550 /*
michael@0 551 * Return a reference so passing a MutableHandle<T> to something that takes
michael@0 552 * a |const T&| is not a GC hazard.
michael@0 553 */
michael@0 554 operator const T&() const { return get(); }
michael@0 555 T operator->() const { return get(); }
michael@0 556
michael@0 557 private:
michael@0 558 MutableHandle() {}
michael@0 559
michael@0 560 T *ptr;
michael@0 561
michael@0 562 template <typename S> void operator=(S v) MOZ_DELETE;
michael@0 563 void operator=(MutableHandle other) MOZ_DELETE;
michael@0 564 };
michael@0 565
michael@0 566 #ifdef JSGC_GENERATIONAL
michael@0 567 JS_FRIEND_API(void) HeapCellPostBarrier(js::gc::Cell **cellp);
michael@0 568 JS_FRIEND_API(void) HeapCellRelocate(js::gc::Cell **cellp);
michael@0 569 #endif
michael@0 570
michael@0 571 } /* namespace JS */
michael@0 572
michael@0 573 namespace js {
michael@0 574
michael@0 575 /*
michael@0 576 * InternalHandle is a handle to an internal pointer into a gcthing. Use
michael@0 577 * InternalHandle when you have a pointer to a direct field of a gcthing, or
michael@0 578 * when you need a parameter type for something that *may* be a pointer to a
michael@0 579 * direct field of a gcthing.
michael@0 580 */
michael@0 581 template <typename T>
michael@0 582 class InternalHandle {};
michael@0 583
michael@0 584 template <typename T>
michael@0 585 class InternalHandle<T*>
michael@0 586 {
michael@0 587 void * const *holder;
michael@0 588 size_t offset;
michael@0 589
michael@0 590 public:
michael@0 591 /*
michael@0 592 * Create an InternalHandle using a Handle to the gcthing containing the
michael@0 593 * field in question, and a pointer to the field.
michael@0 594 */
michael@0 595 template<typename H>
michael@0 596 InternalHandle(const JS::Handle<H> &handle, T *field)
michael@0 597 : holder((void**)handle.address()), offset(uintptr_t(field) - uintptr_t(handle.get()))
michael@0 598 {}
michael@0 599
michael@0 600 /*
michael@0 601 * Create an InternalHandle to a field within a Rooted<>.
michael@0 602 */
michael@0 603 template<typename R>
michael@0 604 InternalHandle(const JS::Rooted<R> &root, T *field)
michael@0 605 : holder((void**)root.address()), offset(uintptr_t(field) - uintptr_t(root.get()))
michael@0 606 {}
michael@0 607
michael@0 608 InternalHandle(const InternalHandle<T*>& other)
michael@0 609 : holder(other.holder), offset(other.offset) {}
michael@0 610
michael@0 611 T *get() const { return reinterpret_cast<T*>(uintptr_t(*holder) + offset); }
michael@0 612
michael@0 613 const T &operator*() const { return *get(); }
michael@0 614 T *operator->() const { return get(); }
michael@0 615
michael@0 616 static InternalHandle<T*> fromMarkedLocation(T *fieldPtr) {
michael@0 617 return InternalHandle(fieldPtr);
michael@0 618 }
michael@0 619
michael@0 620 private:
michael@0 621 /*
michael@0 622 * Create an InternalHandle to something that is not a pointer to a
michael@0 623 * gcthing, and so does not need to be rooted in the first place. Use these
michael@0 624 * InternalHandles to pass pointers into functions that also need to accept
michael@0 625 * regular InternalHandles to gcthing fields.
michael@0 626 *
michael@0 627 * Make this private to prevent accidental misuse; this is only for
michael@0 628 * fromMarkedLocation().
michael@0 629 */
michael@0 630 InternalHandle(T *field)
michael@0 631 : holder(reinterpret_cast<void * const *>(&js::NullPtr::constNullValue)),
michael@0 632 offset(uintptr_t(field))
michael@0 633 {}
michael@0 634
michael@0 635 void operator=(InternalHandle<T*> other) MOZ_DELETE;
michael@0 636 };
michael@0 637
michael@0 638 /*
michael@0 639 * By default, pointers should use the inheritance hierarchy to find their
michael@0 640 * ThingRootKind. Some pointer types are explicitly set in jspubtd.h so that
michael@0 641 * Rooted<T> may be used without the class definition being available.
michael@0 642 */
michael@0 643 template <typename T>
michael@0 644 struct RootKind<T *>
michael@0 645 {
michael@0 646 static ThingRootKind rootKind() { return T::rootKind(); }
michael@0 647 };
michael@0 648
michael@0 649 template <typename T>
michael@0 650 struct GCMethods<T *>
michael@0 651 {
michael@0 652 static T *initial() { return nullptr; }
michael@0 653 static ThingRootKind kind() { return RootKind<T *>::rootKind(); }
michael@0 654 static bool poisoned(T *v) { return JS::IsPoisonedPtr(v); }
michael@0 655 static bool needsPostBarrier(T *v) { return false; }
michael@0 656 #ifdef JSGC_GENERATIONAL
michael@0 657 static void postBarrier(T **vp) {}
michael@0 658 static void relocate(T **vp) {}
michael@0 659 #endif
michael@0 660 };
michael@0 661
michael@0 662 template <>
michael@0 663 struct GCMethods<JSObject *>
michael@0 664 {
michael@0 665 static JSObject *initial() { return nullptr; }
michael@0 666 static ThingRootKind kind() { return RootKind<JSObject *>::rootKind(); }
michael@0 667 static bool poisoned(JSObject *v) { return JS::IsPoisonedPtr(v); }
michael@0 668 static bool needsPostBarrier(JSObject *v) { return v; }
michael@0 669 #ifdef JSGC_GENERATIONAL
michael@0 670 static void postBarrier(JSObject **vp) {
michael@0 671 JS::HeapCellPostBarrier(reinterpret_cast<js::gc::Cell **>(vp));
michael@0 672 }
michael@0 673 static void relocate(JSObject **vp) {
michael@0 674 JS::HeapCellRelocate(reinterpret_cast<js::gc::Cell **>(vp));
michael@0 675 }
michael@0 676 #endif
michael@0 677 };
michael@0 678
michael@0 679 template <>
michael@0 680 struct GCMethods<JSFunction *>
michael@0 681 {
michael@0 682 static JSFunction *initial() { return nullptr; }
michael@0 683 static ThingRootKind kind() { return RootKind<JSObject *>::rootKind(); }
michael@0 684 static bool poisoned(JSFunction *v) { return JS::IsPoisonedPtr(v); }
michael@0 685 static bool needsPostBarrier(JSFunction *v) { return v; }
michael@0 686 #ifdef JSGC_GENERATIONAL
michael@0 687 static void postBarrier(JSFunction **vp) {
michael@0 688 JS::HeapCellPostBarrier(reinterpret_cast<js::gc::Cell **>(vp));
michael@0 689 }
michael@0 690 static void relocate(JSFunction **vp) {
michael@0 691 JS::HeapCellRelocate(reinterpret_cast<js::gc::Cell **>(vp));
michael@0 692 }
michael@0 693 #endif
michael@0 694 };
michael@0 695
michael@0 696 #ifdef JS_DEBUG
michael@0 697 /* This helper allows us to assert that Rooted<T> is scoped within a request. */
michael@0 698 extern JS_PUBLIC_API(bool)
michael@0 699 IsInRequest(JSContext *cx);
michael@0 700 #endif
michael@0 701
michael@0 702 } /* namespace js */
michael@0 703
michael@0 704 namespace JS {
michael@0 705
michael@0 706 /*
michael@0 707 * Local variable of type T whose value is always rooted. This is typically
michael@0 708 * used for local variables, or for non-rooted values being passed to a
michael@0 709 * function that requires a handle, e.g. Foo(Root<T>(cx, x)).
michael@0 710 *
michael@0 711 * If you want to add additional methods to Rooted for a specific
michael@0 712 * specialization, define a RootedBase<T> specialization containing them.
michael@0 713 */
michael@0 714 template <typename T>
michael@0 715 class MOZ_STACK_CLASS Rooted : public js::RootedBase<T>
michael@0 716 {
michael@0 717 /* Note: CX is a subclass of either ContextFriendFields or PerThreadDataFriendFields. */
michael@0 718 template <typename CX>
michael@0 719 void init(CX *cx) {
michael@0 720 #ifdef JSGC_TRACK_EXACT_ROOTS
michael@0 721 js::ThingRootKind kind = js::GCMethods<T>::kind();
michael@0 722 this->stack = &cx->thingGCRooters[kind];
michael@0 723 this->prev = *stack;
michael@0 724 *stack = reinterpret_cast<Rooted<void*>*>(this);
michael@0 725
michael@0 726 MOZ_ASSERT(!js::GCMethods<T>::poisoned(ptr));
michael@0 727 #endif
michael@0 728 }
michael@0 729
michael@0 730 public:
michael@0 731 Rooted(JSContext *cx
michael@0 732 MOZ_GUARD_OBJECT_NOTIFIER_PARAM)
michael@0 733 : ptr(js::GCMethods<T>::initial())
michael@0 734 {
michael@0 735 MOZ_GUARD_OBJECT_NOTIFIER_INIT;
michael@0 736 #ifdef JS_DEBUG
michael@0 737 MOZ_ASSERT(js::IsInRequest(cx));
michael@0 738 #endif
michael@0 739 init(js::ContextFriendFields::get(cx));
michael@0 740 }
michael@0 741
michael@0 742 Rooted(JSContext *cx, T initial
michael@0 743 MOZ_GUARD_OBJECT_NOTIFIER_PARAM)
michael@0 744 : ptr(initial)
michael@0 745 {
michael@0 746 MOZ_GUARD_OBJECT_NOTIFIER_INIT;
michael@0 747 #ifdef JS_DEBUG
michael@0 748 MOZ_ASSERT(js::IsInRequest(cx));
michael@0 749 #endif
michael@0 750 init(js::ContextFriendFields::get(cx));
michael@0 751 }
michael@0 752
michael@0 753 Rooted(js::ContextFriendFields *cx
michael@0 754 MOZ_GUARD_OBJECT_NOTIFIER_PARAM)
michael@0 755 : ptr(js::GCMethods<T>::initial())
michael@0 756 {
michael@0 757 MOZ_GUARD_OBJECT_NOTIFIER_INIT;
michael@0 758 init(cx);
michael@0 759 }
michael@0 760
michael@0 761 Rooted(js::ContextFriendFields *cx, T initial
michael@0 762 MOZ_GUARD_OBJECT_NOTIFIER_PARAM)
michael@0 763 : ptr(initial)
michael@0 764 {
michael@0 765 MOZ_GUARD_OBJECT_NOTIFIER_INIT;
michael@0 766 init(cx);
michael@0 767 }
michael@0 768
michael@0 769 Rooted(js::PerThreadDataFriendFields *pt
michael@0 770 MOZ_GUARD_OBJECT_NOTIFIER_PARAM)
michael@0 771 : ptr(js::GCMethods<T>::initial())
michael@0 772 {
michael@0 773 MOZ_GUARD_OBJECT_NOTIFIER_INIT;
michael@0 774 init(pt);
michael@0 775 }
michael@0 776
michael@0 777 Rooted(js::PerThreadDataFriendFields *pt, T initial
michael@0 778 MOZ_GUARD_OBJECT_NOTIFIER_PARAM)
michael@0 779 : ptr(initial)
michael@0 780 {
michael@0 781 MOZ_GUARD_OBJECT_NOTIFIER_INIT;
michael@0 782 init(pt);
michael@0 783 }
michael@0 784
michael@0 785 Rooted(JSRuntime *rt
michael@0 786 MOZ_GUARD_OBJECT_NOTIFIER_PARAM)
michael@0 787 : ptr(js::GCMethods<T>::initial())
michael@0 788 {
michael@0 789 MOZ_GUARD_OBJECT_NOTIFIER_INIT;
michael@0 790 init(js::PerThreadDataFriendFields::getMainThread(rt));
michael@0 791 }
michael@0 792
michael@0 793 Rooted(JSRuntime *rt, T initial
michael@0 794 MOZ_GUARD_OBJECT_NOTIFIER_PARAM)
michael@0 795 : ptr(initial)
michael@0 796 {
michael@0 797 MOZ_GUARD_OBJECT_NOTIFIER_INIT;
michael@0 798 init(js::PerThreadDataFriendFields::getMainThread(rt));
michael@0 799 }
michael@0 800
michael@0 801 // Note that we need to let the compiler generate the default destructor in
michael@0 802 // non-exact-rooting builds because of a bug in the instrumented PGO builds
michael@0 803 // using MSVC, see bug 915735 for more details.
michael@0 804 #ifdef JSGC_TRACK_EXACT_ROOTS
michael@0 805 ~Rooted() {
michael@0 806 MOZ_ASSERT(*stack == reinterpret_cast<Rooted<void*>*>(this));
michael@0 807 *stack = prev;
michael@0 808 }
michael@0 809 #endif
michael@0 810
michael@0 811 #ifdef JSGC_TRACK_EXACT_ROOTS
michael@0 812 Rooted<T> *previous() { return prev; }
michael@0 813 #endif
michael@0 814
michael@0 815 /*
michael@0 816 * Important: Return a reference here so passing a Rooted<T> to
michael@0 817 * something that takes a |const T&| is not a GC hazard.
michael@0 818 */
michael@0 819 operator const T&() const { return ptr; }
michael@0 820 T operator->() const { return ptr; }
michael@0 821 T *address() { return &ptr; }
michael@0 822 const T *address() const { return &ptr; }
michael@0 823 T &get() { return ptr; }
michael@0 824 const T &get() const { return ptr; }
michael@0 825
michael@0 826 T &operator=(T value) {
michael@0 827 MOZ_ASSERT(!js::GCMethods<T>::poisoned(value));
michael@0 828 ptr = value;
michael@0 829 return ptr;
michael@0 830 }
michael@0 831
michael@0 832 T &operator=(const Rooted &value) {
michael@0 833 ptr = value;
michael@0 834 return ptr;
michael@0 835 }
michael@0 836
michael@0 837 void set(T value) {
michael@0 838 MOZ_ASSERT(!js::GCMethods<T>::poisoned(value));
michael@0 839 ptr = value;
michael@0 840 }
michael@0 841
michael@0 842 bool operator!=(const T &other) const { return ptr != other; }
michael@0 843 bool operator==(const T &other) const { return ptr == other; }
michael@0 844
michael@0 845 private:
michael@0 846 #ifdef JSGC_TRACK_EXACT_ROOTS
michael@0 847 Rooted<void*> **stack, *prev;
michael@0 848 #endif
michael@0 849
michael@0 850 /*
michael@0 851 * |ptr| must be the last field in Rooted because the analysis treats all
michael@0 852 * Rooted as Rooted<void*> during the analysis. See bug 829372.
michael@0 853 */
michael@0 854 T ptr;
michael@0 855
michael@0 856 MOZ_DECL_USE_GUARD_OBJECT_NOTIFIER
michael@0 857
michael@0 858 Rooted(const Rooted &) MOZ_DELETE;
michael@0 859 };
michael@0 860
michael@0 861 } /* namespace JS */
michael@0 862
michael@0 863 namespace js {
michael@0 864
michael@0 865 /*
michael@0 866 * Augment the generic Rooted<T> interface when T = JSObject* with
michael@0 867 * class-querying and downcasting operations.
michael@0 868 *
michael@0 869 * Given a Rooted<JSObject*> obj, one can view
michael@0 870 * Handle<StringObject*> h = obj.as<StringObject*>();
michael@0 871 * as an optimization of
michael@0 872 * Rooted<StringObject*> rooted(cx, &obj->as<StringObject*>());
michael@0 873 * Handle<StringObject*> h = rooted;
michael@0 874 */
michael@0 875 template <>
michael@0 876 class RootedBase<JSObject*>
michael@0 877 {
michael@0 878 public:
michael@0 879 template <class U>
michael@0 880 JS::Handle<U*> as() const;
michael@0 881 };
michael@0 882
michael@0 883
michael@0 884 /*
michael@0 885 * RootedGeneric<T> allows a class to instantiate its own Rooted type by
michael@0 886 * including the following two methods:
michael@0 887 *
michael@0 888 * static inline js::ThingRootKind rootKind() { return js::THING_ROOT_CUSTOM; }
michael@0 889 * void trace(JSTracer *trc);
michael@0 890 *
michael@0 891 * The trace() method must trace all of the class's fields.
michael@0 892 *
michael@0 893 * Implementation:
michael@0 894 *
michael@0 895 * RootedGeneric<T> works by placing a pointer to its 'rooter' field into the
michael@0 896 * usual list of rooters when it is instantiated. When marking, it backs up
michael@0 897 * from this pointer to find a vtable containing a type-appropriate trace()
michael@0 898 * method.
michael@0 899 */
michael@0 900 template <typename GCType>
michael@0 901 class JS_PUBLIC_API(RootedGeneric)
michael@0 902 {
michael@0 903 public:
michael@0 904 JS::Rooted<GCType> rooter;
michael@0 905
michael@0 906 RootedGeneric(js::ContextFriendFields *cx)
michael@0 907 : rooter(cx)
michael@0 908 {
michael@0 909 }
michael@0 910
michael@0 911 RootedGeneric(js::ContextFriendFields *cx, const GCType &initial)
michael@0 912 : rooter(cx, initial)
michael@0 913 {
michael@0 914 }
michael@0 915
michael@0 916 virtual inline void trace(JSTracer *trc);
michael@0 917
michael@0 918 operator const GCType&() const { return rooter.get(); }
michael@0 919 GCType operator->() const { return rooter.get(); }
michael@0 920 };
michael@0 921
michael@0 922 template <typename GCType>
michael@0 923 inline void RootedGeneric<GCType>::trace(JSTracer *trc)
michael@0 924 {
michael@0 925 rooter->trace(trc);
michael@0 926 }
michael@0 927
michael@0 928 // We will instantiate RootedGeneric<void*> in RootMarking.cpp, and MSVC will
michael@0 929 // notice that void*s have no trace() method defined on them and complain (even
michael@0 930 // though it's never called.) MSVC's complaint is not unreasonable, so
michael@0 931 // specialize for void*.
michael@0 932 template <>
michael@0 933 inline void RootedGeneric<void*>::trace(JSTracer *trc)
michael@0 934 {
michael@0 935 MOZ_ASSUME_UNREACHABLE("RootedGeneric<void*>::trace()");
michael@0 936 }
michael@0 937
michael@0 938 /* Interface substitute for Rooted<T> which does not root the variable's memory. */
michael@0 939 template <typename T>
michael@0 940 class FakeRooted : public RootedBase<T>
michael@0 941 {
michael@0 942 public:
michael@0 943 template <typename CX>
michael@0 944 FakeRooted(CX *cx
michael@0 945 MOZ_GUARD_OBJECT_NOTIFIER_PARAM)
michael@0 946 : ptr(GCMethods<T>::initial())
michael@0 947 {
michael@0 948 MOZ_GUARD_OBJECT_NOTIFIER_INIT;
michael@0 949 }
michael@0 950
michael@0 951 template <typename CX>
michael@0 952 FakeRooted(CX *cx, T initial
michael@0 953 MOZ_GUARD_OBJECT_NOTIFIER_PARAM)
michael@0 954 : ptr(initial)
michael@0 955 {
michael@0 956 MOZ_GUARD_OBJECT_NOTIFIER_INIT;
michael@0 957 }
michael@0 958
michael@0 959 operator T() const { return ptr; }
michael@0 960 T operator->() const { return ptr; }
michael@0 961 T *address() { return &ptr; }
michael@0 962 const T *address() const { return &ptr; }
michael@0 963 T &get() { return ptr; }
michael@0 964 const T &get() const { return ptr; }
michael@0 965
michael@0 966 FakeRooted<T> &operator=(T value) {
michael@0 967 MOZ_ASSERT(!GCMethods<T>::poisoned(value));
michael@0 968 ptr = value;
michael@0 969 return *this;
michael@0 970 }
michael@0 971
michael@0 972 FakeRooted<T> &operator=(const FakeRooted<T> &other) {
michael@0 973 MOZ_ASSERT(!GCMethods<T>::poisoned(other.ptr));
michael@0 974 ptr = other.ptr;
michael@0 975 return *this;
michael@0 976 }
michael@0 977
michael@0 978 bool operator!=(const T &other) const { return ptr != other; }
michael@0 979 bool operator==(const T &other) const { return ptr == other; }
michael@0 980
michael@0 981 private:
michael@0 982 T ptr;
michael@0 983
michael@0 984 MOZ_DECL_USE_GUARD_OBJECT_NOTIFIER
michael@0 985
michael@0 986 FakeRooted(const FakeRooted &) MOZ_DELETE;
michael@0 987 };
michael@0 988
michael@0 989 /* Interface substitute for MutableHandle<T> which is not required to point to rooted memory. */
michael@0 990 template <typename T>
michael@0 991 class FakeMutableHandle : public js::MutableHandleBase<T>
michael@0 992 {
michael@0 993 public:
michael@0 994 FakeMutableHandle(T *t) {
michael@0 995 ptr = t;
michael@0 996 }
michael@0 997
michael@0 998 FakeMutableHandle(FakeRooted<T> *root) {
michael@0 999 ptr = root->address();
michael@0 1000 }
michael@0 1001
michael@0 1002 void set(T v) {
michael@0 1003 MOZ_ASSERT(!js::GCMethods<T>::poisoned(v));
michael@0 1004 *ptr = v;
michael@0 1005 }
michael@0 1006
michael@0 1007 T *address() const { return ptr; }
michael@0 1008 T get() const { return *ptr; }
michael@0 1009
michael@0 1010 operator T() const { return get(); }
michael@0 1011 T operator->() const { return get(); }
michael@0 1012
michael@0 1013 private:
michael@0 1014 FakeMutableHandle() {}
michael@0 1015
michael@0 1016 T *ptr;
michael@0 1017
michael@0 1018 template <typename S>
michael@0 1019 void operator=(S v) MOZ_DELETE;
michael@0 1020
michael@0 1021 void operator=(const FakeMutableHandle<T>& other) MOZ_DELETE;
michael@0 1022 };
michael@0 1023
michael@0 1024 /*
michael@0 1025 * Types for a variable that either should or shouldn't be rooted, depending on
michael@0 1026 * the template parameter allowGC. Used for implementing functions that can
michael@0 1027 * operate on either rooted or unrooted data.
michael@0 1028 *
michael@0 1029 * The toHandle() and toMutableHandle() functions are for calling functions
michael@0 1030 * which require handle types and are only called in the CanGC case. These
michael@0 1031 * allow the calling code to type check.
michael@0 1032 */
michael@0 1033 enum AllowGC {
michael@0 1034 NoGC = 0,
michael@0 1035 CanGC = 1
michael@0 1036 };
michael@0 1037 template <typename T, AllowGC allowGC>
michael@0 1038 class MaybeRooted
michael@0 1039 {
michael@0 1040 };
michael@0 1041
michael@0 1042 template <typename T> class MaybeRooted<T, CanGC>
michael@0 1043 {
michael@0 1044 public:
michael@0 1045 typedef JS::Handle<T> HandleType;
michael@0 1046 typedef JS::Rooted<T> RootType;
michael@0 1047 typedef JS::MutableHandle<T> MutableHandleType;
michael@0 1048
michael@0 1049 static inline JS::Handle<T> toHandle(HandleType v) {
michael@0 1050 return v;
michael@0 1051 }
michael@0 1052
michael@0 1053 static inline JS::MutableHandle<T> toMutableHandle(MutableHandleType v) {
michael@0 1054 return v;
michael@0 1055 }
michael@0 1056 };
michael@0 1057
michael@0 1058 template <typename T> class MaybeRooted<T, NoGC>
michael@0 1059 {
michael@0 1060 public:
michael@0 1061 typedef T HandleType;
michael@0 1062 typedef FakeRooted<T> RootType;
michael@0 1063 typedef FakeMutableHandle<T> MutableHandleType;
michael@0 1064
michael@0 1065 static inline JS::Handle<T> toHandle(HandleType v) {
michael@0 1066 MOZ_ASSUME_UNREACHABLE("Bad conversion");
michael@0 1067 }
michael@0 1068
michael@0 1069 static inline JS::MutableHandle<T> toMutableHandle(MutableHandleType v) {
michael@0 1070 MOZ_ASSUME_UNREACHABLE("Bad conversion");
michael@0 1071 }
michael@0 1072 };
michael@0 1073
michael@0 1074 } /* namespace js */
michael@0 1075
michael@0 1076 namespace JS {
michael@0 1077
michael@0 1078 template <typename T> template <typename S>
michael@0 1079 inline
michael@0 1080 Handle<T>::Handle(const Rooted<S> &root,
michael@0 1081 typename mozilla::EnableIf<mozilla::IsConvertible<S, T>::value, int>::Type dummy)
michael@0 1082 {
michael@0 1083 ptr = reinterpret_cast<const T *>(root.address());
michael@0 1084 }
michael@0 1085
michael@0 1086 template <typename T> template <typename S>
michael@0 1087 inline
michael@0 1088 Handle<T>::Handle(const PersistentRooted<S> &root,
michael@0 1089 typename mozilla::EnableIf<mozilla::IsConvertible<S, T>::value, int>::Type dummy)
michael@0 1090 {
michael@0 1091 ptr = reinterpret_cast<const T *>(root.address());
michael@0 1092 }
michael@0 1093
michael@0 1094 template <typename T> template <typename S>
michael@0 1095 inline
michael@0 1096 Handle<T>::Handle(MutableHandle<S> &root,
michael@0 1097 typename mozilla::EnableIf<mozilla::IsConvertible<S, T>::value, int>::Type dummy)
michael@0 1098 {
michael@0 1099 ptr = reinterpret_cast<const T *>(root.address());
michael@0 1100 }
michael@0 1101
michael@0 1102 template <typename T>
michael@0 1103 inline
michael@0 1104 MutableHandle<T>::MutableHandle(Rooted<T> *root)
michael@0 1105 {
michael@0 1106 static_assert(sizeof(MutableHandle<T>) == sizeof(T *),
michael@0 1107 "MutableHandle must be binary compatible with T*.");
michael@0 1108 ptr = root->address();
michael@0 1109 }
michael@0 1110
michael@0 1111 template <typename T>
michael@0 1112 inline
michael@0 1113 MutableHandle<T>::MutableHandle(PersistentRooted<T> *root)
michael@0 1114 {
michael@0 1115 static_assert(sizeof(MutableHandle<T>) == sizeof(T *),
michael@0 1116 "MutableHandle must be binary compatible with T*.");
michael@0 1117 ptr = root->address();
michael@0 1118 }
michael@0 1119
michael@0 1120 /*
michael@0 1121 * A copyable, assignable global GC root type with arbitrary lifetime, an
michael@0 1122 * infallible constructor, and automatic unrooting on destruction.
michael@0 1123 *
michael@0 1124 * These roots can be used in heap-allocated data structures, so they are not
michael@0 1125 * associated with any particular JSContext or stack. They are registered with
michael@0 1126 * the JSRuntime itself, without locking, so they require a full JSContext to be
michael@0 1127 * constructed, not one of its more restricted superclasses.
michael@0 1128 *
michael@0 1129 * Note that you must not use an PersistentRooted in an object owned by a JS
michael@0 1130 * object:
michael@0 1131 *
michael@0 1132 * Whenever one object whose lifetime is decided by the GC refers to another
michael@0 1133 * such object, that edge must be traced only if the owning JS object is traced.
michael@0 1134 * This applies not only to JS objects (which obviously are managed by the GC)
michael@0 1135 * but also to C++ objects owned by JS objects.
michael@0 1136 *
michael@0 1137 * If you put a PersistentRooted in such a C++ object, that is almost certainly
michael@0 1138 * a leak. When a GC begins, the referent of the PersistentRooted is treated as
michael@0 1139 * live, unconditionally (because a PersistentRooted is a *root*), even if the
michael@0 1140 * JS object that owns it is unreachable. If there is any path from that
michael@0 1141 * referent back to the JS object, then the C++ object containing the
michael@0 1142 * PersistentRooted will not be destructed, and the whole blob of objects will
michael@0 1143 * not be freed, even if there are no references to them from the outside.
michael@0 1144 *
michael@0 1145 * In the context of Firefox, this is a severe restriction: almost everything in
michael@0 1146 * Firefox is owned by some JS object or another, so using PersistentRooted in
michael@0 1147 * such objects would introduce leaks. For these kinds of edges, Heap<T> or
michael@0 1148 * TenuredHeap<T> would be better types. It's up to the implementor of the type
michael@0 1149 * containing Heap<T> or TenuredHeap<T> members to make sure their referents get
michael@0 1150 * marked when the object itself is marked.
michael@0 1151 */
michael@0 1152 template<typename T>
michael@0 1153 class PersistentRooted : private mozilla::LinkedListElement<PersistentRooted<T> > {
michael@0 1154 friend class mozilla::LinkedList<PersistentRooted>;
michael@0 1155 friend class mozilla::LinkedListElement<PersistentRooted>;
michael@0 1156
michael@0 1157 friend class js::gc::PersistentRootedMarker<T>;
michael@0 1158
michael@0 1159 void registerWithRuntime(JSRuntime *rt) {
michael@0 1160 JS::shadow::Runtime *srt = JS::shadow::Runtime::asShadowRuntime(rt);
michael@0 1161 srt->getPersistentRootedList<T>().insertBack(this);
michael@0 1162 }
michael@0 1163
michael@0 1164 public:
michael@0 1165 PersistentRooted(JSContext *cx) : ptr(js::GCMethods<T>::initial())
michael@0 1166 {
michael@0 1167 registerWithRuntime(js::GetRuntime(cx));
michael@0 1168 }
michael@0 1169
michael@0 1170 PersistentRooted(JSContext *cx, T initial) : ptr(initial)
michael@0 1171 {
michael@0 1172 registerWithRuntime(js::GetRuntime(cx));
michael@0 1173 }
michael@0 1174
michael@0 1175 PersistentRooted(JSRuntime *rt) : ptr(js::GCMethods<T>::initial())
michael@0 1176 {
michael@0 1177 registerWithRuntime(rt);
michael@0 1178 }
michael@0 1179
michael@0 1180 PersistentRooted(JSRuntime *rt, T initial) : ptr(initial)
michael@0 1181 {
michael@0 1182 registerWithRuntime(rt);
michael@0 1183 }
michael@0 1184
michael@0 1185 PersistentRooted(PersistentRooted &rhs) : ptr(rhs.ptr)
michael@0 1186 {
michael@0 1187 /*
michael@0 1188 * Copy construction takes advantage of the fact that the original
michael@0 1189 * is already inserted, and simply adds itself to whatever list the
michael@0 1190 * original was on - no JSRuntime pointer needed.
michael@0 1191 */
michael@0 1192 rhs.setNext(this);
michael@0 1193 }
michael@0 1194
michael@0 1195 /*
michael@0 1196 * Important: Return a reference here so passing a Rooted<T> to
michael@0 1197 * something that takes a |const T&| is not a GC hazard.
michael@0 1198 */
michael@0 1199 operator const T&() const { return ptr; }
michael@0 1200 T operator->() const { return ptr; }
michael@0 1201 T *address() { return &ptr; }
michael@0 1202 const T *address() const { return &ptr; }
michael@0 1203 T &get() { return ptr; }
michael@0 1204 const T &get() const { return ptr; }
michael@0 1205
michael@0 1206 T &operator=(T value) {
michael@0 1207 MOZ_ASSERT(!js::GCMethods<T>::poisoned(value));
michael@0 1208 ptr = value;
michael@0 1209 return ptr;
michael@0 1210 }
michael@0 1211
michael@0 1212 T &operator=(const PersistentRooted &value) {
michael@0 1213 ptr = value;
michael@0 1214 return ptr;
michael@0 1215 }
michael@0 1216
michael@0 1217 void set(T value) {
michael@0 1218 MOZ_ASSERT(!js::GCMethods<T>::poisoned(value));
michael@0 1219 ptr = value;
michael@0 1220 }
michael@0 1221
michael@0 1222 bool operator!=(const T &other) const { return ptr != other; }
michael@0 1223 bool operator==(const T &other) const { return ptr == other; }
michael@0 1224
michael@0 1225 private:
michael@0 1226 T ptr;
michael@0 1227 };
michael@0 1228
michael@0 1229 } /* namespace JS */
michael@0 1230
michael@0 1231 namespace js {
michael@0 1232
michael@0 1233 /* Base class for automatic read-only object rooting during compilation. */
michael@0 1234 class CompilerRootNode
michael@0 1235 {
michael@0 1236 protected:
michael@0 1237 CompilerRootNode(js::gc::Cell *ptr) : next(nullptr), ptr_(ptr) {}
michael@0 1238
michael@0 1239 public:
michael@0 1240 void **address() { return (void **)&ptr_; }
michael@0 1241
michael@0 1242 public:
michael@0 1243 CompilerRootNode *next;
michael@0 1244
michael@0 1245 protected:
michael@0 1246 js::gc::Cell *ptr_;
michael@0 1247 };
michael@0 1248
michael@0 1249 } /* namespace js */
michael@0 1250
michael@0 1251 #endif /* js_RootingAPI_h */

mercurial