Differential D3143 Diff 14286 ps/trunk/libraries/source/spidermonkey/include-win32-debug/js/RootingAPI.h
Changeset View
Changeset View
Standalone View
Standalone View
ps/trunk/libraries/source/spidermonkey/include-win32-debug/js/RootingAPI.h
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*- | /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- | ||||
* vim: set ts=8 sts=4 et sw=4 tw=99: | * vim: set ts=8 sts=2 et sw=2 tw=80: | ||||
* This Source Code Form is subject to the terms of the Mozilla Public | * This Source Code Form is subject to the terms of the Mozilla Public | ||||
* License, v. 2.0. If a copy of the MPL was not distributed with this | * License, v. 2.0. If a copy of the MPL was not distributed with this | ||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */ | * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ | ||||
#ifndef js_RootingAPI_h | #ifndef js_RootingAPI_h | ||||
#define js_RootingAPI_h | #define js_RootingAPI_h | ||||
#include "mozilla/Attributes.h" | #include "mozilla/Attributes.h" | ||||
#include "mozilla/DebugOnly.h" | #include "mozilla/DebugOnly.h" | ||||
#include "mozilla/GuardObjects.h" | #include "mozilla/GuardObjects.h" | ||||
#include "mozilla/LinkedList.h" | #include "mozilla/LinkedList.h" | ||||
#include "mozilla/Move.h" | #include "mozilla/Move.h" | ||||
#include "mozilla/TypeTraits.h" | #include "mozilla/TypeTraits.h" | ||||
#include <type_traits> | #include <type_traits> | ||||
#include "jspubtd.h" | #include "jspubtd.h" | ||||
#include "js/GCAnnotations.h" | #include "js/GCAnnotations.h" | ||||
#include "js/GCPolicyAPI.h" | #include "js/GCPolicyAPI.h" | ||||
#include "js/HeapAPI.h" | #include "js/HeapAPI.h" | ||||
#include "js/ProfilingStack.h" | #include "js/ProfilingStack.h" | ||||
#include "js/Realm.h" | |||||
#include "js/TypeDecls.h" | #include "js/TypeDecls.h" | ||||
#include "js/UniquePtr.h" | #include "js/UniquePtr.h" | ||||
#include "js/Utility.h" | #include "js/Utility.h" | ||||
/* | /* | ||||
* [SMDOC] Stack Rooting | |||||
* | |||||
* Moving GC Stack Rooting | * Moving GC Stack Rooting | ||||
* | * | ||||
* A moving GC may change the physical location of GC allocated things, even | * A moving GC may change the physical location of GC allocated things, even | ||||
* when they are rooted, updating all pointers to the thing to refer to its new | * when they are rooted, updating all pointers to the thing to refer to its new | ||||
* location. The GC must therefore know about all live pointers to a thing, | * location. The GC must therefore know about all live pointers to a thing, | ||||
* not just one of them, in order to behave correctly. | * not just one of them, in order to behave correctly. | ||||
* | * | ||||
* The |Rooted| and |Handle| classes below are used to root stack locations | * The |Rooted| and |Handle| classes below are used to root stack locations | ||||
▲ Show 20 Lines • Show All 133 Lines • ▼ Show 20 Lines | |||||
// operator= on the derived class. Thus, define the operator= directly on the | // operator= on the derived class. Thus, define the operator= directly on the | ||||
// class as we would need to manually pass it through anyway. | // class as we would need to manually pass it through anyway. | ||||
#define DECLARE_POINTER_ASSIGN_OPS(Wrapper, T) \ | #define DECLARE_POINTER_ASSIGN_OPS(Wrapper, T) \ | ||||
Wrapper<T>& operator=(const T& p) { \ | Wrapper<T>& operator=(const T& p) { \ | ||||
set(p); \ | set(p); \ | ||||
return *this; \ | return *this; \ | ||||
} \ | } \ | ||||
Wrapper<T>& operator=(T&& p) { \ | Wrapper<T>& operator=(T&& p) { \ | ||||
set(mozilla::Move(p)); \ | set(std::move(p)); \ | ||||
return *this; \ | return *this; \ | ||||
} \ | } \ | ||||
Wrapper<T>& operator=(const Wrapper<T>& other) { \ | Wrapper<T>& operator=(const Wrapper<T>& other) { \ | ||||
set(other.get()); \ | set(other.get()); \ | ||||
return *this; \ | return *this; \ | ||||
} | } | ||||
#define DELETE_ASSIGNMENT_OPS(Wrapper, T) \ | #define DELETE_ASSIGNMENT_OPS(Wrapper, T) \ | ||||
Show All 13 Lines | |||||
namespace JS { | namespace JS { | ||||
template <typename T> | template <typename T> | ||||
class Rooted; | class Rooted; | ||||
template <typename T> | template <typename T> | ||||
class PersistentRooted; | class PersistentRooted; | ||||
/* This is exposing internal state of the GC for inlining purposes. */ | JS_FRIEND_API void HeapObjectWriteBarriers(JSObject** objp, JSObject* prev, | ||||
JS_FRIEND_API bool isGCEnabled(); | |||||
JS_FRIEND_API void HeapObjectPostBarrier(JSObject** objp, JSObject* prev, | |||||
JSObject* next); | JSObject* next); | ||||
JS_FRIEND_API void HeapStringPostBarrier(JSString** objp, JSString* prev, | JS_FRIEND_API void HeapStringWriteBarriers(JSString** objp, JSString* prev, | ||||
JSString* next); | JSString* next); | ||||
JS_FRIEND_API void HeapScriptWriteBarriers(JSScript** objp, JSScript* prev, | |||||
JSScript* next); | |||||
/** | |||||
* Create a safely-initialized |T|, suitable for use as a default value in | |||||
* situations requiring a safe but arbitrary |T| value. | |||||
*/ | |||||
template <typename T> | |||||
inline T SafelyInitialized() { | |||||
// This function wants to presume that |T()| -- which value-initializes a | |||||
// |T| per C++11 [expr.type.conv]p2 -- will produce a safely-initialized, | |||||
// safely-usable T that it can return. | |||||
#if defined(XP_WIN) || defined(XP_MACOSX) || \ | |||||
(defined(XP_UNIX) && !defined(__clang__)) | |||||
// That presumption holds for pointers, where value initialization produces | |||||
// a null pointer. | |||||
constexpr bool IsPointer = std::is_pointer<T>::value; | |||||
// For classes and unions we *assume* that if |T|'s default constructor is | |||||
// non-trivial it'll initialize correctly. (This is unideal, but C++ | |||||
// doesn't offer a type trait indicating whether a class's constructor is | |||||
// user-defined, which better approximates our desired semantics.) | |||||
constexpr bool IsNonTriviallyDefaultConstructibleClassOrUnion = | |||||
(std::is_class<T>::value || std::is_union<T>::value) && | |||||
!std::is_trivially_default_constructible<T>::value; | |||||
static_assert(IsPointer || IsNonTriviallyDefaultConstructibleClassOrUnion, | |||||
"T() must evaluate to a safely-initialized T"); | |||||
#endif | |||||
return T(); | |||||
} | |||||
#ifdef JS_DEBUG | #ifdef JS_DEBUG | ||||
/** | /** | ||||
* For generational GC, assert that an object is in the tenured generation as | * For generational GC, assert that an object is in the tenured generation as | ||||
* opposed to being in the nursery. | * opposed to being in the nursery. | ||||
*/ | */ | ||||
extern JS_FRIEND_API void AssertGCThingMustBeTenured(JSObject* obj); | extern JS_FRIEND_API void AssertGCThingMustBeTenured(JSObject* obj); | ||||
extern JS_FRIEND_API void AssertGCThingIsNotNurseryAllocable( | extern JS_FRIEND_API void AssertGCThingIsNotNurseryAllocable( | ||||
js::gc::Cell* cell); | js::gc::Cell* cell); | ||||
#else | #else | ||||
inline void AssertGCThingMustBeTenured(JSObject* obj) {} | inline void AssertGCThingMustBeTenured(JSObject* obj) {} | ||||
inline void AssertGCThingIsNotNurseryAllocable(js::gc::Cell* cell) {} | inline void AssertGCThingIsNotNurseryAllocable(js::gc::Cell* cell) {} | ||||
#endif | #endif | ||||
/** | /** | ||||
* The Heap<T> class is a heap-stored reference to a JS GC thing. All members of | * The Heap<T> class is a heap-stored reference to a JS GC thing for use outside | ||||
* heap classes that refer to GC things should use Heap<T> (or possibly | * the JS engine. All members of heap classes that refer to GC things should use | ||||
* TenuredHeap<T>, described below). | * Heap<T> (or possibly TenuredHeap<T>, described below). | ||||
* | * | ||||
* Heap<T> is an abstraction that hides some of the complexity required to | * Heap<T> is an abstraction that hides some of the complexity required to | ||||
* maintain GC invariants for the contained reference. It uses operator | * maintain GC invariants for the contained reference. It uses operator | ||||
* overloading to provide a normal pointer interface, but notifies the GC every | * overloading to provide a normal pointer interface, but adds barriers to | ||||
* time the value it contains is updated. This is necessary for generational GC, | * notify the GC of changes. | ||||
* which keeps track of all pointers into the nursery. | * | ||||
* Heap<T> implements the following barriers: | |||||
* | |||||
* - Pre-write barrier (necessary for incremental GC). | |||||
* - Post-write barrier (necessary for generational GC). | |||||
* - Read barrier (necessary for cycle collector integration). | |||||
* | |||||
* Heap<T> may be moved or destroyed outside of GC finalization and hence may be | |||||
* used in dynamic storage such as a Vector. | |||||
* | * | ||||
* Heap<T> instances must be traced when their containing object is traced to | * Heap<T> instances must be traced when their containing object is traced to | ||||
* keep the pointed-to GC thing alive. | * keep the pointed-to GC thing alive. | ||||
* | * | ||||
* Heap<T> objects should only be used on the heap. GC references stored on the | * Heap<T> objects should only be used on the heap. GC references stored on the | ||||
* C/C++ stack must use Rooted/Handle/MutableHandle instead. | * C/C++ stack must use Rooted/Handle/MutableHandle instead. | ||||
* | * | ||||
* Type T must be a public GC pointer type. | * Type T must be a public GC pointer type. | ||||
*/ | */ | ||||
template <typename T> | template <typename T> | ||||
class MOZ_NON_MEMMOVABLE Heap : public js::HeapBase<T, Heap<T>> { | class MOZ_NON_MEMMOVABLE Heap : public js::HeapBase<T, Heap<T>> { | ||||
// Please note: this can actually also be used by nsXBLMaybeCompiled<T>, for | // Please note: this can actually also be used by nsXBLMaybeCompiled<T>, for | ||||
// legacy reasons. | // legacy reasons. | ||||
static_assert(js::IsHeapConstructibleType<T>::value, | static_assert(js::IsHeapConstructibleType<T>::value, | ||||
"Type T must be a public GC pointer type"); | "Type T must be a public GC pointer type"); | ||||
public: | public: | ||||
using ElementType = T; | using ElementType = T; | ||||
Heap() { | Heap() : ptr(SafelyInitialized<T>()) { | ||||
// No barriers are required for initialization to the default value. | |||||
static_assert(sizeof(T) == sizeof(Heap<T>), | static_assert(sizeof(T) == sizeof(Heap<T>), | ||||
"Heap<T> must be binary compatible with T."); | "Heap<T> must be binary compatible with T."); | ||||
init(GCPolicy<T>::initial()); | |||||
} | } | ||||
explicit Heap(const T& p) { init(p); } | explicit Heap(const T& p) { init(p); } | ||||
/* | /* | ||||
* For Heap, move semantics are equivalent to copy semantics. In C++, a | * For Heap, move semantics are equivalent to copy semantics. In C++, a | ||||
* copy constructor taking const-ref is the way to get a single function | * copy constructor taking const-ref is the way to get a single function | ||||
* that will be used for both lvalue and rvalue copies, so we can simply | * that will be used for both lvalue and rvalue copies, so we can simply | ||||
* omit the rvalue variant. | * omit the rvalue variant. | ||||
*/ | */ | ||||
explicit Heap(const Heap<T>& p) { init(p.ptr); } | explicit Heap(const Heap<T>& p) { init(p.ptr); } | ||||
~Heap() { post(ptr, GCPolicy<T>::initial()); } | ~Heap() { writeBarriers(ptr, SafelyInitialized<T>()); } | ||||
DECLARE_POINTER_CONSTREF_OPS(T); | DECLARE_POINTER_CONSTREF_OPS(T); | ||||
DECLARE_POINTER_ASSIGN_OPS(Heap, T); | DECLARE_POINTER_ASSIGN_OPS(Heap, T); | ||||
const T* address() const { return &ptr; } | const T* address() const { return &ptr; } | ||||
void exposeToActiveJS() const { js::BarrierMethods<T>::exposeToJS(ptr); } | void exposeToActiveJS() const { js::BarrierMethods<T>::exposeToJS(ptr); } | ||||
const T& get() const { | const T& get() const { | ||||
exposeToActiveJS(); | exposeToActiveJS(); | ||||
return ptr; | return ptr; | ||||
} | } | ||||
const T& unbarrieredGet() const { return ptr; } | const T& unbarrieredGet() const { return ptr; } | ||||
T* unsafeGet() { return &ptr; } | T* unsafeGet() { return &ptr; } | ||||
void unbarrieredSet(const T& newPtr) { ptr = newPtr; } | |||||
explicit operator bool() const { | explicit operator bool() const { | ||||
return bool(js::BarrierMethods<T>::asGCThingOrNull(ptr)); | return bool(js::BarrierMethods<T>::asGCThingOrNull(ptr)); | ||||
} | } | ||||
explicit operator bool() { | explicit operator bool() { | ||||
return bool(js::BarrierMethods<T>::asGCThingOrNull(ptr)); | return bool(js::BarrierMethods<T>::asGCThingOrNull(ptr)); | ||||
} | } | ||||
private: | private: | ||||
void init(const T& newPtr) { | void init(const T& newPtr) { | ||||
ptr = newPtr; | ptr = newPtr; | ||||
post(GCPolicy<T>::initial(), ptr); | writeBarriers(SafelyInitialized<T>(), ptr); | ||||
} | } | ||||
void set(const T& newPtr) { | void set(const T& newPtr) { | ||||
T tmp = ptr; | T tmp = ptr; | ||||
ptr = newPtr; | ptr = newPtr; | ||||
post(tmp, ptr); | writeBarriers(tmp, ptr); | ||||
} | } | ||||
void post(const T& prev, const T& next) { | void writeBarriers(const T& prev, const T& next) { | ||||
js::BarrierMethods<T>::postBarrier(&ptr, prev, next); | js::BarrierMethods<T>::writeBarriers(&ptr, prev, next); | ||||
} | } | ||||
T ptr; | T ptr; | ||||
}; | }; | ||||
static MOZ_ALWAYS_INLINE bool ObjectIsTenured(JSObject* obj) { | static MOZ_ALWAYS_INLINE bool ObjectIsTenured(JSObject* obj) { | ||||
return !js::gc::IsInsideNursery(reinterpret_cast<js::gc::Cell*>(obj)); | return !js::gc::IsInsideNursery(reinterpret_cast<js::gc::Cell*>(obj)); | ||||
} | } | ||||
static MOZ_ALWAYS_INLINE bool ObjectIsTenured(const Heap<JSObject*>& obj) { | static MOZ_ALWAYS_INLINE bool ObjectIsTenured(const Heap<JSObject*>& obj) { | ||||
return ObjectIsTenured(obj.unbarrieredGet()); | return ObjectIsTenured(obj.unbarrieredGet()); | ||||
} | } | ||||
static MOZ_ALWAYS_INLINE bool ObjectIsMarkedGray(JSObject* obj) { | static MOZ_ALWAYS_INLINE bool ObjectIsMarkedGray(JSObject* obj) { | ||||
auto cell = reinterpret_cast<js::gc::Cell*>(obj); | auto cell = reinterpret_cast<js::gc::Cell*>(obj); | ||||
return js::gc::detail::CellIsMarkedGrayIfKnown(cell); | return js::gc::detail::CellIsMarkedGrayIfKnown(cell); | ||||
} | } | ||||
static MOZ_ALWAYS_INLINE bool ObjectIsMarkedGray( | static MOZ_ALWAYS_INLINE bool ObjectIsMarkedGray( | ||||
const JS::Heap<JSObject*>& obj) { | const JS::Heap<JSObject*>& obj) { | ||||
return ObjectIsMarkedGray(obj.unbarrieredGet()); | return ObjectIsMarkedGray(obj.unbarrieredGet()); | ||||
} | } | ||||
// The following *IsNotGray functions are for use in assertions and take account | // The following *IsNotGray functions take account of the eventual | ||||
// of the eventual gray marking state at the end of any ongoing incremental GC. | // gray marking state at the end of any ongoing incremental GC by | ||||
// delaying the checks if necessary. | |||||
#ifdef DEBUG | #ifdef DEBUG | ||||
inline bool CellIsNotGray(js::gc::Cell* maybeCell) { | |||||
if (!maybeCell) return true; | |||||
return js::gc::detail::CellIsNotGray(maybeCell); | inline void AssertCellIsNotGray(const js::gc::Cell* maybeCell) { | ||||
if (maybeCell) { | |||||
js::gc::detail::AssertCellIsNotGray(maybeCell); | |||||
} | |||||
} | } | ||||
inline bool ObjectIsNotGray(JSObject* maybeObj) { | inline void AssertObjectIsNotGray(JSObject* maybeObj) { | ||||
return CellIsNotGray(reinterpret_cast<js::gc::Cell*>(maybeObj)); | AssertCellIsNotGray(reinterpret_cast<js::gc::Cell*>(maybeObj)); | ||||
} | } | ||||
inline bool ObjectIsNotGray(const JS::Heap<JSObject*>& obj) { | inline void AssertObjectIsNotGray(const JS::Heap<JSObject*>& obj) { | ||||
return ObjectIsNotGray(obj.unbarrieredGet()); | AssertObjectIsNotGray(obj.unbarrieredGet()); | ||||
} | } | ||||
#else | |||||
inline void AssertCellIsNotGray(js::gc::Cell* maybeCell) {} | |||||
inline void AssertObjectIsNotGray(JSObject* maybeObj) {} | |||||
inline void AssertObjectIsNotGray(const JS::Heap<JSObject*>& obj) {} | |||||
#endif | #endif | ||||
/** | /** | ||||
* The TenuredHeap<T> class is similar to the Heap<T> class above in that it | * The TenuredHeap<T> class is similar to the Heap<T> class above in that it | ||||
* encapsulates the GC concerns of an on-heap reference to a JS object. However, | * encapsulates the GC concerns of an on-heap reference to a JS object. However, | ||||
* it has two important differences: | * it has two important differences: | ||||
* | * | ||||
* 1) Pointers which are statically known to only reference "tenured" objects | * 1) Pointers which are statically known to only reference "tenured" objects | ||||
Show All 28 Lines | public: | ||||
TenuredHeap() : bits(0) { | TenuredHeap() : bits(0) { | ||||
static_assert(sizeof(T) == sizeof(TenuredHeap<T>), | static_assert(sizeof(T) == sizeof(TenuredHeap<T>), | ||||
"TenuredHeap<T> must be binary compatible with T."); | "TenuredHeap<T> must be binary compatible with T."); | ||||
} | } | ||||
explicit TenuredHeap(T p) : bits(0) { setPtr(p); } | explicit TenuredHeap(T p) : bits(0) { setPtr(p); } | ||||
explicit TenuredHeap(const TenuredHeap<T>& p) : bits(0) { | explicit TenuredHeap(const TenuredHeap<T>& p) : bits(0) { | ||||
setPtr(p.getPtr()); | setPtr(p.getPtr()); | ||||
} | } | ||||
~TenuredHeap() { pre(); } | |||||
void setPtr(T newPtr) { | void setPtr(T newPtr) { | ||||
MOZ_ASSERT((reinterpret_cast<uintptr_t>(newPtr) & flagsMask) == 0); | MOZ_ASSERT((reinterpret_cast<uintptr_t>(newPtr) & flagsMask) == 0); | ||||
MOZ_ASSERT(js::gc::IsCellPointerValidOrNull(newPtr)); | MOZ_ASSERT(js::gc::IsCellPointerValidOrNull(newPtr)); | ||||
if (newPtr) AssertGCThingMustBeTenured(newPtr); | if (newPtr) { | ||||
AssertGCThingMustBeTenured(newPtr); | |||||
} | |||||
pre(); | |||||
unbarrieredSetPtr(newPtr); | |||||
} | |||||
void unbarrieredSetPtr(T newPtr) { | |||||
bits = (bits & flagsMask) | reinterpret_cast<uintptr_t>(newPtr); | bits = (bits & flagsMask) | reinterpret_cast<uintptr_t>(newPtr); | ||||
} | } | ||||
void setFlags(uintptr_t flagsToSet) { | void setFlags(uintptr_t flagsToSet) { | ||||
MOZ_ASSERT((flagsToSet & ~flagsMask) == 0); | MOZ_ASSERT((flagsToSet & ~flagsMask) == 0); | ||||
bits |= flagsToSet; | bits |= flagsToSet; | ||||
} | } | ||||
Show All 39 Lines | public: | ||||
} | } | ||||
private: | private: | ||||
enum { | enum { | ||||
maskBits = 3, | maskBits = 3, | ||||
flagsMask = (1 << maskBits) - 1, | flagsMask = (1 << maskBits) - 1, | ||||
}; | }; | ||||
void pre() { | |||||
if (T prev = unbarrieredGetPtr()) { | |||||
JS::IncrementalPreWriteBarrier(JS::GCCellPtr(prev)); | |||||
} | |||||
} | |||||
uintptr_t bits; | uintptr_t bits; | ||||
}; | }; | ||||
static MOZ_ALWAYS_INLINE bool ObjectIsMarkedGray( | |||||
const JS::TenuredHeap<JSObject*>& obj) { | |||||
return ObjectIsMarkedGray(obj.unbarrieredGetPtr()); | |||||
} | |||||
/** | /** | ||||
* Reference to a T that has been rooted elsewhere. This is most useful | * Reference to a T that has been rooted elsewhere. This is most useful | ||||
* as a parameter type, which guarantees that the T lvalue is properly | * as a parameter type, which guarantees that the T lvalue is properly | ||||
* rooted. See "Move GC Stack Rooting" above. | * rooted. See "Move GC Stack Rooting" above. | ||||
* | * | ||||
* If you want to add additional methods to Handle for a specific | * If you want to add additional methods to Handle for a specific | ||||
* specialization, define a HandleBase<T> specialization containing them. | * specialization, define a HandleBase<T> specialization containing them. | ||||
*/ | */ | ||||
▲ Show 20 Lines • Show All 103 Lines • ▼ Show 20 Lines | private: | ||||
MutableHandle(decltype(nullptr)) = delete; | MutableHandle(decltype(nullptr)) = delete; | ||||
public: | public: | ||||
void set(const T& v) { | void set(const T& v) { | ||||
*ptr = v; | *ptr = v; | ||||
MOZ_ASSERT(GCPolicy<T>::isValid(*ptr)); | MOZ_ASSERT(GCPolicy<T>::isValid(*ptr)); | ||||
} | } | ||||
void set(T&& v) { | void set(T&& v) { | ||||
*ptr = mozilla::Move(v); | *ptr = std::move(v); | ||||
MOZ_ASSERT(GCPolicy<T>::isValid(*ptr)); | MOZ_ASSERT(GCPolicy<T>::isValid(*ptr)); | ||||
} | } | ||||
/* | /* | ||||
* This may be called only if the location of the T is guaranteed | * This may be called only if the location of the T is guaranteed | ||||
* to be marked (for some reason other than being a Rooted), | * to be marked (for some reason other than being a Rooted), | ||||
* e.g., if it is guaranteed to be reachable from an implicit root. | * e.g., if it is guaranteed to be reachable from an implicit root. | ||||
* | * | ||||
Show All 15 Lines | private: | ||||
T* ptr; | T* ptr; | ||||
}; | }; | ||||
} /* namespace JS */ | } /* namespace JS */ | ||||
namespace js { | namespace js { | ||||
namespace detail { | |||||
// Default implementations for barrier methods on GC thing pointers. | |||||
template <typename T> | template <typename T> | ||||
struct BarrierMethods<T*> { | struct PtrBarrierMethodsBase { | ||||
static T* initial() { return nullptr; } | static T* initial() { return nullptr; } | ||||
static gc::Cell* asGCThingOrNull(T* v) { | static gc::Cell* asGCThingOrNull(T* v) { | ||||
if (!v) return nullptr; | if (!v) { | ||||
return nullptr; | |||||
} | |||||
MOZ_ASSERT(uintptr_t(v) > 32); | MOZ_ASSERT(uintptr_t(v) > 32); | ||||
return reinterpret_cast<gc::Cell*>(v); | return reinterpret_cast<gc::Cell*>(v); | ||||
} | } | ||||
static void postBarrier(T** vp, T* prev, T* next) { | static void exposeToJS(T* t) { | ||||
if (next) | if (t) { | ||||
js::gc::ExposeGCThingToActiveJS(JS::GCCellPtr(t)); | |||||
} | |||||
} | |||||
}; | |||||
} // namespace detail | |||||
template <typename T> | |||||
struct BarrierMethods<T*> : public detail::PtrBarrierMethodsBase<T> { | |||||
static void writeBarriers(T** vp, T* prev, T* next) { | |||||
if (prev) { | |||||
JS::IncrementalPreWriteBarrier(JS::GCCellPtr(prev)); | |||||
} | |||||
if (next) { | |||||
JS::AssertGCThingIsNotNurseryAllocable( | JS::AssertGCThingIsNotNurseryAllocable( | ||||
reinterpret_cast<js::gc::Cell*>(next)); | reinterpret_cast<js::gc::Cell*>(next)); | ||||
} | } | ||||
static void exposeToJS(T* t) { | |||||
if (t) js::gc::ExposeGCThingToActiveJS(JS::GCCellPtr(t)); | |||||
} | } | ||||
}; | }; | ||||
template <> | template <> | ||||
struct BarrierMethods<JSObject*> { | struct BarrierMethods<JSObject*> | ||||
static JSObject* initial() { return nullptr; } | : public detail::PtrBarrierMethodsBase<JSObject> { | ||||
static gc::Cell* asGCThingOrNull(JSObject* v) { | static void writeBarriers(JSObject** vp, JSObject* prev, JSObject* next) { | ||||
if (!v) return nullptr; | JS::HeapObjectWriteBarriers(vp, prev, next); | ||||
MOZ_ASSERT(uintptr_t(v) > 32); | |||||
return reinterpret_cast<gc::Cell*>(v); | |||||
} | |||||
static void postBarrier(JSObject** vp, JSObject* prev, JSObject* next) { | |||||
JS::HeapObjectPostBarrier(vp, prev, next); | |||||
} | } | ||||
static void exposeToJS(JSObject* obj) { | static void exposeToJS(JSObject* obj) { | ||||
if (obj) JS::ExposeObjectToActiveJS(obj); | if (obj) { | ||||
JS::ExposeObjectToActiveJS(obj); | |||||
} | |||||
} | } | ||||
}; | }; | ||||
template <> | template <> | ||||
struct BarrierMethods<JSFunction*> { | struct BarrierMethods<JSFunction*> | ||||
static JSFunction* initial() { return nullptr; } | : public detail::PtrBarrierMethodsBase<JSFunction> { | ||||
static gc::Cell* asGCThingOrNull(JSFunction* v) { | static void writeBarriers(JSFunction** vp, JSFunction* prev, | ||||
if (!v) return nullptr; | JSFunction* next) { | ||||
MOZ_ASSERT(uintptr_t(v) > 32); | JS::HeapObjectWriteBarriers(reinterpret_cast<JSObject**>(vp), | ||||
return reinterpret_cast<gc::Cell*>(v); | |||||
} | |||||
static void postBarrier(JSFunction** vp, JSFunction* prev, JSFunction* next) { | |||||
JS::HeapObjectPostBarrier(reinterpret_cast<JSObject**>(vp), | |||||
reinterpret_cast<JSObject*>(prev), | reinterpret_cast<JSObject*>(prev), | ||||
reinterpret_cast<JSObject*>(next)); | reinterpret_cast<JSObject*>(next)); | ||||
} | } | ||||
static void exposeToJS(JSFunction* fun) { | static void exposeToJS(JSFunction* fun) { | ||||
if (fun) JS::ExposeObjectToActiveJS(reinterpret_cast<JSObject*>(fun)); | if (fun) { | ||||
JS::ExposeObjectToActiveJS(reinterpret_cast<JSObject*>(fun)); | |||||
} | |||||
} | } | ||||
}; | }; | ||||
template <> | template <> | ||||
struct BarrierMethods<JSString*> { | struct BarrierMethods<JSString*> | ||||
static JSString* initial() { return nullptr; } | : public detail::PtrBarrierMethodsBase<JSString> { | ||||
static gc::Cell* asGCThingOrNull(JSString* v) { | static void writeBarriers(JSString** vp, JSString* prev, JSString* next) { | ||||
if (!v) return nullptr; | JS::HeapStringWriteBarriers(vp, prev, next); | ||||
MOZ_ASSERT(uintptr_t(v) > 32); | |||||
return reinterpret_cast<gc::Cell*>(v); | |||||
} | |||||
static void postBarrier(JSString** vp, JSString* prev, JSString* next) { | |||||
JS::HeapStringPostBarrier(vp, prev, next); | |||||
} | } | ||||
static void exposeToJS(JSString* v) { | }; | ||||
if (v) js::gc::ExposeGCThingToActiveJS(JS::GCCellPtr(v)); | |||||
template <> | |||||
struct BarrierMethods<JSScript*> | |||||
: public detail::PtrBarrierMethodsBase<JSScript> { | |||||
static void writeBarriers(JSScript** vp, JSScript* prev, JSScript* next) { | |||||
JS::HeapScriptWriteBarriers(vp, prev, next); | |||||
} | } | ||||
}; | }; | ||||
// Provide hash codes for Cell kinds that may be relocated and, thus, not have | // Provide hash codes for Cell kinds that may be relocated and, thus, not have | ||||
// a stable address to use as the base for a hash code. Instead of the address, | // a stable address to use as the base for a hash code. Instead of the address, | ||||
// this hasher uses Cell::getUniqueId to provide exact matches and as a base | // this hasher uses Cell::getUniqueId to provide exact matches and as a base | ||||
// for generating hash codes. | // for generating hash codes. | ||||
// | // | ||||
Show All 30 Lines | static HashNumber hash(const Lookup& l) { | ||||
return MovableCellHasher<T>::hash(l); | return MovableCellHasher<T>::hash(l); | ||||
} | } | ||||
static bool match(const Key& k, const Lookup& l) { | static bool match(const Key& k, const Lookup& l) { | ||||
return MovableCellHasher<T>::match(k.unbarrieredGet(), l); | return MovableCellHasher<T>::match(k.unbarrieredGet(), l); | ||||
} | } | ||||
static void rekey(Key& k, const Key& newKey) { k.unsafeSet(newKey); } | static void rekey(Key& k, const Key& newKey) { k.unsafeSet(newKey); } | ||||
}; | }; | ||||
} // namespace js | |||||
namespace mozilla { | |||||
template <typename T> | template <typename T> | ||||
struct FallibleHashMethods<MovableCellHasher<T>> { | struct FallibleHashMethods<js::MovableCellHasher<T>> { | ||||
template <typename Lookup> | template <typename Lookup> | ||||
static bool hasHash(Lookup&& l) { | static bool hasHash(Lookup&& l) { | ||||
return MovableCellHasher<T>::hasHash(mozilla::Forward<Lookup>(l)); | return js::MovableCellHasher<T>::hasHash(std::forward<Lookup>(l)); | ||||
} | } | ||||
template <typename Lookup> | template <typename Lookup> | ||||
static bool ensureHash(Lookup&& l) { | static bool ensureHash(Lookup&& l) { | ||||
return MovableCellHasher<T>::ensureHash(mozilla::Forward<Lookup>(l)); | return js::MovableCellHasher<T>::ensureHash(std::forward<Lookup>(l)); | ||||
} | } | ||||
}; | }; | ||||
} /* namespace js */ | } // namespace mozilla | ||||
namespace js { | namespace js { | ||||
// The alignment must be set because the Rooted and PersistentRooted ptr fields | // The alignment must be set because the Rooted and PersistentRooted ptr fields | ||||
// may be accessed through reinterpret_cast<Rooted<ConcreteTraceable>*>, and | // may be accessed through reinterpret_cast<Rooted<ConcreteTraceable>*>, and | ||||
// the compiler may choose a different alignment for the ptr field when it | // the compiler may choose a different alignment for the ptr field when it | ||||
// knows the actual type stored in DispatchWrapper<T>. | // knows the actual type stored in DispatchWrapper<T>. | ||||
// | // | ||||
// It would make more sense to align only those specific fields of type | // It would make more sense to align only those specific fields of type | ||||
// DispatchWrapper, rather than DispatchWrapper itself, but that causes MSVC to | // DispatchWrapper, rather than DispatchWrapper itself, but that causes MSVC to | ||||
// fail when Rooted is used in an IsConvertible test. | // fail when Rooted is used in an IsConvertible test. | ||||
template <typename T> | template <typename T> | ||||
class alignas(8) DispatchWrapper { | class alignas(8) DispatchWrapper { | ||||
static_assert(JS::MapTypeToRootKind<T>::kind == JS::RootKind::Traceable, | static_assert(JS::MapTypeToRootKind<T>::kind == JS::RootKind::Traceable, | ||||
"DispatchWrapper is intended only for usage with a Traceable"); | "DispatchWrapper is intended only for usage with a Traceable"); | ||||
using TraceFn = void (*)(JSTracer*, T*, const char*); | using TraceFn = void (*)(JSTracer*, T*, const char*); | ||||
TraceFn tracer; | TraceFn tracer; | ||||
alignas(gc::CellAlignBytes) T storage; | alignas(gc::CellAlignBytes) T storage; | ||||
public: | public: | ||||
template <typename U> | template <typename U> | ||||
MOZ_IMPLICIT DispatchWrapper(U&& initial) | MOZ_IMPLICIT DispatchWrapper(U&& initial) | ||||
: tracer(&JS::GCPolicy<T>::trace), | : tracer(&JS::GCPolicy<T>::trace), storage(std::forward<U>(initial)) {} | ||||
storage(mozilla::Forward<U>(initial)) {} | |||||
// Mimic a pointer type, so that we can drop into Rooted. | // Mimic a pointer type, so that we can drop into Rooted. | ||||
T* operator&() { return &storage; } | T* operator&() { return &storage; } | ||||
const T* operator&() const { return &storage; } | const T* operator&() const { return &storage; } | ||||
operator T&() { return storage; } | operator T&() { return storage; } | ||||
operator const T&() const { return storage; } | operator const T&() const { return storage; } | ||||
// Trace the contained storage (of unknown type) using the trace function | // Trace the contained storage (of unknown type) using the trace function | ||||
Show All 30 Lines | class RootingContext { | ||||
friend class JS::Rooted; | friend class JS::Rooted; | ||||
// Stack GC roots for AutoFooRooter classes. | // Stack GC roots for AutoFooRooter classes. | ||||
JS::AutoGCRooter* autoGCRooters_; | JS::AutoGCRooter* autoGCRooters_; | ||||
friend class JS::AutoGCRooter; | friend class JS::AutoGCRooter; | ||||
// Gecko profiling metadata. | // Gecko profiling metadata. | ||||
// This isn't really rooting related. It's only here because we want | // This isn't really rooting related. It's only here because we want | ||||
// GetContextProfilingStack to be inlineable into non-JS code, and we | // GetContextProfilingStackIfEnabled to be inlineable into non-JS code, and | ||||
// didn't want to add another superclass of JSContext just for this. | // we didn't want to add another superclass of JSContext just for this. | ||||
js::GeckoProfilerThread geckoProfiler_; | js::GeckoProfilerThread geckoProfiler_; | ||||
public: | public: | ||||
RootingContext(); | RootingContext(); | ||||
void traceStackRoots(JSTracer* trc); | void traceStackRoots(JSTracer* trc); | ||||
void checkNoGCRooters(); | void checkNoGCRooters(); | ||||
js::GeckoProfilerThread& geckoProfiler() { return geckoProfiler_; } | js::GeckoProfilerThread& geckoProfiler() { return geckoProfiler_; } | ||||
protected: | protected: | ||||
// The remaining members in this class should only be accessed through | // The remaining members in this class should only be accessed through | ||||
// JSContext pointers. They are unrelated to rooting and are in place so | // JSContext pointers. They are unrelated to rooting and are in place so | ||||
// that inlined API functions can directly access the data. | // that inlined API functions can directly access the data. | ||||
/* The current compartment. */ | /* The current realm. */ | ||||
JSCompartment* compartment_; | JS::Realm* realm_; | ||||
/* The current zone. */ | /* The current zone. */ | ||||
JS::Zone* zone_; | JS::Zone* zone_; | ||||
public: | public: | ||||
/* Limit pointer for checking native stack consumption. */ | /* Limit pointer for checking native stack consumption. */ | ||||
uintptr_t nativeStackLimit[StackKindCount]; | uintptr_t nativeStackLimit[StackKindCount]; | ||||
static const RootingContext* get(const JSContext* cx) { | static const RootingContext* get(const JSContext* cx) { | ||||
return reinterpret_cast<const RootingContext*>(cx); | return reinterpret_cast<const RootingContext*>(cx); | ||||
} | } | ||||
static RootingContext* get(JSContext* cx) { | static RootingContext* get(JSContext* cx) { | ||||
return reinterpret_cast<RootingContext*>(cx); | return reinterpret_cast<RootingContext*>(cx); | ||||
} | } | ||||
friend JSCompartment* js::GetContextCompartment(const JSContext* cx); | friend JS::Realm* js::GetContextRealm(const JSContext* cx); | ||||
friend JS::Zone* js::GetContextZone(const JSContext* cx); | friend JS::Zone* js::GetContextZone(const JSContext* cx); | ||||
}; | }; | ||||
class JS_PUBLIC_API AutoGCRooter { | class JS_PUBLIC_API AutoGCRooter { | ||||
protected: | |||||
enum class Tag : uint8_t { | |||||
Array, /* js::AutoArrayRooter */ | |||||
ValueArray, /* js::AutoValueArray */ | |||||
Parser, /* js::frontend::Parser */ | |||||
#if defined(JS_BUILD_BINAST) | |||||
BinASTParser, /* js::frontend::BinASTParser */ | |||||
#endif // defined(JS_BUILD_BINAST) | |||||
WrapperVector, /* js::AutoWrapperVector */ | |||||
Wrapper, /* js::AutoWrapperRooter */ | |||||
Custom /* js::CustomAutoRooter */ | |||||
}; | |||||
public: | public: | ||||
AutoGCRooter(JSContext* cx, ptrdiff_t tag) | AutoGCRooter(JSContext* cx, Tag tag) | ||||
: AutoGCRooter(JS::RootingContext::get(cx), tag) {} | : AutoGCRooter(JS::RootingContext::get(cx), tag) {} | ||||
AutoGCRooter(JS::RootingContext* cx, ptrdiff_t tag) | AutoGCRooter(JS::RootingContext* cx, Tag tag) | ||||
: down(cx->autoGCRooters_), tag_(tag), stackTop(&cx->autoGCRooters_) { | : down(cx->autoGCRooters_), stackTop(&cx->autoGCRooters_), tag_(tag) { | ||||
MOZ_ASSERT(this != *stackTop); | MOZ_ASSERT(this != *stackTop); | ||||
*stackTop = this; | *stackTop = this; | ||||
} | } | ||||
~AutoGCRooter() { | ~AutoGCRooter() { | ||||
MOZ_ASSERT(this == *stackTop); | MOZ_ASSERT(this == *stackTop); | ||||
*stackTop = down; | *stackTop = down; | ||||
} | } | ||||
/* Implemented in gc/RootMarking.cpp. */ | /* Implemented in gc/RootMarking.cpp. */ | ||||
inline void trace(JSTracer* trc); | inline void trace(JSTracer* trc); | ||||
static void traceAll(const js::CooperatingContext& target, JSTracer* trc); | static void traceAll(JSContext* cx, JSTracer* trc); | ||||
static void traceAllWrappers(const js::CooperatingContext& target, | static void traceAllWrappers(JSContext* cx, JSTracer* trc); | ||||
JSTracer* trc); | |||||
protected: | private: | ||||
AutoGCRooter* const down; | AutoGCRooter* const down; | ||||
AutoGCRooter** const stackTop; | |||||
/* | /* | ||||
* Discriminates actual subclass of this being used. If non-negative, the | * Discriminates actual subclass of this being used. The meaning is | ||||
* subclass roots an array of values of the length stored in this field. | * indicated by the corresponding value in the Tag enum. | ||||
* If negative, meaning is indicated by the corresponding value in the enum | |||||
* below. Any other negative value indicates some deeper problem such as | |||||
* memory corruption. | |||||
*/ | */ | ||||
ptrdiff_t tag_; | Tag tag_; | ||||
enum { | |||||
VALARRAY = -2, /* js::AutoValueArray */ | |||||
PARSER = -3, /* js::frontend::Parser */ | |||||
#if defined(JS_BUILD_BINAST) | |||||
BINPARSER = -4, /* js::frontend::BinSource */ | |||||
#endif // defined(JS_BUILD_BINAST) | |||||
IONMASM = -19, /* js::jit::MacroAssembler */ | |||||
WRAPVECTOR = -20, /* js::AutoWrapperVector */ | |||||
WRAPPER = -21, /* js::AutoWrapperRooter */ | |||||
CUSTOM = -26 /* js::CustomAutoRooter */ | |||||
}; | |||||
private: | |||||
AutoGCRooter** const stackTop; | |||||
/* No copy or assignment semantics. */ | /* No copy or assignment semantics. */ | ||||
AutoGCRooter(AutoGCRooter& ida) = delete; | AutoGCRooter(AutoGCRooter& ida) = delete; | ||||
void operator=(AutoGCRooter& ida) = delete; | void operator=(AutoGCRooter& ida) = delete; | ||||
}; | } JS_HAZ_ROOTED_BASE; | ||||
namespace detail { | namespace detail { | ||||
/* | /* | ||||
* For pointer types, the TraceKind for tracing is based on the list it is | * For pointer types, the TraceKind for tracing is based on the list it is | ||||
* in (selected via MapTypeToRootKind), so no additional storage is | * in (selected via MapTypeToRootKind), so no additional storage is | ||||
* required here. Non-pointer types, however, share the same list, so the | * required here. Non-pointer types, however, share the same list, so the | ||||
* function to call for tracing is stored adjacent to the struct. Since C++ | * function to call for tracing is stored adjacent to the struct. Since C++ | ||||
* cannot templatize on storage class, this is implemented via the wrapper | * cannot templatize on storage class, this is implemented via the wrapper | ||||
* class DispatchWrapper. | * class DispatchWrapper. | ||||
*/ | */ | ||||
template <typename T> | template <typename T> | ||||
using MaybeWrapped = | using MaybeWrapped = | ||||
typename mozilla::Conditional<MapTypeToRootKind<T>::kind == | typename mozilla::Conditional<MapTypeToRootKind<T>::kind == | ||||
JS::RootKind::Traceable, | JS::RootKind::Traceable, | ||||
js::DispatchWrapper<T>, T>::Type; | js::DispatchWrapper<T>, T>::Type; | ||||
// Dummy types to make it easier to understand template overload preference | |||||
// ordering. | |||||
struct FallbackOverload {}; | |||||
struct PreferredOverload : FallbackOverload {}; | |||||
using OverloadSelector = PreferredOverload; | |||||
} /* namespace detail */ | } /* namespace detail */ | ||||
/** | /** | ||||
* Local variable of type T whose value is always rooted. This is typically | * Local variable of type T whose value is always rooted. This is typically | ||||
* used for local variables, or for non-rooted values being passed to a | * used for local variables, or for non-rooted values being passed to a | ||||
* function that requires a handle, e.g. Foo(Root<T>(cx, x)). | * function that requires a handle, e.g. Foo(Root<T>(cx, x)). | ||||
* | * | ||||
* If you want to add additional methods to Rooted for a specific | * If you want to add additional methods to Rooted for a specific | ||||
Show All 9 Lines | class MOZ_RAII Rooted : public js::RootedBase<T, Rooted<T>> { | ||||
inline RootedListHeads& rootLists(RootingContext* cx) { | inline RootedListHeads& rootLists(RootingContext* cx) { | ||||
return cx->stackRoots_; | return cx->stackRoots_; | ||||
} | } | ||||
inline RootedListHeads& rootLists(JSContext* cx) { | inline RootedListHeads& rootLists(JSContext* cx) { | ||||
return rootLists(RootingContext::get(cx)); | return rootLists(RootingContext::get(cx)); | ||||
} | } | ||||
// Define either one or two Rooted(cx) constructors: the fallback one, which | |||||
// constructs a Rooted holding a SafelyInitialized<T>, and a convenience one | |||||
// for types that can be constructed with a cx, which will give a Rooted | |||||
// holding a T(cx). | |||||
// Dummy type to distinguish these constructors from Rooted(cx, initial) | |||||
struct CtorDispatcher {}; | |||||
// Normal case: construct an empty Rooted holding a safely initialized but | |||||
// empty T. | |||||
template <typename RootingContext> | |||||
Rooted(const RootingContext& cx, CtorDispatcher, detail::FallbackOverload) | |||||
: Rooted(cx, SafelyInitialized<T>()) {} | |||||
// If T can be constructed with a cx, then define another constructor for it | |||||
// that will be preferred. | |||||
template <typename RootingContext, | |||||
typename = typename std::enable_if<std::is_constructible<T, RootingContext>::value>::type> | |||||
Rooted(const RootingContext& cx, CtorDispatcher, detail::PreferredOverload) | |||||
: Rooted(cx, T(cx)) {} | |||||
public: | public: | ||||
using ElementType = T; | using ElementType = T; | ||||
// Construct an empty Rooted. Delegates to an internal constructor that | |||||
// chooses a specific meaning of "empty" depending on whether T can be | |||||
// constructed with a cx. | |||||
template <typename RootingContext> | template <typename RootingContext> | ||||
explicit Rooted(const RootingContext& cx) : ptr(GCPolicy<T>::initial()) { | explicit Rooted(const RootingContext& cx) | ||||
registerWithRootLists(rootLists(cx)); | : Rooted(cx, CtorDispatcher(), detail::OverloadSelector()) {} | ||||
} | |||||
template <typename RootingContext, typename S> | template <typename RootingContext, typename S> | ||||
Rooted(const RootingContext& cx, S&& initial) | Rooted(const RootingContext& cx, S&& initial) | ||||
: ptr(mozilla::Forward<S>(initial)) { | : ptr(std::forward<S>(initial)) { | ||||
MOZ_ASSERT(GCPolicy<T>::isValid(ptr)); | MOZ_ASSERT(GCPolicy<T>::isValid(ptr)); | ||||
registerWithRootLists(rootLists(cx)); | registerWithRootLists(rootLists(cx)); | ||||
} | } | ||||
~Rooted() { | ~Rooted() { | ||||
MOZ_ASSERT(*stack == reinterpret_cast<Rooted<void*>*>(this)); | MOZ_ASSERT(*stack == reinterpret_cast<Rooted<void*>*>(this)); | ||||
*stack = prev; | *stack = prev; | ||||
} | } | ||||
Rooted<T>* previous() { return reinterpret_cast<Rooted<T>*>(prev); } | Rooted<T>* previous() { return reinterpret_cast<Rooted<T>*>(prev); } | ||||
/* | /* | ||||
* This method is public for Rooted so that Codegen.py can use a Rooted | * This method is public for Rooted so that Codegen.py can use a Rooted | ||||
* interchangeably with a MutableHandleValue. | * interchangeably with a MutableHandleValue. | ||||
*/ | */ | ||||
void set(const T& value) { | void set(const T& value) { | ||||
ptr = value; | ptr = value; | ||||
MOZ_ASSERT(GCPolicy<T>::isValid(ptr)); | MOZ_ASSERT(GCPolicy<T>::isValid(ptr)); | ||||
} | } | ||||
void set(T&& value) { | void set(T&& value) { | ||||
ptr = mozilla::Move(value); | ptr = std::move(value); | ||||
MOZ_ASSERT(GCPolicy<T>::isValid(ptr)); | MOZ_ASSERT(GCPolicy<T>::isValid(ptr)); | ||||
} | } | ||||
DECLARE_POINTER_CONSTREF_OPS(T); | DECLARE_POINTER_CONSTREF_OPS(T); | ||||
DECLARE_POINTER_ASSIGN_OPS(Rooted, T); | DECLARE_POINTER_ASSIGN_OPS(Rooted, T); | ||||
DECLARE_NONPOINTER_ACCESSOR_METHODS(ptr); | DECLARE_NONPOINTER_ACCESSOR_METHODS(ptr); | ||||
DECLARE_NONPOINTER_MUTABLE_ACCESSOR_METHODS(ptr); | DECLARE_NONPOINTER_MUTABLE_ACCESSOR_METHODS(ptr); | ||||
Show All 20 Lines | |||||
* | * | ||||
* - These must not be available on the more restricted superclasses of | * - These must not be available on the more restricted superclasses of | ||||
* JSContext, so we can't simply define them on RootingContext. | * JSContext, so we can't simply define them on RootingContext. | ||||
* | * | ||||
* - They're perfectly ordinary JSContext functionality, so ought to be | * - They're perfectly ordinary JSContext functionality, so ought to be | ||||
* usable without resorting to jsfriendapi.h, and when JSContext is an | * usable without resorting to jsfriendapi.h, and when JSContext is an | ||||
* incomplete type. | * incomplete type. | ||||
*/ | */ | ||||
inline JSCompartment* GetContextCompartment(const JSContext* cx) { | inline JS::Realm* GetContextRealm(const JSContext* cx) { | ||||
return JS::RootingContext::get(cx)->compartment_; | return JS::RootingContext::get(cx)->realm_; | ||||
} | |||||
inline JS::Compartment* GetContextCompartment(const JSContext* cx) { | |||||
if (JS::Realm* realm = GetContextRealm(cx)) { | |||||
return GetCompartmentForRealm(realm); | |||||
} | |||||
return nullptr; | |||||
} | } | ||||
inline JS::Zone* GetContextZone(const JSContext* cx) { | inline JS::Zone* GetContextZone(const JSContext* cx) { | ||||
return JS::RootingContext::get(cx)->zone_; | return JS::RootingContext::get(cx)->zone_; | ||||
} | } | ||||
inline PseudoStack* GetContextProfilingStack(JSContext* cx) { | inline ProfilingStack* GetContextProfilingStackIfEnabled(JSContext* cx) { | ||||
return JS::RootingContext::get(cx)->geckoProfiler().getPseudoStack(); | return JS::RootingContext::get(cx) | ||||
->geckoProfiler() | |||||
.getProfilingStackIfEnabled(); | |||||
} | } | ||||
/** | /** | ||||
* Augment the generic Rooted<T> interface when T = JSObject* with | * Augment the generic Rooted<T> interface when T = JSObject* with | ||||
* class-querying and downcasting operations. | * class-querying and downcasting operations. | ||||
* | * | ||||
* Given a Rooted<JSObject*> obj, one can view | * Given a Rooted<JSObject*> obj, one can view | ||||
* Handle<StringObject*> h = obj.as<StringObject*>(); | * Handle<StringObject*> h = obj.as<StringObject*>(); | ||||
▲ Show 20 Lines • Show All 165 Lines • ▼ Show 20 Lines | void registerWithRootLists(JSRuntime* rt) { | ||||
JS::RootKind kind = JS::MapTypeToRootKind<T>::kind; | JS::RootKind kind = JS::MapTypeToRootKind<T>::kind; | ||||
AddPersistentRoot(rt, kind, | AddPersistentRoot(rt, kind, | ||||
reinterpret_cast<JS::PersistentRooted<void*>*>(this)); | reinterpret_cast<JS::PersistentRooted<void*>*>(this)); | ||||
} | } | ||||
public: | public: | ||||
using ElementType = T; | using ElementType = T; | ||||
PersistentRooted() : ptr(GCPolicy<T>::initial()) {} | PersistentRooted() : ptr(SafelyInitialized<T>()) {} | ||||
explicit PersistentRooted(RootingContext* cx) : ptr(GCPolicy<T>::initial()) { | explicit PersistentRooted(RootingContext* cx) : ptr(SafelyInitialized<T>()) { | ||||
registerWithRootLists(cx); | registerWithRootLists(cx); | ||||
} | } | ||||
explicit PersistentRooted(JSContext* cx) : ptr(GCPolicy<T>::initial()) { | explicit PersistentRooted(JSContext* cx) : ptr(SafelyInitialized<T>()) { | ||||
registerWithRootLists(RootingContext::get(cx)); | registerWithRootLists(RootingContext::get(cx)); | ||||
} | } | ||||
template <typename U> | template <typename U> | ||||
PersistentRooted(RootingContext* cx, U&& initial) | PersistentRooted(RootingContext* cx, U&& initial) | ||||
: ptr(mozilla::Forward<U>(initial)) { | : ptr(std::forward<U>(initial)) { | ||||
registerWithRootLists(cx); | registerWithRootLists(cx); | ||||
} | } | ||||
template <typename U> | template <typename U> | ||||
PersistentRooted(JSContext* cx, U&& initial) | PersistentRooted(JSContext* cx, U&& initial) : ptr(std::forward<U>(initial)) { | ||||
: ptr(mozilla::Forward<U>(initial)) { | |||||
registerWithRootLists(RootingContext::get(cx)); | registerWithRootLists(RootingContext::get(cx)); | ||||
} | } | ||||
explicit PersistentRooted(JSRuntime* rt) : ptr(GCPolicy<T>::initial()) { | explicit PersistentRooted(JSRuntime* rt) : ptr(SafelyInitialized<T>()) { | ||||
registerWithRootLists(rt); | registerWithRootLists(rt); | ||||
} | } | ||||
template <typename U> | template <typename U> | ||||
PersistentRooted(JSRuntime* rt, U&& initial) | PersistentRooted(JSRuntime* rt, U&& initial) : ptr(std::forward<U>(initial)) { | ||||
: ptr(mozilla::Forward<U>(initial)) { | |||||
registerWithRootLists(rt); | registerWithRootLists(rt); | ||||
} | } | ||||
PersistentRooted(const PersistentRooted& rhs) | PersistentRooted(const PersistentRooted& rhs) | ||||
: mozilla::LinkedListElement<PersistentRooted<T>>(), ptr(rhs.ptr) { | : mozilla::LinkedListElement<PersistentRooted<T>>(), ptr(rhs.ptr) { | ||||
/* | /* | ||||
* Copy construction takes advantage of the fact that the original | * Copy construction takes advantage of the fact that the original | ||||
* is already inserted, and simply adds itself to whatever list the | * is already inserted, and simply adds itself to whatever list the | ||||
* original was on - no JSRuntime pointer needed. | * original was on - no JSRuntime pointer needed. | ||||
* | * | ||||
* This requires mutating rhs's links, but those should be 'mutable' | * This requires mutating rhs's links, but those should be 'mutable' | ||||
* anyway. C++ doesn't let us declare mutable base classes. | * anyway. C++ doesn't let us declare mutable base classes. | ||||
*/ | */ | ||||
const_cast<PersistentRooted&>(rhs).setNext(this); | const_cast<PersistentRooted&>(rhs).setNext(this); | ||||
} | } | ||||
bool initialized() { return ListBase::isInList(); } | bool initialized() { return ListBase::isInList(); } | ||||
void init(JSContext* cx) { init(cx, GCPolicy<T>::initial()); } | void init(JSContext* cx) { init(cx, SafelyInitialized<T>()); } | ||||
template <typename U> | template <typename U> | ||||
void init(JSContext* cx, U&& initial) { | void init(JSContext* cx, U&& initial) { | ||||
ptr = mozilla::Forward<U>(initial); | ptr = std::forward<U>(initial); | ||||
registerWithRootLists(RootingContext::get(cx)); | registerWithRootLists(RootingContext::get(cx)); | ||||
} | } | ||||
void reset() { | void reset() { | ||||
if (initialized()) { | if (initialized()) { | ||||
set(GCPolicy<T>::initial()); | set(SafelyInitialized<T>()); | ||||
ListBase::remove(); | ListBase::remove(); | ||||
} | } | ||||
} | } | ||||
DECLARE_POINTER_CONSTREF_OPS(T); | DECLARE_POINTER_CONSTREF_OPS(T); | ||||
DECLARE_POINTER_ASSIGN_OPS(PersistentRooted, T); | DECLARE_POINTER_ASSIGN_OPS(PersistentRooted, T); | ||||
DECLARE_NONPOINTER_ACCESSOR_METHODS(ptr); | DECLARE_NONPOINTER_ACCESSOR_METHODS(ptr); | ||||
// These are the same as DECLARE_NONPOINTER_MUTABLE_ACCESSOR_METHODS, except | // These are the same as DECLARE_NONPOINTER_MUTABLE_ACCESSOR_METHODS, except | ||||
// they check that |this| is initialized in case the caller later stores | // they check that |this| is initialized in case the caller later stores | ||||
// something in |ptr|. | // something in |ptr|. | ||||
T* address() { | T* address() { | ||||
MOZ_ASSERT(initialized()); | MOZ_ASSERT(initialized()); | ||||
return &ptr; | return &ptr; | ||||
} | } | ||||
T& get() { | T& get() { | ||||
MOZ_ASSERT(initialized()); | MOZ_ASSERT(initialized()); | ||||
return ptr; | return ptr; | ||||
} | } | ||||
private: | private: | ||||
template <typename U> | template <typename U> | ||||
void set(U&& value) { | void set(U&& value) { | ||||
MOZ_ASSERT(initialized()); | MOZ_ASSERT(initialized()); | ||||
ptr = mozilla::Forward<U>(value); | ptr = std::forward<U>(value); | ||||
} | } | ||||
detail::MaybeWrapped<T> ptr; | detail::MaybeWrapped<T> ptr; | ||||
} JS_HAZ_ROOTED; | } JS_HAZ_ROOTED; | ||||
class JS_PUBLIC_API ObjectPtr { | |||||
Heap<JSObject*> value; | |||||
public: | |||||
using ElementType = JSObject*; | |||||
ObjectPtr() : value(nullptr) {} | |||||
explicit ObjectPtr(JSObject* obj) : value(obj) {} | |||||
ObjectPtr(const ObjectPtr& other) : value(other.value) {} | |||||
ObjectPtr(ObjectPtr&& other) : value(other.value) { other.value = nullptr; } | |||||
/* Always call finalize before the destructor. */ | |||||
~ObjectPtr() { MOZ_ASSERT(!value); } | |||||
void finalize(JSRuntime* rt); | |||||
void finalize(JSContext* cx); | |||||
void init(JSObject* obj) { value = obj; } | |||||
JSObject* get() const { return value; } | |||||
JSObject* unbarrieredGet() const { return value.unbarrieredGet(); } | |||||
void writeBarrierPre(JSContext* cx) { IncrementalPreWriteBarrier(value); } | |||||
void updateWeakPointerAfterGC(); | |||||
ObjectPtr& operator=(JSObject* obj) { | |||||
IncrementalPreWriteBarrier(value); | |||||
value = obj; | |||||
return *this; | |||||
} | |||||
void trace(JSTracer* trc, const char* name); | |||||
JSObject& operator*() const { return *value; } | |||||
JSObject* operator->() const { return value; } | |||||
operator JSObject*() const { return value; } | |||||
explicit operator bool() const { return value.unbarrieredGet(); } | |||||
explicit operator bool() { return value.unbarrieredGet(); } | |||||
}; | |||||
} /* namespace JS */ | } /* namespace JS */ | ||||
namespace js { | namespace js { | ||||
template <typename T, typename D, typename Container> | template <typename T, typename D, typename Container> | ||||
class WrappedPtrOperations<UniquePtr<T, D>, Container> { | class WrappedPtrOperations<UniquePtr<T, D>, Container> { | ||||
const UniquePtr<T, D>& uniquePtr() const { | const UniquePtr<T, D>& uniquePtr() const { | ||||
return static_cast<const Container*>(this)->get(); | return static_cast<const Container*>(this)->get(); | ||||
▲ Show 20 Lines • Show All 78 Lines • ▼ Show 20 Lines | |||||
template <typename T> | template <typename T> | ||||
struct DefineComparisonOps<JS::TenuredHeap<T>> : mozilla::TrueType { | struct DefineComparisonOps<JS::TenuredHeap<T>> : mozilla::TrueType { | ||||
static const T get(const JS::TenuredHeap<T>& v) { | static const T get(const JS::TenuredHeap<T>& v) { | ||||
return v.unbarrieredGetPtr(); | return v.unbarrieredGetPtr(); | ||||
} | } | ||||
}; | }; | ||||
template <> | |||||
struct DefineComparisonOps<JS::ObjectPtr> : mozilla::TrueType { | |||||
static const JSObject* get(const JS::ObjectPtr& v) { | |||||
return v.unbarrieredGet(); | |||||
} | |||||
}; | |||||
template <typename T> | template <typename T> | ||||
struct DefineComparisonOps<JS::Rooted<T>> : mozilla::TrueType { | struct DefineComparisonOps<JS::Rooted<T>> : mozilla::TrueType { | ||||
static const T& get(const JS::Rooted<T>& v) { return v.get(); } | static const T& get(const JS::Rooted<T>& v) { return v.get(); } | ||||
}; | }; | ||||
template <typename T> | template <typename T> | ||||
struct DefineComparisonOps<JS::Handle<T>> : mozilla::TrueType { | struct DefineComparisonOps<JS::Handle<T>> : mozilla::TrueType { | ||||
static const T& get(const JS::Handle<T>& v) { return v.get(); } | static const T& get(const JS::Handle<T>& v) { return v.get(); } | ||||
▲ Show 20 Lines • Show All 165 Lines • Show Last 20 Lines |
Wildfire Games · Phabricator