michael@0: /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- michael@0: * vim: set ts=8 sts=4 et sw=4 tw=99: michael@0: * This Source Code Form is subject to the terms of the Mozilla Public michael@0: * License, v. 2.0. If a copy of the MPL was not distributed with this michael@0: * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ michael@0: michael@0: #ifndef js_RootingAPI_h michael@0: #define js_RootingAPI_h michael@0: michael@0: #include "mozilla/Attributes.h" michael@0: #include "mozilla/GuardObjects.h" michael@0: #include "mozilla/LinkedList.h" michael@0: #include "mozilla/NullPtr.h" michael@0: #include "mozilla/TypeTraits.h" michael@0: michael@0: #include "jspubtd.h" michael@0: michael@0: #include "js/TypeDecls.h" michael@0: #include "js/Utility.h" michael@0: michael@0: /* michael@0: * Moving GC Stack Rooting michael@0: * michael@0: * A moving GC may change the physical location of GC allocated things, even michael@0: * when they are rooted, updating all pointers to the thing to refer to its new michael@0: * location. The GC must therefore know about all live pointers to a thing, michael@0: * not just one of them, in order to behave correctly. michael@0: * michael@0: * The |Rooted| and |Handle| classes below are used to root stack locations michael@0: * whose value may be held live across a call that can trigger GC. For a michael@0: * code fragment such as: michael@0: * michael@0: * JSObject *obj = NewObject(cx); michael@0: * DoSomething(cx); michael@0: * ... = obj->lastProperty(); michael@0: * michael@0: * If |DoSomething()| can trigger a GC, the stack location of |obj| must be michael@0: * rooted to ensure that the GC does not move the JSObject referred to by michael@0: * |obj| without updating |obj|'s location itself. This rooting must happen michael@0: * regardless of whether there are other roots which ensure that the object michael@0: * itself will not be collected. michael@0: * michael@0: * If |DoSomething()| cannot trigger a GC, and the same holds for all other michael@0: * calls made between |obj|'s definitions and its last uses, then no rooting michael@0: * is required. michael@0: * michael@0: * SpiderMonkey can trigger a GC at almost any time and in ways that are not michael@0: * always clear. For example, the following innocuous-looking actions can michael@0: * cause a GC: allocation of any new GC thing; JSObject::hasProperty; michael@0: * JS_ReportError and friends; and ToNumber, among many others. The following michael@0: * dangerous-looking actions cannot trigger a GC: js_malloc, cx->malloc_, michael@0: * rt->malloc_, and friends and JS_ReportOutOfMemory. michael@0: * michael@0: * The following family of three classes will exactly root a stack location. michael@0: * Incorrect usage of these classes will result in a compile error in almost michael@0: * all cases. Therefore, it is very hard to be incorrectly rooted if you use michael@0: * these classes exclusively. These classes are all templated on the type T of michael@0: * the value being rooted. michael@0: * michael@0: * - Rooted declares a variable of type T, whose value is always rooted. michael@0: * Rooted may be automatically coerced to a Handle, below. Rooted michael@0: * should be used whenever a local variable's value may be held live across a michael@0: * call which can trigger a GC. michael@0: * michael@0: * - Handle is a const reference to a Rooted. Functions which take GC michael@0: * things or values as arguments and need to root those arguments should michael@0: * generally use handles for those arguments and avoid any explicit rooting. michael@0: * This has two benefits. First, when several such functions call each other michael@0: * then redundant rooting of multiple copies of the GC thing can be avoided. michael@0: * Second, if the caller does not pass a rooted value a compile error will be michael@0: * generated, which is quicker and easier to fix than when relying on a michael@0: * separate rooting analysis. michael@0: * michael@0: * - MutableHandle is a non-const reference to Rooted. It is used in the michael@0: * same way as Handle and includes a |set(const T &v)| method to allow michael@0: * updating the value of the referenced Rooted. A MutableHandle can be michael@0: * created from a Rooted by using |Rooted::operator&()|. michael@0: * michael@0: * In some cases the small performance overhead of exact rooting (measured to michael@0: * be a few nanoseconds on desktop) is too much. In these cases, try the michael@0: * following: michael@0: * michael@0: * - Move all Rooted above inner loops: this allows you to re-use the root michael@0: * on each iteration of the loop. michael@0: * michael@0: * - Pass Handle through your hot call stack to avoid re-rooting costs at michael@0: * every invocation. michael@0: * michael@0: * The following diagram explains the list of supported, implicit type michael@0: * conversions between classes of this family: michael@0: * michael@0: * Rooted ----> Handle michael@0: * | ^ michael@0: * | | michael@0: * | | michael@0: * +---> MutableHandle michael@0: * (via &) michael@0: * michael@0: * All of these types have an implicit conversion to raw pointers. michael@0: */ michael@0: michael@0: namespace js { michael@0: michael@0: class ScriptSourceObject; michael@0: michael@0: template michael@0: struct GCMethods {}; michael@0: michael@0: template michael@0: class RootedBase {}; michael@0: michael@0: template michael@0: class HandleBase {}; michael@0: michael@0: template michael@0: class MutableHandleBase {}; michael@0: michael@0: template michael@0: class HeapBase {}; michael@0: michael@0: /* michael@0: * js::NullPtr acts like a nullptr pointer in contexts that require a Handle. michael@0: * michael@0: * Handle provides an implicit constructor for js::NullPtr so that, given: michael@0: * foo(Handle h); michael@0: * callers can simply write: michael@0: * foo(js::NullPtr()); michael@0: * which avoids creating a Rooted just to pass nullptr. michael@0: * michael@0: * This is the SpiderMonkey internal variant. js::NullPtr should be used in michael@0: * preference to JS::NullPtr to avoid the GOT access required for JS_PUBLIC_API michael@0: * symbols. michael@0: */ michael@0: struct NullPtr michael@0: { michael@0: static void * const constNullValue; michael@0: }; michael@0: michael@0: namespace gc { michael@0: struct Cell; michael@0: template michael@0: struct PersistentRootedMarker; michael@0: } /* namespace gc */ michael@0: michael@0: } /* namespace js */ michael@0: michael@0: namespace JS { michael@0: michael@0: template class Rooted; michael@0: template class PersistentRooted; michael@0: michael@0: /* This is exposing internal state of the GC for inlining purposes. */ michael@0: JS_FRIEND_API(bool) isGCEnabled(); michael@0: michael@0: /* michael@0: * JS::NullPtr acts like a nullptr pointer in contexts that require a Handle. michael@0: * michael@0: * Handle provides an implicit constructor for JS::NullPtr so that, given: michael@0: * foo(Handle h); michael@0: * callers can simply write: michael@0: * foo(JS::NullPtr()); michael@0: * which avoids creating a Rooted just to pass nullptr. michael@0: */ michael@0: struct JS_PUBLIC_API(NullPtr) michael@0: { michael@0: static void * const constNullValue; michael@0: }; michael@0: michael@0: /* michael@0: * The Heap class is a heap-stored reference to a JS GC thing. All members of michael@0: * heap classes that refer to GC things should use Heap (or possibly michael@0: * TenuredHeap, described below). michael@0: * michael@0: * Heap is an abstraction that hides some of the complexity required to michael@0: * maintain GC invariants for the contained reference. It uses operator michael@0: * overloading to provide a normal pointer interface, but notifies the GC every michael@0: * time the value it contains is updated. This is necessary for generational GC, michael@0: * which keeps track of all pointers into the nursery. michael@0: * michael@0: * Heap instances must be traced when their containing object is traced to michael@0: * keep the pointed-to GC thing alive. michael@0: * michael@0: * Heap objects should only be used on the heap. GC references stored on the michael@0: * C/C++ stack must use Rooted/Handle/MutableHandle instead. michael@0: * michael@0: * Type T must be one of: JS::Value, jsid, JSObject*, JSString*, JSScript* michael@0: */ michael@0: template michael@0: class Heap : public js::HeapBase michael@0: { michael@0: public: michael@0: Heap() { michael@0: static_assert(sizeof(T) == sizeof(Heap), michael@0: "Heap must be binary compatible with T."); michael@0: init(js::GCMethods::initial()); michael@0: } michael@0: explicit Heap(T p) { init(p); } michael@0: michael@0: /* michael@0: * For Heap, move semantics are equivalent to copy semantics. In C++, a michael@0: * copy constructor taking const-ref is the way to get a single function michael@0: * that will be used for both lvalue and rvalue copies, so we can simply michael@0: * omit the rvalue variant. michael@0: */ michael@0: explicit Heap(const Heap &p) { init(p.ptr); } michael@0: michael@0: ~Heap() { michael@0: if (js::GCMethods::needsPostBarrier(ptr)) michael@0: relocate(); michael@0: } michael@0: michael@0: bool operator==(const Heap &other) { return ptr == other.ptr; } michael@0: bool operator!=(const Heap &other) { return ptr != other.ptr; } michael@0: michael@0: bool operator==(const T &other) const { return ptr == other; } michael@0: bool operator!=(const T &other) const { return ptr != other; } michael@0: michael@0: operator T() const { return ptr; } michael@0: T operator->() const { return ptr; } michael@0: const T *address() const { return &ptr; } michael@0: const T &get() const { return ptr; } michael@0: michael@0: T *unsafeGet() { return &ptr; } michael@0: michael@0: Heap &operator=(T p) { michael@0: set(p); michael@0: return *this; michael@0: } michael@0: michael@0: Heap &operator=(const Heap& other) { michael@0: set(other.get()); michael@0: return *this; michael@0: } michael@0: michael@0: void set(T newPtr) { michael@0: MOZ_ASSERT(!js::GCMethods::poisoned(newPtr)); michael@0: if (js::GCMethods::needsPostBarrier(newPtr)) { michael@0: ptr = newPtr; michael@0: post(); michael@0: } else if (js::GCMethods::needsPostBarrier(ptr)) { michael@0: relocate(); /* Called before overwriting ptr. */ michael@0: ptr = newPtr; michael@0: } else { michael@0: ptr = newPtr; michael@0: } michael@0: } michael@0: michael@0: /* michael@0: * Set the pointer to a value which will cause a crash if it is michael@0: * dereferenced. michael@0: */ michael@0: void setToCrashOnTouch() { michael@0: ptr = reinterpret_cast(crashOnTouchPointer); michael@0: } michael@0: michael@0: bool isSetToCrashOnTouch() { michael@0: return ptr == crashOnTouchPointer; michael@0: } michael@0: michael@0: private: michael@0: void init(T newPtr) { michael@0: MOZ_ASSERT(!js::GCMethods::poisoned(newPtr)); michael@0: ptr = newPtr; michael@0: if (js::GCMethods::needsPostBarrier(ptr)) michael@0: post(); michael@0: } michael@0: michael@0: void post() { michael@0: #ifdef JSGC_GENERATIONAL michael@0: MOZ_ASSERT(js::GCMethods::needsPostBarrier(ptr)); michael@0: js::GCMethods::postBarrier(&ptr); michael@0: #endif michael@0: } michael@0: michael@0: void relocate() { michael@0: #ifdef JSGC_GENERATIONAL michael@0: js::GCMethods::relocate(&ptr); michael@0: #endif michael@0: } michael@0: michael@0: enum { michael@0: crashOnTouchPointer = 1 michael@0: }; michael@0: michael@0: T ptr; michael@0: }; michael@0: michael@0: #ifdef JS_DEBUG michael@0: /* michael@0: * For generational GC, assert that an object is in the tenured generation as michael@0: * opposed to being in the nursery. michael@0: */ michael@0: extern JS_FRIEND_API(void) michael@0: AssertGCThingMustBeTenured(JSObject* obj); michael@0: #else michael@0: inline void michael@0: AssertGCThingMustBeTenured(JSObject *obj) {} michael@0: #endif michael@0: michael@0: /* michael@0: * The TenuredHeap class is similar to the Heap class above in that it michael@0: * encapsulates the GC concerns of an on-heap reference to a JS object. However, michael@0: * it has two important differences: michael@0: * michael@0: * 1) Pointers which are statically known to only reference "tenured" objects michael@0: * can avoid the extra overhead of SpiderMonkey's write barriers. michael@0: * michael@0: * 2) Objects in the "tenured" heap have stronger alignment restrictions than michael@0: * those in the "nursery", so it is possible to store flags in the lower michael@0: * bits of pointers known to be tenured. TenuredHeap wraps a normal tagged michael@0: * pointer with a nice API for accessing the flag bits and adds various michael@0: * assertions to ensure that it is not mis-used. michael@0: * michael@0: * GC things are said to be "tenured" when they are located in the long-lived michael@0: * heap: e.g. they have gained tenure as an object by surviving past at least michael@0: * one GC. For performance, SpiderMonkey allocates some things which are known michael@0: * to normally be long lived directly into the tenured generation; for example, michael@0: * global objects. Additionally, SpiderMonkey does not visit individual objects michael@0: * when deleting non-tenured objects, so object with finalizers are also always michael@0: * tenured; for instance, this includes most DOM objects. michael@0: * michael@0: * The considerations to keep in mind when using a TenuredHeap vs a normal michael@0: * Heap are: michael@0: * michael@0: * - It is invalid for a TenuredHeap to refer to a non-tenured thing. michael@0: * - It is however valid for a Heap to refer to a tenured thing. michael@0: * - It is not possible to store flag bits in a Heap. michael@0: */ michael@0: template michael@0: class TenuredHeap : public js::HeapBase michael@0: { michael@0: public: michael@0: TenuredHeap() : bits(0) { michael@0: static_assert(sizeof(T) == sizeof(TenuredHeap), michael@0: "TenuredHeap must be binary compatible with T."); michael@0: } michael@0: explicit TenuredHeap(T p) : bits(0) { setPtr(p); } michael@0: explicit TenuredHeap(const TenuredHeap &p) : bits(0) { setPtr(p.getPtr()); } michael@0: michael@0: bool operator==(const TenuredHeap &other) { return bits == other.bits; } michael@0: bool operator!=(const TenuredHeap &other) { return bits != other.bits; } michael@0: michael@0: void setPtr(T newPtr) { michael@0: MOZ_ASSERT((reinterpret_cast(newPtr) & flagsMask) == 0); michael@0: MOZ_ASSERT(!js::GCMethods::poisoned(newPtr)); michael@0: if (newPtr) michael@0: AssertGCThingMustBeTenured(newPtr); michael@0: bits = (bits & flagsMask) | reinterpret_cast(newPtr); michael@0: } michael@0: michael@0: void setFlags(uintptr_t flagsToSet) { michael@0: MOZ_ASSERT((flagsToSet & ~flagsMask) == 0); michael@0: bits |= flagsToSet; michael@0: } michael@0: michael@0: void unsetFlags(uintptr_t flagsToUnset) { michael@0: MOZ_ASSERT((flagsToUnset & ~flagsMask) == 0); michael@0: bits &= ~flagsToUnset; michael@0: } michael@0: michael@0: bool hasFlag(uintptr_t flag) const { michael@0: MOZ_ASSERT((flag & ~flagsMask) == 0); michael@0: return (bits & flag) != 0; michael@0: } michael@0: michael@0: T getPtr() const { return reinterpret_cast(bits & ~flagsMask); } michael@0: uintptr_t getFlags() const { return bits & flagsMask; } michael@0: michael@0: operator T() const { return getPtr(); } michael@0: T operator->() const { return getPtr(); } michael@0: michael@0: TenuredHeap &operator=(T p) { michael@0: setPtr(p); michael@0: return *this; michael@0: } michael@0: michael@0: TenuredHeap &operator=(const TenuredHeap& other) { michael@0: bits = other.bits; michael@0: return *this; michael@0: } michael@0: michael@0: private: michael@0: enum { michael@0: maskBits = 3, michael@0: flagsMask = (1 << maskBits) - 1, michael@0: }; michael@0: michael@0: uintptr_t bits; michael@0: }; michael@0: michael@0: /* michael@0: * Reference to a T that has been rooted elsewhere. This is most useful michael@0: * as a parameter type, which guarantees that the T lvalue is properly michael@0: * rooted. See "Move GC Stack Rooting" above. michael@0: * michael@0: * If you want to add additional methods to Handle for a specific michael@0: * specialization, define a HandleBase specialization containing them. michael@0: */ michael@0: template michael@0: class MOZ_NONHEAP_CLASS Handle : public js::HandleBase michael@0: { michael@0: friend class JS::MutableHandle; michael@0: michael@0: public: michael@0: /* Creates a handle from a handle of a type convertible to T. */ michael@0: template michael@0: Handle(Handle handle, michael@0: typename mozilla::EnableIf::value, int>::Type dummy = 0) michael@0: { michael@0: static_assert(sizeof(Handle) == sizeof(T *), michael@0: "Handle must be binary compatible with T*."); michael@0: ptr = reinterpret_cast(handle.address()); michael@0: } michael@0: michael@0: /* Create a handle for a nullptr pointer. */ michael@0: Handle(js::NullPtr) { michael@0: static_assert(mozilla::IsPointer::value, michael@0: "js::NullPtr overload not valid for non-pointer types"); michael@0: ptr = reinterpret_cast(&js::NullPtr::constNullValue); michael@0: } michael@0: michael@0: /* Create a handle for a nullptr pointer. */ michael@0: Handle(JS::NullPtr) { michael@0: static_assert(mozilla::IsPointer::value, michael@0: "JS::NullPtr overload not valid for non-pointer types"); michael@0: ptr = reinterpret_cast(&JS::NullPtr::constNullValue); michael@0: } michael@0: michael@0: Handle(MutableHandle handle) { michael@0: ptr = handle.address(); michael@0: } michael@0: michael@0: /* michael@0: * Take care when calling this method! michael@0: * michael@0: * This creates a Handle from the raw location of a T. michael@0: * michael@0: * It should be called only if the following conditions hold: michael@0: * michael@0: * 1) the location of the T is guaranteed to be marked (for some reason michael@0: * other than being a Rooted), e.g., if it is guaranteed to be reachable michael@0: * from an implicit root. michael@0: * michael@0: * 2) the contents of the location are immutable, or at least cannot change michael@0: * for the lifetime of the handle, as its users may not expect its value michael@0: * to change underneath them. michael@0: */ michael@0: static MOZ_CONSTEXPR Handle fromMarkedLocation(const T *p) { michael@0: return Handle(p, DeliberatelyChoosingThisOverload, michael@0: ImUsingThisOnlyInFromFromMarkedLocation); michael@0: } michael@0: michael@0: /* michael@0: * Construct a handle from an explicitly rooted location. This is the michael@0: * normal way to create a handle, and normally happens implicitly. michael@0: */ michael@0: template michael@0: inline michael@0: Handle(const Rooted &root, michael@0: typename mozilla::EnableIf::value, int>::Type dummy = 0); michael@0: michael@0: template michael@0: inline michael@0: Handle(const PersistentRooted &root, michael@0: typename mozilla::EnableIf::value, int>::Type dummy = 0); michael@0: michael@0: /* Construct a read only handle from a mutable handle. */ michael@0: template michael@0: inline michael@0: Handle(MutableHandle &root, michael@0: typename mozilla::EnableIf::value, int>::Type dummy = 0); michael@0: michael@0: const T *address() const { return ptr; } michael@0: const T& get() const { return *ptr; } michael@0: michael@0: /* michael@0: * Return a reference so passing a Handle to something that michael@0: * takes a |const T&| is not a GC hazard. michael@0: */ michael@0: operator const T&() const { return get(); } michael@0: T operator->() const { return get(); } michael@0: michael@0: bool operator!=(const T &other) const { return *ptr != other; } michael@0: bool operator==(const T &other) const { return *ptr == other; } michael@0: michael@0: /* Change this handle to point to the same rooted location RHS does. */ michael@0: void repoint(const Handle &rhs) { ptr = rhs.address(); } michael@0: michael@0: private: michael@0: Handle() {} michael@0: michael@0: enum Disambiguator { DeliberatelyChoosingThisOverload = 42 }; michael@0: enum CallerIdentity { ImUsingThisOnlyInFromFromMarkedLocation = 17 }; michael@0: MOZ_CONSTEXPR Handle(const T *p, Disambiguator, CallerIdentity) : ptr(p) {} michael@0: michael@0: const T *ptr; michael@0: michael@0: template void operator=(S) MOZ_DELETE; michael@0: void operator=(Handle) MOZ_DELETE; michael@0: }; michael@0: michael@0: /* michael@0: * Similar to a handle, but the underlying storage can be changed. This is michael@0: * useful for outparams. michael@0: * michael@0: * If you want to add additional methods to MutableHandle for a specific michael@0: * specialization, define a MutableHandleBase specialization containing michael@0: * them. michael@0: */ michael@0: template michael@0: class MOZ_STACK_CLASS MutableHandle : public js::MutableHandleBase michael@0: { michael@0: public: michael@0: inline MutableHandle(Rooted *root); michael@0: inline MutableHandle(PersistentRooted *root); michael@0: michael@0: private: michael@0: // Disallow true nullptr and emulated nullptr (gcc 4.4/4.5, __null, appears michael@0: // as int/long [32/64-bit]) for overloading purposes. michael@0: template michael@0: MutableHandle(N, michael@0: typename mozilla::EnableIf::value || michael@0: mozilla::IsSame::value || michael@0: mozilla::IsSame::value, michael@0: int>::Type dummy = 0) michael@0: MOZ_DELETE; michael@0: michael@0: public: michael@0: void set(T v) { michael@0: MOZ_ASSERT(!js::GCMethods::poisoned(v)); michael@0: *ptr = v; michael@0: } michael@0: michael@0: /* michael@0: * This may be called only if the location of the T is guaranteed michael@0: * to be marked (for some reason other than being a Rooted), michael@0: * e.g., if it is guaranteed to be reachable from an implicit root. michael@0: * michael@0: * Create a MutableHandle from a raw location of a T. michael@0: */ michael@0: static MutableHandle fromMarkedLocation(T *p) { michael@0: MutableHandle h; michael@0: h.ptr = p; michael@0: return h; michael@0: } michael@0: michael@0: T *address() const { return ptr; } michael@0: const T& get() const { return *ptr; } michael@0: michael@0: /* michael@0: * Return a reference so passing a MutableHandle to something that takes michael@0: * a |const T&| is not a GC hazard. michael@0: */ michael@0: operator const T&() const { return get(); } michael@0: T operator->() const { return get(); } michael@0: michael@0: private: michael@0: MutableHandle() {} michael@0: michael@0: T *ptr; michael@0: michael@0: template void operator=(S v) MOZ_DELETE; michael@0: void operator=(MutableHandle other) MOZ_DELETE; michael@0: }; michael@0: michael@0: #ifdef JSGC_GENERATIONAL michael@0: JS_FRIEND_API(void) HeapCellPostBarrier(js::gc::Cell **cellp); michael@0: JS_FRIEND_API(void) HeapCellRelocate(js::gc::Cell **cellp); michael@0: #endif michael@0: michael@0: } /* namespace JS */ michael@0: michael@0: namespace js { michael@0: michael@0: /* michael@0: * InternalHandle is a handle to an internal pointer into a gcthing. Use michael@0: * InternalHandle when you have a pointer to a direct field of a gcthing, or michael@0: * when you need a parameter type for something that *may* be a pointer to a michael@0: * direct field of a gcthing. michael@0: */ michael@0: template michael@0: class InternalHandle {}; michael@0: michael@0: template michael@0: class InternalHandle michael@0: { michael@0: void * const *holder; michael@0: size_t offset; michael@0: michael@0: public: michael@0: /* michael@0: * Create an InternalHandle using a Handle to the gcthing containing the michael@0: * field in question, and a pointer to the field. michael@0: */ michael@0: template michael@0: InternalHandle(const JS::Handle &handle, T *field) michael@0: : holder((void**)handle.address()), offset(uintptr_t(field) - uintptr_t(handle.get())) michael@0: {} michael@0: michael@0: /* michael@0: * Create an InternalHandle to a field within a Rooted<>. michael@0: */ michael@0: template michael@0: InternalHandle(const JS::Rooted &root, T *field) michael@0: : holder((void**)root.address()), offset(uintptr_t(field) - uintptr_t(root.get())) michael@0: {} michael@0: michael@0: InternalHandle(const InternalHandle& other) michael@0: : holder(other.holder), offset(other.offset) {} michael@0: michael@0: T *get() const { return reinterpret_cast(uintptr_t(*holder) + offset); } michael@0: michael@0: const T &operator*() const { return *get(); } michael@0: T *operator->() const { return get(); } michael@0: michael@0: static InternalHandle fromMarkedLocation(T *fieldPtr) { michael@0: return InternalHandle(fieldPtr); michael@0: } michael@0: michael@0: private: michael@0: /* michael@0: * Create an InternalHandle to something that is not a pointer to a michael@0: * gcthing, and so does not need to be rooted in the first place. Use these michael@0: * InternalHandles to pass pointers into functions that also need to accept michael@0: * regular InternalHandles to gcthing fields. michael@0: * michael@0: * Make this private to prevent accidental misuse; this is only for michael@0: * fromMarkedLocation(). michael@0: */ michael@0: InternalHandle(T *field) michael@0: : holder(reinterpret_cast(&js::NullPtr::constNullValue)), michael@0: offset(uintptr_t(field)) michael@0: {} michael@0: michael@0: void operator=(InternalHandle other) MOZ_DELETE; michael@0: }; michael@0: michael@0: /* michael@0: * By default, pointers should use the inheritance hierarchy to find their michael@0: * ThingRootKind. Some pointer types are explicitly set in jspubtd.h so that michael@0: * Rooted may be used without the class definition being available. michael@0: */ michael@0: template michael@0: struct RootKind michael@0: { michael@0: static ThingRootKind rootKind() { return T::rootKind(); } michael@0: }; michael@0: michael@0: template michael@0: struct GCMethods michael@0: { michael@0: static T *initial() { return nullptr; } michael@0: static ThingRootKind kind() { return RootKind::rootKind(); } michael@0: static bool poisoned(T *v) { return JS::IsPoisonedPtr(v); } michael@0: static bool needsPostBarrier(T *v) { return false; } michael@0: #ifdef JSGC_GENERATIONAL michael@0: static void postBarrier(T **vp) {} michael@0: static void relocate(T **vp) {} michael@0: #endif michael@0: }; michael@0: michael@0: template <> michael@0: struct GCMethods michael@0: { michael@0: static JSObject *initial() { return nullptr; } michael@0: static ThingRootKind kind() { return RootKind::rootKind(); } michael@0: static bool poisoned(JSObject *v) { return JS::IsPoisonedPtr(v); } michael@0: static bool needsPostBarrier(JSObject *v) { return v; } michael@0: #ifdef JSGC_GENERATIONAL michael@0: static void postBarrier(JSObject **vp) { michael@0: JS::HeapCellPostBarrier(reinterpret_cast(vp)); michael@0: } michael@0: static void relocate(JSObject **vp) { michael@0: JS::HeapCellRelocate(reinterpret_cast(vp)); michael@0: } michael@0: #endif michael@0: }; michael@0: michael@0: template <> michael@0: struct GCMethods michael@0: { michael@0: static JSFunction *initial() { return nullptr; } michael@0: static ThingRootKind kind() { return RootKind::rootKind(); } michael@0: static bool poisoned(JSFunction *v) { return JS::IsPoisonedPtr(v); } michael@0: static bool needsPostBarrier(JSFunction *v) { return v; } michael@0: #ifdef JSGC_GENERATIONAL michael@0: static void postBarrier(JSFunction **vp) { michael@0: JS::HeapCellPostBarrier(reinterpret_cast(vp)); michael@0: } michael@0: static void relocate(JSFunction **vp) { michael@0: JS::HeapCellRelocate(reinterpret_cast(vp)); michael@0: } michael@0: #endif michael@0: }; michael@0: michael@0: #ifdef JS_DEBUG michael@0: /* This helper allows us to assert that Rooted is scoped within a request. */ michael@0: extern JS_PUBLIC_API(bool) michael@0: IsInRequest(JSContext *cx); michael@0: #endif michael@0: michael@0: } /* namespace js */ michael@0: michael@0: namespace JS { michael@0: michael@0: /* michael@0: * Local variable of type T whose value is always rooted. This is typically michael@0: * used for local variables, or for non-rooted values being passed to a michael@0: * function that requires a handle, e.g. Foo(Root(cx, x)). michael@0: * michael@0: * If you want to add additional methods to Rooted for a specific michael@0: * specialization, define a RootedBase specialization containing them. michael@0: */ michael@0: template michael@0: class MOZ_STACK_CLASS Rooted : public js::RootedBase michael@0: { michael@0: /* Note: CX is a subclass of either ContextFriendFields or PerThreadDataFriendFields. */ michael@0: template michael@0: void init(CX *cx) { michael@0: #ifdef JSGC_TRACK_EXACT_ROOTS michael@0: js::ThingRootKind kind = js::GCMethods::kind(); michael@0: this->stack = &cx->thingGCRooters[kind]; michael@0: this->prev = *stack; michael@0: *stack = reinterpret_cast*>(this); michael@0: michael@0: MOZ_ASSERT(!js::GCMethods::poisoned(ptr)); michael@0: #endif michael@0: } michael@0: michael@0: public: michael@0: Rooted(JSContext *cx michael@0: MOZ_GUARD_OBJECT_NOTIFIER_PARAM) michael@0: : ptr(js::GCMethods::initial()) michael@0: { michael@0: MOZ_GUARD_OBJECT_NOTIFIER_INIT; michael@0: #ifdef JS_DEBUG michael@0: MOZ_ASSERT(js::IsInRequest(cx)); michael@0: #endif michael@0: init(js::ContextFriendFields::get(cx)); michael@0: } michael@0: michael@0: Rooted(JSContext *cx, T initial michael@0: MOZ_GUARD_OBJECT_NOTIFIER_PARAM) michael@0: : ptr(initial) michael@0: { michael@0: MOZ_GUARD_OBJECT_NOTIFIER_INIT; michael@0: #ifdef JS_DEBUG michael@0: MOZ_ASSERT(js::IsInRequest(cx)); michael@0: #endif michael@0: init(js::ContextFriendFields::get(cx)); michael@0: } michael@0: michael@0: Rooted(js::ContextFriendFields *cx michael@0: MOZ_GUARD_OBJECT_NOTIFIER_PARAM) michael@0: : ptr(js::GCMethods::initial()) michael@0: { michael@0: MOZ_GUARD_OBJECT_NOTIFIER_INIT; michael@0: init(cx); michael@0: } michael@0: michael@0: Rooted(js::ContextFriendFields *cx, T initial michael@0: MOZ_GUARD_OBJECT_NOTIFIER_PARAM) michael@0: : ptr(initial) michael@0: { michael@0: MOZ_GUARD_OBJECT_NOTIFIER_INIT; michael@0: init(cx); michael@0: } michael@0: michael@0: Rooted(js::PerThreadDataFriendFields *pt michael@0: MOZ_GUARD_OBJECT_NOTIFIER_PARAM) michael@0: : ptr(js::GCMethods::initial()) michael@0: { michael@0: MOZ_GUARD_OBJECT_NOTIFIER_INIT; michael@0: init(pt); michael@0: } michael@0: michael@0: Rooted(js::PerThreadDataFriendFields *pt, T initial michael@0: MOZ_GUARD_OBJECT_NOTIFIER_PARAM) michael@0: : ptr(initial) michael@0: { michael@0: MOZ_GUARD_OBJECT_NOTIFIER_INIT; michael@0: init(pt); michael@0: } michael@0: michael@0: Rooted(JSRuntime *rt michael@0: MOZ_GUARD_OBJECT_NOTIFIER_PARAM) michael@0: : ptr(js::GCMethods::initial()) michael@0: { michael@0: MOZ_GUARD_OBJECT_NOTIFIER_INIT; michael@0: init(js::PerThreadDataFriendFields::getMainThread(rt)); michael@0: } michael@0: michael@0: Rooted(JSRuntime *rt, T initial michael@0: MOZ_GUARD_OBJECT_NOTIFIER_PARAM) michael@0: : ptr(initial) michael@0: { michael@0: MOZ_GUARD_OBJECT_NOTIFIER_INIT; michael@0: init(js::PerThreadDataFriendFields::getMainThread(rt)); michael@0: } michael@0: michael@0: // Note that we need to let the compiler generate the default destructor in michael@0: // non-exact-rooting builds because of a bug in the instrumented PGO builds michael@0: // using MSVC, see bug 915735 for more details. michael@0: #ifdef JSGC_TRACK_EXACT_ROOTS michael@0: ~Rooted() { michael@0: MOZ_ASSERT(*stack == reinterpret_cast*>(this)); michael@0: *stack = prev; michael@0: } michael@0: #endif michael@0: michael@0: #ifdef JSGC_TRACK_EXACT_ROOTS michael@0: Rooted *previous() { return prev; } michael@0: #endif michael@0: michael@0: /* michael@0: * Important: Return a reference here so passing a Rooted to michael@0: * something that takes a |const T&| is not a GC hazard. michael@0: */ michael@0: operator const T&() const { return ptr; } michael@0: T operator->() const { return ptr; } michael@0: T *address() { return &ptr; } michael@0: const T *address() const { return &ptr; } michael@0: T &get() { return ptr; } michael@0: const T &get() const { return ptr; } michael@0: michael@0: T &operator=(T value) { michael@0: MOZ_ASSERT(!js::GCMethods::poisoned(value)); michael@0: ptr = value; michael@0: return ptr; michael@0: } michael@0: michael@0: T &operator=(const Rooted &value) { michael@0: ptr = value; michael@0: return ptr; michael@0: } michael@0: michael@0: void set(T value) { michael@0: MOZ_ASSERT(!js::GCMethods::poisoned(value)); michael@0: ptr = value; michael@0: } michael@0: michael@0: bool operator!=(const T &other) const { return ptr != other; } michael@0: bool operator==(const T &other) const { return ptr == other; } michael@0: michael@0: private: michael@0: #ifdef JSGC_TRACK_EXACT_ROOTS michael@0: Rooted **stack, *prev; michael@0: #endif michael@0: michael@0: /* michael@0: * |ptr| must be the last field in Rooted because the analysis treats all michael@0: * Rooted as Rooted during the analysis. See bug 829372. michael@0: */ michael@0: T ptr; michael@0: michael@0: MOZ_DECL_USE_GUARD_OBJECT_NOTIFIER michael@0: michael@0: Rooted(const Rooted &) MOZ_DELETE; michael@0: }; michael@0: michael@0: } /* namespace JS */ michael@0: michael@0: namespace js { michael@0: michael@0: /* michael@0: * Augment the generic Rooted interface when T = JSObject* with michael@0: * class-querying and downcasting operations. michael@0: * michael@0: * Given a Rooted obj, one can view michael@0: * Handle h = obj.as(); michael@0: * as an optimization of michael@0: * Rooted rooted(cx, &obj->as()); michael@0: * Handle h = rooted; michael@0: */ michael@0: template <> michael@0: class RootedBase michael@0: { michael@0: public: michael@0: template michael@0: JS::Handle as() const; michael@0: }; michael@0: michael@0: michael@0: /* michael@0: * RootedGeneric allows a class to instantiate its own Rooted type by michael@0: * including the following two methods: michael@0: * michael@0: * static inline js::ThingRootKind rootKind() { return js::THING_ROOT_CUSTOM; } michael@0: * void trace(JSTracer *trc); michael@0: * michael@0: * The trace() method must trace all of the class's fields. michael@0: * michael@0: * Implementation: michael@0: * michael@0: * RootedGeneric works by placing a pointer to its 'rooter' field into the michael@0: * usual list of rooters when it is instantiated. When marking, it backs up michael@0: * from this pointer to find a vtable containing a type-appropriate trace() michael@0: * method. michael@0: */ michael@0: template michael@0: class JS_PUBLIC_API(RootedGeneric) michael@0: { michael@0: public: michael@0: JS::Rooted rooter; michael@0: michael@0: RootedGeneric(js::ContextFriendFields *cx) michael@0: : rooter(cx) michael@0: { michael@0: } michael@0: michael@0: RootedGeneric(js::ContextFriendFields *cx, const GCType &initial) michael@0: : rooter(cx, initial) michael@0: { michael@0: } michael@0: michael@0: virtual inline void trace(JSTracer *trc); michael@0: michael@0: operator const GCType&() const { return rooter.get(); } michael@0: GCType operator->() const { return rooter.get(); } michael@0: }; michael@0: michael@0: template michael@0: inline void RootedGeneric::trace(JSTracer *trc) michael@0: { michael@0: rooter->trace(trc); michael@0: } michael@0: michael@0: // We will instantiate RootedGeneric in RootMarking.cpp, and MSVC will michael@0: // notice that void*s have no trace() method defined on them and complain (even michael@0: // though it's never called.) MSVC's complaint is not unreasonable, so michael@0: // specialize for void*. michael@0: template <> michael@0: inline void RootedGeneric::trace(JSTracer *trc) michael@0: { michael@0: MOZ_ASSUME_UNREACHABLE("RootedGeneric::trace()"); michael@0: } michael@0: michael@0: /* Interface substitute for Rooted which does not root the variable's memory. */ michael@0: template michael@0: class FakeRooted : public RootedBase michael@0: { michael@0: public: michael@0: template michael@0: FakeRooted(CX *cx michael@0: MOZ_GUARD_OBJECT_NOTIFIER_PARAM) michael@0: : ptr(GCMethods::initial()) michael@0: { michael@0: MOZ_GUARD_OBJECT_NOTIFIER_INIT; michael@0: } michael@0: michael@0: template michael@0: FakeRooted(CX *cx, T initial michael@0: MOZ_GUARD_OBJECT_NOTIFIER_PARAM) michael@0: : ptr(initial) michael@0: { michael@0: MOZ_GUARD_OBJECT_NOTIFIER_INIT; michael@0: } michael@0: michael@0: operator T() const { return ptr; } michael@0: T operator->() const { return ptr; } michael@0: T *address() { return &ptr; } michael@0: const T *address() const { return &ptr; } michael@0: T &get() { return ptr; } michael@0: const T &get() const { return ptr; } michael@0: michael@0: FakeRooted &operator=(T value) { michael@0: MOZ_ASSERT(!GCMethods::poisoned(value)); michael@0: ptr = value; michael@0: return *this; michael@0: } michael@0: michael@0: FakeRooted &operator=(const FakeRooted &other) { michael@0: MOZ_ASSERT(!GCMethods::poisoned(other.ptr)); michael@0: ptr = other.ptr; michael@0: return *this; michael@0: } michael@0: michael@0: bool operator!=(const T &other) const { return ptr != other; } michael@0: bool operator==(const T &other) const { return ptr == other; } michael@0: michael@0: private: michael@0: T ptr; michael@0: michael@0: MOZ_DECL_USE_GUARD_OBJECT_NOTIFIER michael@0: michael@0: FakeRooted(const FakeRooted &) MOZ_DELETE; michael@0: }; michael@0: michael@0: /* Interface substitute for MutableHandle which is not required to point to rooted memory. */ michael@0: template michael@0: class FakeMutableHandle : public js::MutableHandleBase michael@0: { michael@0: public: michael@0: FakeMutableHandle(T *t) { michael@0: ptr = t; michael@0: } michael@0: michael@0: FakeMutableHandle(FakeRooted *root) { michael@0: ptr = root->address(); michael@0: } michael@0: michael@0: void set(T v) { michael@0: MOZ_ASSERT(!js::GCMethods::poisoned(v)); michael@0: *ptr = v; michael@0: } michael@0: michael@0: T *address() const { return ptr; } michael@0: T get() const { return *ptr; } michael@0: michael@0: operator T() const { return get(); } michael@0: T operator->() const { return get(); } michael@0: michael@0: private: michael@0: FakeMutableHandle() {} michael@0: michael@0: T *ptr; michael@0: michael@0: template michael@0: void operator=(S v) MOZ_DELETE; michael@0: michael@0: void operator=(const FakeMutableHandle& other) MOZ_DELETE; michael@0: }; michael@0: michael@0: /* michael@0: * Types for a variable that either should or shouldn't be rooted, depending on michael@0: * the template parameter allowGC. Used for implementing functions that can michael@0: * operate on either rooted or unrooted data. michael@0: * michael@0: * The toHandle() and toMutableHandle() functions are for calling functions michael@0: * which require handle types and are only called in the CanGC case. These michael@0: * allow the calling code to type check. michael@0: */ michael@0: enum AllowGC { michael@0: NoGC = 0, michael@0: CanGC = 1 michael@0: }; michael@0: template michael@0: class MaybeRooted michael@0: { michael@0: }; michael@0: michael@0: template class MaybeRooted michael@0: { michael@0: public: michael@0: typedef JS::Handle HandleType; michael@0: typedef JS::Rooted RootType; michael@0: typedef JS::MutableHandle MutableHandleType; michael@0: michael@0: static inline JS::Handle toHandle(HandleType v) { michael@0: return v; michael@0: } michael@0: michael@0: static inline JS::MutableHandle toMutableHandle(MutableHandleType v) { michael@0: return v; michael@0: } michael@0: }; michael@0: michael@0: template class MaybeRooted michael@0: { michael@0: public: michael@0: typedef T HandleType; michael@0: typedef FakeRooted RootType; michael@0: typedef FakeMutableHandle MutableHandleType; michael@0: michael@0: static inline JS::Handle toHandle(HandleType v) { michael@0: MOZ_ASSUME_UNREACHABLE("Bad conversion"); michael@0: } michael@0: michael@0: static inline JS::MutableHandle toMutableHandle(MutableHandleType v) { michael@0: MOZ_ASSUME_UNREACHABLE("Bad conversion"); michael@0: } michael@0: }; michael@0: michael@0: } /* namespace js */ michael@0: michael@0: namespace JS { michael@0: michael@0: template template michael@0: inline michael@0: Handle::Handle(const Rooted &root, michael@0: typename mozilla::EnableIf::value, int>::Type dummy) michael@0: { michael@0: ptr = reinterpret_cast(root.address()); michael@0: } michael@0: michael@0: template template michael@0: inline michael@0: Handle::Handle(const PersistentRooted &root, michael@0: typename mozilla::EnableIf::value, int>::Type dummy) michael@0: { michael@0: ptr = reinterpret_cast(root.address()); michael@0: } michael@0: michael@0: template template michael@0: inline michael@0: Handle::Handle(MutableHandle &root, michael@0: typename mozilla::EnableIf::value, int>::Type dummy) michael@0: { michael@0: ptr = reinterpret_cast(root.address()); michael@0: } michael@0: michael@0: template michael@0: inline michael@0: MutableHandle::MutableHandle(Rooted *root) michael@0: { michael@0: static_assert(sizeof(MutableHandle) == sizeof(T *), michael@0: "MutableHandle must be binary compatible with T*."); michael@0: ptr = root->address(); michael@0: } michael@0: michael@0: template michael@0: inline michael@0: MutableHandle::MutableHandle(PersistentRooted *root) michael@0: { michael@0: static_assert(sizeof(MutableHandle) == sizeof(T *), michael@0: "MutableHandle must be binary compatible with T*."); michael@0: ptr = root->address(); michael@0: } michael@0: michael@0: /* michael@0: * A copyable, assignable global GC root type with arbitrary lifetime, an michael@0: * infallible constructor, and automatic unrooting on destruction. michael@0: * michael@0: * These roots can be used in heap-allocated data structures, so they are not michael@0: * associated with any particular JSContext or stack. They are registered with michael@0: * the JSRuntime itself, without locking, so they require a full JSContext to be michael@0: * constructed, not one of its more restricted superclasses. michael@0: * michael@0: * Note that you must not use an PersistentRooted in an object owned by a JS michael@0: * object: michael@0: * michael@0: * Whenever one object whose lifetime is decided by the GC refers to another michael@0: * such object, that edge must be traced only if the owning JS object is traced. michael@0: * This applies not only to JS objects (which obviously are managed by the GC) michael@0: * but also to C++ objects owned by JS objects. michael@0: * michael@0: * If you put a PersistentRooted in such a C++ object, that is almost certainly michael@0: * a leak. When a GC begins, the referent of the PersistentRooted is treated as michael@0: * live, unconditionally (because a PersistentRooted is a *root*), even if the michael@0: * JS object that owns it is unreachable. If there is any path from that michael@0: * referent back to the JS object, then the C++ object containing the michael@0: * PersistentRooted will not be destructed, and the whole blob of objects will michael@0: * not be freed, even if there are no references to them from the outside. michael@0: * michael@0: * In the context of Firefox, this is a severe restriction: almost everything in michael@0: * Firefox is owned by some JS object or another, so using PersistentRooted in michael@0: * such objects would introduce leaks. For these kinds of edges, Heap or michael@0: * TenuredHeap would be better types. It's up to the implementor of the type michael@0: * containing Heap or TenuredHeap members to make sure their referents get michael@0: * marked when the object itself is marked. michael@0: */ michael@0: template michael@0: class PersistentRooted : private mozilla::LinkedListElement > { michael@0: friend class mozilla::LinkedList; michael@0: friend class mozilla::LinkedListElement; michael@0: michael@0: friend class js::gc::PersistentRootedMarker; michael@0: michael@0: void registerWithRuntime(JSRuntime *rt) { michael@0: JS::shadow::Runtime *srt = JS::shadow::Runtime::asShadowRuntime(rt); michael@0: srt->getPersistentRootedList().insertBack(this); michael@0: } michael@0: michael@0: public: michael@0: PersistentRooted(JSContext *cx) : ptr(js::GCMethods::initial()) michael@0: { michael@0: registerWithRuntime(js::GetRuntime(cx)); michael@0: } michael@0: michael@0: PersistentRooted(JSContext *cx, T initial) : ptr(initial) michael@0: { michael@0: registerWithRuntime(js::GetRuntime(cx)); michael@0: } michael@0: michael@0: PersistentRooted(JSRuntime *rt) : ptr(js::GCMethods::initial()) michael@0: { michael@0: registerWithRuntime(rt); michael@0: } michael@0: michael@0: PersistentRooted(JSRuntime *rt, T initial) : ptr(initial) michael@0: { michael@0: registerWithRuntime(rt); michael@0: } michael@0: michael@0: PersistentRooted(PersistentRooted &rhs) : ptr(rhs.ptr) michael@0: { michael@0: /* michael@0: * Copy construction takes advantage of the fact that the original michael@0: * is already inserted, and simply adds itself to whatever list the michael@0: * original was on - no JSRuntime pointer needed. michael@0: */ michael@0: rhs.setNext(this); michael@0: } michael@0: michael@0: /* michael@0: * Important: Return a reference here so passing a Rooted to michael@0: * something that takes a |const T&| is not a GC hazard. michael@0: */ michael@0: operator const T&() const { return ptr; } michael@0: T operator->() const { return ptr; } michael@0: T *address() { return &ptr; } michael@0: const T *address() const { return &ptr; } michael@0: T &get() { return ptr; } michael@0: const T &get() const { return ptr; } michael@0: michael@0: T &operator=(T value) { michael@0: MOZ_ASSERT(!js::GCMethods::poisoned(value)); michael@0: ptr = value; michael@0: return ptr; michael@0: } michael@0: michael@0: T &operator=(const PersistentRooted &value) { michael@0: ptr = value; michael@0: return ptr; michael@0: } michael@0: michael@0: void set(T value) { michael@0: MOZ_ASSERT(!js::GCMethods::poisoned(value)); michael@0: ptr = value; michael@0: } michael@0: michael@0: bool operator!=(const T &other) const { return ptr != other; } michael@0: bool operator==(const T &other) const { return ptr == other; } michael@0: michael@0: private: michael@0: T ptr; michael@0: }; michael@0: michael@0: } /* namespace JS */ michael@0: michael@0: namespace js { michael@0: michael@0: /* Base class for automatic read-only object rooting during compilation. */ michael@0: class CompilerRootNode michael@0: { michael@0: protected: michael@0: CompilerRootNode(js::gc::Cell *ptr) : next(nullptr), ptr_(ptr) {} michael@0: michael@0: public: michael@0: void **address() { return (void **)&ptr_; } michael@0: michael@0: public: michael@0: CompilerRootNode *next; michael@0: michael@0: protected: michael@0: js::gc::Cell *ptr_; michael@0: }; michael@0: michael@0: } /* namespace js */ michael@0: michael@0: #endif /* js_RootingAPI_h */