author | Sandor Molnar <smolnar@mozilla.com> |
Tue, 21 Sep 2021 11:37:12 +0300 | |
changeset 592590 | 2be5c656e888fb1ebdadc7220561621e7c146f4a |
parent 592589 | 3e3296e0b0e655a144a7482ed360d0f1daefa245 |
child 592591 | 4c4b28b643e6f25bea8fef5487023459ed0d600e |
push id | 38809 |
push user | smolnar@mozilla.com |
push date | Tue, 21 Sep 2021 15:52:59 +0000 |
treeherder | mozilla-central@79a3346995bc [default view] [failures only] |
perfherder | [talos] [build metrics] [platform microbench] (compared to previous push) |
bugs | 1731218 |
milestone | 94.0a1 |
backs out | 0dfcae8520269987517985f34e30be82d698e463 e2c59b5af7eae47644125bebb533b8454c8d6a85 3e98b832dcc6fffeaa4251137cec10cb679476d4 57e60277e4ca8b09b1d6b82fee6f97379b794c83 3b264a4bc67e2adb877fc2af9c58b63b84f4de7f 304f27af6b950cc07970fbd25e29491122a4d614 06e7a1992de8e6e3335a19b49f2e3f2d81614909 |
first release with | nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
|
last release without | nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
|
--- a/js/public/RootingAPI.h +++ b/js/public/RootingAPI.h @@ -120,27 +120,26 @@ struct BarrierMethods {}; template <typename Element, typename Wrapper> class WrappedPtrOperations {}; template <typename Element, typename Wrapper> class MutableWrappedPtrOperations : public WrappedPtrOperations<Element, Wrapper> {}; template <typename T, typename Wrapper> -class RootedOperations : public MutableWrappedPtrOperations<T, Wrapper> {}; - -template <typename T, typename Wrapper> -class HandleOperations : public WrappedPtrOperations<T, Wrapper> {}; +class RootedBase : public MutableWrappedPtrOperations<T, Wrapper> {}; template <typename T, typename Wrapper> -class MutableHandleOperations : public MutableWrappedPtrOperations<T, Wrapper> { -}; +class HandleBase : public WrappedPtrOperations<T, Wrapper> {}; template <typename T, typename Wrapper> -class HeapOperations : public MutableWrappedPtrOperations<T, Wrapper> {}; +class MutableHandleBase : public MutableWrappedPtrOperations<T, Wrapper> {}; + +template <typename T, typename Wrapper> +class HeapBase : public MutableWrappedPtrOperations<T, Wrapper> {}; // Cannot use FOR_EACH_HEAP_ABLE_GC_POINTER_TYPE, as this would import too many // macros into scope template <typename T> struct IsHeapConstructibleType { static constexpr bool value = false; }; #define DECLARE_IS_HEAP_CONSTRUCTIBLE_TYPE(T) \ @@ -285,17 +284,17 @@ inline void AssertGCThingIsNotNurseryAll * keep the pointed-to GC thing alive. * * Heap<T> objects should only be used on the heap. GC references stored on the * C/C++ stack must use Rooted/Handle/MutableHandle instead. * * Type T must be a public GC pointer type. */ template <typename T> -class MOZ_NON_MEMMOVABLE Heap : public js::HeapOperations<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 // legacy reasons. static_assert(js::IsHeapConstructibleType<T>::value, "Type T must be a public GC pointer type"); public: using ElementType = T; @@ -445,17 +444,17 @@ inline void AssertObjectIsNotGray(const * The considerations to keep in mind when using a TenuredHeap<T> vs a normal * Heap<T> are: * * - It is invalid for a TenuredHeap<T> to refer to a non-tenured thing. * - It is however valid for a Heap<T> to refer to a tenured thing. * - It is not possible to store flag bits in a Heap<T>. */ template <typename T> -class TenuredHeap : public js::HeapOperations<T, TenuredHeap<T>> { +class TenuredHeap : public js::HeapBase<T, TenuredHeap<T>> { public: using ElementType = T; TenuredHeap() : bits(0) { static_assert(sizeof(T) == sizeof(TenuredHeap<T>), "TenuredHeap<T> must be binary compatible with T."); } explicit TenuredHeap(T p) : bits(0) { setPtr(p); } @@ -565,20 +564,20 @@ template <typename T> class PersistentRooted; /** * 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 * rooted. See "Move GC Stack Rooting" above. * * If you want to add additional methods to Handle for a specific - * specialization, define a HandleOperations<T> specialization containing them. + * specialization, define a HandleBase<T> specialization containing them. */ template <typename T> -class MOZ_NONHEAP_CLASS Handle : public js::HandleOperations<T, Handle<T>> { +class MOZ_NONHEAP_CLASS Handle : public js::HandleBase<T, Handle<T>> { friend class MutableHandle<T>; public: using ElementType = T; Handle(const Handle<T>&) = default; /* Creates a handle from a handle of a type convertible to T. */ @@ -663,22 +662,22 @@ struct DefineComparisonOps<Handle<T>> : } // namespace detail /** * Similar to a handle, but the underlying storage can be changed. This is * useful for outparams. * * If you want to add additional methods to MutableHandle for a specific - * specialization, define a MutableHandleOperations<T> specialization containing + * specialization, define a MutableHandleBase<T> specialization containing * them. */ template <typename T> class MOZ_STACK_CLASS MutableHandle - : public js::MutableHandleOperations<T, MutableHandle<T>> { + : public js::MutableHandleBase<T, MutableHandle<T>> { public: using ElementType = T; inline MOZ_IMPLICIT MutableHandle(Rooted<T>* root); inline MOZ_IMPLICIT MutableHandle(PersistentRooted<T>* root); private: // Disallow nullptr for overloading purposes. @@ -873,92 +872,89 @@ struct FallibleHashMethods<js::MovableCe namespace js { struct VirtualTraceable { virtual ~VirtualTraceable() = default; virtual void trace(JSTracer* trc, const char* name) = 0; }; -class StackRootedBase { - public: - StackRootedBase* previous() { return prev; } - - protected: - StackRootedBase** stack; - StackRootedBase* prev; +template <typename T> +struct RootedTraceable final : public VirtualTraceable { + static_assert(JS::MapTypeToRootKind<T>::kind == JS::RootKind::Traceable, + "RootedTraceable is intended only for usage with a Traceable"); - template <typename T> - auto* derived() { - return static_cast<JS::Rooted<T>*>(this); - } -}; - -class PersistentRootedBase - : protected mozilla::LinkedListElement<PersistentRootedBase> { - protected: - friend class mozilla::LinkedList<PersistentRootedBase>; - friend class mozilla::LinkedListElement<PersistentRootedBase>; + T ptr; - template <typename T> - auto* derived() { - return static_cast<JS::PersistentRooted<T>*>(this); - } -}; - -struct StackRootedTraceableBase : public StackRootedBase, - public VirtualTraceable {}; - -class PersistentRootedTraceableBase : public PersistentRootedBase, - public VirtualTraceable {}; + template <typename... CtorArgs> + explicit RootedTraceable(std::in_place_t, CtorArgs... args) + : ptr(std::forward<CtorArgs>(args)...) {} -template <typename Base, typename T> -class TypedRootedGCThingBase : public Base { - public: - void trace(JSTracer* trc, const char* name); -}; + template <typename U, typename = typename std::is_constructible<T, U>::type> + MOZ_IMPLICIT RootedTraceable(U&& initial) : ptr(std::forward<U>(initial)) {} -template <typename Base, typename T> -class TypedRootedTraceableBase : public Base { - public: + operator T&() { return ptr; } + operator const T&() const { return ptr; } + void trace(JSTracer* trc, const char* name) override { - auto* self = this->template derived<T>(); - JS::GCPolicy<T>::trace(trc, self->address(), name); + JS::GCPolicy<T>::trace(trc, &ptr, name); } }; template <typename T> struct RootedTraceableTraits { - using StackRootedBase = TypedRootedTraceableBase<StackRootedTraceableBase, T>; - using PersistentRootedBase = - TypedRootedTraceableBase<PersistentRootedTraceableBase, T>; + static T* address(RootedTraceable<T>& self) { return &self.ptr; } + static const T* address(const RootedTraceable<T>& self) { return &self.ptr; } + static void trace(JSTracer* trc, VirtualTraceable* thingp, const char* name); }; template <typename T> struct RootedGCThingTraits { - using StackRootedBase = TypedRootedGCThingBase<StackRootedBase, T>; - using PersistentRootedBase = TypedRootedGCThingBase<PersistentRootedBase, T>; + static T* address(T& self) { return &self; } + static const T* address(const T& self) { return &self; } + static void trace(JSTracer* trc, T* thingp, const char* name); }; } /* namespace js */ namespace JS { class JS_PUBLIC_API AutoGCRooter; enum class AutoGCRooterKind : uint8_t { WrapperVector, /* js::AutoWrapperVector */ Wrapper, /* js::AutoWrapperRooter */ Custom, /* js::CustomAutoRooter */ Limit }; +namespace detail { +// Dummy type to store root list entry pointers as. This code does not just use +// the actual type, because then eg JSObject* and JSFunction* would be assumed +// to never alias but they do (they are stored in the same list). Also, do not +// use `void*` so that `Rooted<void*>` is a compile error. +struct RootListEntry; +} // namespace detail + +template <> +struct MapTypeToRootKind<detail::RootListEntry*> { + static const RootKind kind = RootKind::Traceable; +}; + +// Workaround MSVC issue where GCPolicy is needed even though this dummy type is +// never instantiated. Ideally, RootListEntry is removed in the future and an +// appropriate class hierarchy for the Rooted<T> types. +template <> +struct GCPolicy<detail::RootListEntry*> + : public IgnoreGCPolicy<detail::RootListEntry*> {}; + using RootedListHeads = - mozilla::EnumeratedArray<RootKind, RootKind::Limit, js::StackRootedBase*>; + mozilla::EnumeratedArray<RootKind, RootKind::Limit, + Rooted<detail::RootListEntry*>*>; using AutoRooterListHeads = mozilla::EnumeratedArray<AutoGCRooterKind, AutoGCRooterKind::Limit, AutoGCRooter*>; // Superclass of JSContext which can be used for rooting data in use by the // current thread but that does not provide all the functions of a JSContext. class RootingContext { @@ -1086,39 +1082,43 @@ class MOZ_RAII JS_PUBLIC_API CustomAutoR namespace detail { template <typename T> constexpr bool IsTraceable_v = MapTypeToRootKind<T>::kind == JS::RootKind::Traceable; template <typename T> +using RootedPtr = + std::conditional_t<IsTraceable_v<T>, js::RootedTraceable<T>, T>; + +template <typename T> using RootedPtrTraits = std::conditional_t<IsTraceable_v<T>, js::RootedTraceableTraits<T>, js::RootedGCThingTraits<T>>; } /* namespace detail */ /** * 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 * function that requires a handle, e.g. Foo(Root<T>(cx, x)). * * If you want to add additional methods to Rooted for a specific - * specialization, define a RootedOperations<T> specialization containing them. + * specialization, define a RootedBase<T> specialization containing them. */ template <typename T> -class MOZ_RAII Rooted : public detail::RootedPtrTraits<T>::StackRootedBase, - public js::RootedOperations<T, Rooted<T>> { +class MOZ_RAII Rooted : public js::RootedBase<T, Rooted<T>> { + using Ptr = detail::RootedPtr<T>; using PtrTraits = detail::RootedPtrTraits<T>; inline void registerWithRootLists(RootedListHeads& roots) { this->stack = &roots[JS::MapTypeToRootKind<T>::kind]; - this->prev = *this->stack; - *this->stack = this; + this->prev = *stack; + *stack = reinterpret_cast<Rooted<detail::RootListEntry*>*>(this); } inline RootedListHeads& rootLists(RootingContext* cx) { return cx->stackRoots_; } inline RootedListHeads& rootLists(JSContext* cx) { return rootLists(RootingContext::get(cx)); } @@ -1136,17 +1136,18 @@ class MOZ_RAII Rooted : public detail::R typename = std::enable_if_t<std::is_copy_constructible_v<T>, RootingContext>> explicit Rooted(const RootingContext& cx) : ptr(SafelyInitialized<T>()) { registerWithRootLists(rootLists(cx)); } // Provide an initial value. Requires T to be constructible from the given // argument. - template <typename RootingContext, typename S> + template <typename RootingContext, typename S, + typename = typename std::is_constructible<T, S>::type> Rooted(const RootingContext& cx, S&& initial) : ptr(std::forward<S>(initial)) { MOZ_ASSERT(GCPolicy<T>::isValid(ptr)); registerWithRootLists(rootLists(cx)); } // (Traceables only) Construct the contained value from the given arguments. // Constructs in-place, so T does not need to be copyable or movable. @@ -1155,26 +1156,29 @@ class MOZ_RAII Rooted : public detail::R // choose the above SafelyInitialized<T> constructor, because otherwise // identical functions with parameter packs are considered less specialized. // // The SFINAE type must again depend on an inferred template parameter. template < typename RootingContext, typename... CtorArgs, typename = std::enable_if_t<detail::IsTraceable_v<T>, RootingContext>> explicit Rooted(const RootingContext& cx, CtorArgs... args) - : ptr(std::forward<CtorArgs>(args)...) { + : ptr(std::in_place, std::forward<CtorArgs>(args)...) { MOZ_ASSERT(GCPolicy<T>::isValid(ptr)); registerWithRootLists(rootLists(cx)); } ~Rooted() { - MOZ_ASSERT(*this->stack == this); - *this->stack = this->prev; + MOZ_ASSERT(*stack == + reinterpret_cast<Rooted<detail::RootListEntry*>*>(this)); + *stack = prev; } + Rooted<T>* previous() { return reinterpret_cast<Rooted<T>*>(prev); } + /* * This method is public for Rooted so that Codegen.py can use a Rooted * interchangeably with a MutableHandleValue. */ void set(const T& value) { ptr = value; MOZ_ASSERT(GCPolicy<T>::isValid(ptr)); } @@ -1184,21 +1188,31 @@ class MOZ_RAII Rooted : public detail::R } DECLARE_POINTER_CONSTREF_OPS(T); DECLARE_POINTER_ASSIGN_OPS(Rooted, T); T& get() { return ptr; } const T& get() const { return ptr; } - T* address() { return &ptr; } - const T* address() const { return &ptr; } + T* address() { return PtrTraits::address(ptr); } + const T* address() const { return PtrTraits::address(ptr); } + + void trace(JSTracer* trc, const char* name); private: - T ptr; + /* + * These need to be templated on RootListEntry* to avoid aliasing issues + * between, for example, Rooted<JSObject*> and Rooted<JSFunction*>, which use + * the same stack head pointer for different classes. + */ + Rooted<detail::RootListEntry*>** stack; + Rooted<detail::RootListEntry*>* prev; + + Ptr ptr; Rooted(const Rooted&) = delete; } JS_HAZ_ROOTED; namespace detail { template <typename T> struct DefineComparisonOps<Rooted<T>> : std::true_type { @@ -1248,17 +1262,17 @@ inline ProfilingStack* GetContextProfili * * Given a Rooted<JSObject*> obj, one can view * Handle<StringObject*> h = obj.as<StringObject*>(); * as an optimization of * Rooted<StringObject*> rooted(cx, &obj->as<StringObject*>()); * Handle<StringObject*> h = rooted; */ template <typename Container> -class RootedOperations<JSObject*, Container> +class RootedBase<JSObject*, Container> : public MutableWrappedPtrOperations<JSObject*, Container> { public: template <class U> JS::Handle<U*> as() const; }; /** * Augment the generic Handle<T> interface when T = JSObject* with @@ -1266,17 +1280,17 @@ class RootedOperations<JSObject*, Contai * * Given a Handle<JSObject*> obj, one can view * Handle<StringObject*> h = obj.as<StringObject*>(); * as an optimization of * Rooted<StringObject*> rooted(cx, &obj->as<StringObject*>()); * Handle<StringObject*> h = rooted; */ template <typename Container> -class HandleOperations<JSObject*, Container> +class HandleBase<JSObject*, Container> : public WrappedPtrOperations<JSObject*, Container> { public: template <class U> JS::Handle<U*> as() const; }; } /* namespace js */ @@ -1315,21 +1329,23 @@ inline MutableHandle<T>::MutableHandle(R template <typename T> inline MutableHandle<T>::MutableHandle(PersistentRooted<T>* root) { static_assert(sizeof(MutableHandle<T>) == sizeof(T*), "MutableHandle must be binary compatible with T*."); ptr = root->address(); } -JS_PUBLIC_API void AddPersistentRoot(RootingContext* cx, RootKind kind, - js::PersistentRootedBase* root); +JS_PUBLIC_API void AddPersistentRoot( + RootingContext* cx, RootKind kind, + PersistentRooted<detail::RootListEntry*>* root); -JS_PUBLIC_API void AddPersistentRoot(JSRuntime* rt, RootKind kind, - js::PersistentRootedBase* root); +JS_PUBLIC_API void AddPersistentRoot( + JSRuntime* rt, RootKind kind, + PersistentRooted<detail::RootListEntry*>* root); /** * A copyable, assignable global GC root type with arbitrary lifetime, an * infallible constructor, and automatic unrooting on destruction. * * These roots can be used in heap-allocated data structures, so they are not * associated with any particular JSContext or stack. They are registered with * the JSRuntime itself, without locking. Initialization may take place on @@ -1356,30 +1372,39 @@ JS_PUBLIC_API void AddPersistentRoot(JSR * Firefox is owned by some JS object or another, so using PersistentRooted in * such objects would introduce leaks. For these kinds of edges, Heap<T> or * TenuredHeap<T> would be better types. It's up to the implementor of the type * containing Heap<T> or TenuredHeap<T> members to make sure their referents get * marked when the object itself is marked. */ template <typename T> class PersistentRooted - : public detail::RootedPtrTraits<T>::PersistentRootedBase, - public js::RootedOperations<T, PersistentRooted<T>> { + : public js::RootedBase<T, PersistentRooted<T>>, + private mozilla::LinkedListElement<PersistentRooted<T>> { + using ListBase = mozilla::LinkedListElement<PersistentRooted<T>>; + using Ptr = detail::RootedPtr<T>; using PtrTraits = detail::RootedPtrTraits<T>; + friend class mozilla::LinkedList<PersistentRooted>; + friend class mozilla::LinkedListElement<PersistentRooted>; + void registerWithRootLists(RootingContext* cx) { MOZ_ASSERT(!initialized()); JS::RootKind kind = JS::MapTypeToRootKind<T>::kind; - AddPersistentRoot(cx, kind, this); + AddPersistentRoot( + cx, kind, + reinterpret_cast<JS::PersistentRooted<detail::RootListEntry*>*>(this)); } void registerWithRootLists(JSRuntime* rt) { MOZ_ASSERT(!initialized()); JS::RootKind kind = JS::MapTypeToRootKind<T>::kind; - AddPersistentRoot(rt, kind, this); + AddPersistentRoot( + rt, kind, + reinterpret_cast<JS::PersistentRooted<detail::RootListEntry*>*>(this)); } // Used when JSContext type is incomplete and so it is not known to inherit // from RootingContext. void registerWithRootLists(JSContext* cx) { registerWithRootLists(RootingContext::get(cx)); } @@ -1401,33 +1426,34 @@ class PersistentRooted PersistentRooted(const RootHolder& cx, U&& initial) : ptr(std::forward<U>(initial)) { registerWithRootLists(cx); } template <typename RootHolder, typename... CtorArgs, typename = std::enable_if_t<detail::IsTraceable_v<T>, RootHolder>> explicit PersistentRooted(const RootHolder& cx, CtorArgs... args) - : ptr(std::forward<CtorArgs>(args)...) { + : ptr(std::in_place, std::forward<CtorArgs>(args)...) { registerWithRootLists(cx); } - PersistentRooted(const PersistentRooted& rhs) : ptr(rhs.ptr) { + PersistentRooted(const PersistentRooted& rhs) + : mozilla::LinkedListElement<PersistentRooted<T>>(), ptr(rhs.ptr) { /* * Copy construction takes advantage of the fact that the original * is already inserted, and simply adds itself to whatever list the * original was on - no JSRuntime pointer needed. * * This requires mutating rhs's links, but those should be 'mutable' * anyway. C++ doesn't let us declare mutable base classes. */ const_cast<PersistentRooted&>(rhs).setNext(this); } - bool initialized() const { return this->isInList(); } + bool initialized() const { return ListBase::isInList(); } void init(RootingContext* cx) { init(cx, SafelyInitialized<T>()); } void init(JSContext* cx) { init(RootingContext::get(cx)); } template <typename U> void init(RootingContext* cx, U&& initial) { ptr = std::forward<U>(initial); registerWithRootLists(cx); @@ -1436,40 +1462,42 @@ class PersistentRooted void init(JSContext* cx, U&& initial) { ptr = std::forward<U>(initial); registerWithRootLists(RootingContext::get(cx)); } void reset() { if (initialized()) { set(SafelyInitialized<T>()); - this->remove(); + ListBase::remove(); } } DECLARE_POINTER_CONSTREF_OPS(T); DECLARE_POINTER_ASSIGN_OPS(PersistentRooted, T); T& get() { return ptr; } const T& get() const { return ptr; } T* address() { MOZ_ASSERT(initialized()); - return &ptr; + return PtrTraits::address(ptr); } - const T* address() const { return &ptr; } + const T* address() const { return PtrTraits::address(ptr); } template <typename U> void set(U&& value) { MOZ_ASSERT(initialized()); ptr = std::forward<U>(value); } + void trace(JSTracer* trc, const char* name); + private: - T ptr; + Ptr ptr; } JS_HAZ_ROOTED; namespace detail { template <typename T> struct DefineComparisonOps<PersistentRooted<T>> : std::true_type { static const T& get(const PersistentRooted<T>& v) { return v.get(); } };
--- a/js/public/Value.h +++ b/js/public/Value.h @@ -1212,17 +1212,17 @@ class MutableWrappedPtrOperations<JS::Va } }; /* * Augment the generic Heap<T> interface when T = Value with * type-querying, value-extracting, and mutating operations. */ template <typename Wrapper> -class HeapOperations<JS::Value, Wrapper> +class HeapBase<JS::Value, Wrapper> : public MutableWrappedPtrOperations<JS::Value, Wrapper> {}; MOZ_HAVE_NORETURN MOZ_COLD MOZ_NEVER_INLINE void ReportBadValueTypeAndCrash( const JS::Value& val); // If the Value is a GC pointer type, call |f| with the pointer cast to that // type and return the result wrapped in a Maybe, otherwise return None(). template <typename F>
--- a/js/src/gc/MaybeRooted.h +++ b/js/src/gc/MaybeRooted.h @@ -23,17 +23,17 @@ namespace js { /** * Interface substitute for Rooted<T> which does not root the variable's * memory. */ template <typename T> -class MOZ_RAII FakeRooted : public RootedOperations<T, FakeRooted<T>> { +class MOZ_RAII FakeRooted : public RootedBase<T, FakeRooted<T>> { public: using ElementType = T; explicit FakeRooted(JSContext* cx) : ptr(JS::SafelyInitialized<T>()) {} FakeRooted(JSContext* cx, T initial) : ptr(initial) {} DECLARE_POINTER_CONSTREF_OPS(T); @@ -67,17 +67,17 @@ struct DefineComparisonOps<js::FakeRoote namespace js { /** * Interface substitute for MutableHandle<T> which is not required to point to * rooted memory. */ template <typename T> class FakeMutableHandle - : public js::MutableHandleOperations<T, FakeMutableHandle<T>> { + : public js::MutableHandleBase<T, FakeMutableHandle<T>> { public: using ElementType = T; MOZ_IMPLICIT FakeMutableHandle(T* t) : ptr(t) {} MOZ_IMPLICIT FakeMutableHandle(FakeRooted<T>* root) : ptr(root->address()) {} void set(const T& v) { *ptr = v; }
--- a/js/src/gc/RootMarking.cpp +++ b/js/src/gc/RootMarking.cpp @@ -35,40 +35,57 @@ using namespace js::gc; using mozilla::LinkedList; using JS::AutoGCRooter; using RootRange = RootedValueMap::Range; using RootEntry = RootedValueMap::Entry; using RootEnum = RootedValueMap::Enum; -template <typename Base, typename T> -inline void TypedRootedGCThingBase<Base, T>::trace(JSTracer* trc, - const char* name) { - auto* self = this->template derived<T>(); - TraceNullableRoot(trc, self->address(), name); +// For more detail see JS::Rooted::root and js::RootedTraceable. +// +// The JS::RootKind::Traceable list contains a bunch of totally disparate types, +// but to refer to this list we need /something/ in the type field. We use the +// following type as a compatible stand-in. No actual methods from +// ConcreteTraceable type are actually used at runtime. +struct ConcreteTraceable { + ConcreteTraceable() = delete; + void trace(JSTracer*) = delete; +}; + +template <typename T> +inline void RootedGCThingTraits<T>::trace(JSTracer* trc, T* thingp, + const char* name) { + TraceNullableRoot(trc, thingp, name); } template <typename T> -static inline void TraceExactStackRootList(JSTracer* trc, - StackRootedBase* listHead, - const char* name) { - // Check size of Rooted<T> does not increase. - static_assert(sizeof(Rooted<T>) == sizeof(T) + 2 * sizeof(uintptr_t)); +inline void RootedTraceableTraits<T>::trace(JSTracer* trc, + VirtualTraceable* thingp, + const char* name) { + thingp->trace(trc, name); +} - for (StackRootedBase* root = listHead; root; root = root->previous()) { - static_cast<Rooted<T>*>(root)->trace(trc, name); - } +template <typename T> +inline void JS::Rooted<T>::trace(JSTracer* trc, const char* name) { + PtrTraits::trace(trc, &ptr, name); } -static inline void TraceExactStackRootTraceableList(JSTracer* trc, - StackRootedBase* listHead, - const char* name) { - for (StackRootedBase* root = listHead; root; root = root->previous()) { - static_cast<StackRootedTraceableBase*>(root)->trace(trc, name); +template <typename T> +inline void JS::PersistentRooted<T>::trace(JSTracer* trc, const char* name) { + PtrTraits::trace(trc, &ptr, name); +} + +template <typename T> +static inline void TraceExactStackRootList( + JSTracer* trc, JS::Rooted<JS::detail::RootListEntry*>* listHead, + const char* name) { + auto* typedList = reinterpret_cast<JS::Rooted<T>*>(listHead); + for (JS::Rooted<T>* root = typedList; root; root = root->previous()) { + root->trace(trc, name); } } static inline void TraceStackRoots(JSTracer* trc, JS::RootedListHeads& stackRoots) { #define TRACE_ROOTS(name, type, _, _1) \ TraceExactStackRootList<type*>(trc, stackRoots[JS::RootKind::name], \ "exact-" #name); @@ -76,40 +93,36 @@ static inline void TraceStackRoots(JSTra #undef TRACE_ROOTS TraceExactStackRootList<jsid>(trc, stackRoots[JS::RootKind::Id], "exact-id"); TraceExactStackRootList<Value>(trc, stackRoots[JS::RootKind::Value], "exact-value"); // RootedTraceable uses virtual dispatch. JS::AutoSuppressGCAnalysis nogc; - TraceExactStackRootTraceableList(trc, stackRoots[JS::RootKind::Traceable], - "Traceable"); + TraceExactStackRootList<ConcreteTraceable>( + trc, stackRoots[JS::RootKind::Traceable], "Traceable"); } void JS::RootingContext::traceStackRoots(JSTracer* trc) { TraceStackRoots(trc, stackRoots_); } static void TraceExactStackRoots(JSContext* cx, JSTracer* trc) { cx->traceStackRoots(trc); } template <typename T> static inline void TracePersistentRootedList( - JSTracer* trc, LinkedList<PersistentRootedBase>& list, const char* name) { - for (PersistentRootedBase* root : list) { - static_cast<PersistentRooted<T>*>(root)->trace(trc, name); - } -} - -static inline void TracePersistentRootedTraceableList( - JSTracer* trc, LinkedList<PersistentRootedBase>& list, const char* name) { - for (PersistentRootedBase* root : list) { - static_cast<PersistentRootedTraceableBase*>(root)->trace(trc, name); + JSTracer* trc, + LinkedList<PersistentRooted<JS::detail::RootListEntry*>>& list, + const char* name) { + auto& typedList = reinterpret_cast<LinkedList<PersistentRooted<T>>&>(list); + for (PersistentRooted<T>* root : typedList) { + root->trace(trc, name); } } void JSRuntime::tracePersistentRoots(JSTracer* trc) { #define TRACE_ROOTS(name, type, _, _1) \ TracePersistentRootedList<type*>(trc, heapRoots.ref()[JS::RootKind::name], \ "persistent-" #name); JS_FOR_EACH_TRACEKIND(TRACE_ROOTS) @@ -117,29 +130,30 @@ void JSRuntime::tracePersistentRoots(JST TracePersistentRootedList<jsid>(trc, heapRoots.ref()[JS::RootKind::Id], "persistent-id"); TracePersistentRootedList<Value>(trc, heapRoots.ref()[JS::RootKind::Value], "persistent-value"); // RootedTraceable uses virtual dispatch. JS::AutoSuppressGCAnalysis nogc; - TracePersistentRootedTraceableList( + TracePersistentRootedList<ConcreteTraceable>( trc, heapRoots.ref()[JS::RootKind::Traceable], "persistent-traceable"); } static void TracePersistentRooted(JSRuntime* rt, JSTracer* trc) { rt->tracePersistentRoots(trc); } template <typename T> static void FinishPersistentRootedChain( - LinkedList<PersistentRootedBase>& list) { + LinkedList<PersistentRooted<JS::detail::RootListEntry*>>& listArg) { + auto& list = reinterpret_cast<LinkedList<PersistentRooted<T>>&>(listArg); while (!list.isEmpty()) { - static_cast<PersistentRooted<T>*>(list.getFirst())->reset(); + list.getFirst()->reset(); } } void JSRuntime::finishPersistentRoots() { #define FINISH_ROOT_LIST(name, type, _, _1) \ FinishPersistentRootedChain<type*>(heapRoots.ref()[JS::RootKind::name]); JS_FOR_EACH_TRACEKIND(FINISH_ROOT_LIST) #undef FINISH_ROOT_LIST @@ -449,18 +463,20 @@ void js::gc::GCRuntime::finishRoots() { void js::gc::GCRuntime::checkNoRuntimeRoots(AutoGCSession& session) { #ifdef DEBUG AssertNoRootsTracer trc(rt); traceRuntimeForMajorGC(&trc, session); #endif // DEBUG } -JS_PUBLIC_API void JS::AddPersistentRoot(JS::RootingContext* cx, RootKind kind, - PersistentRootedBase* root) { - JSRuntime* rt = static_cast<JSContext*>(cx)->runtime(); +JS_PUBLIC_API void JS::AddPersistentRoot( + JS::RootingContext* cx, RootKind kind, + PersistentRooted<JS::detail::RootListEntry*>* root) { + static_cast<JSContext*>(cx)->runtime()->heapRoots.ref()[kind].insertBack( + root); +} + +JS_PUBLIC_API void JS::AddPersistentRoot( + JSRuntime* rt, RootKind kind, + PersistentRooted<JS::detail::RootListEntry*>* root) { rt->heapRoots.ref()[kind].insertBack(root); } - -JS_PUBLIC_API void JS::AddPersistentRoot(JSRuntime* rt, RootKind kind, - PersistentRootedBase* root) { - rt->heapRoots.ref()[kind].insertBack(root); -}
--- a/js/src/jsapi-tests/testGCExactRooting.cpp +++ b/js/src/jsapi-tests/testGCExactRooting.cpp @@ -118,17 +118,17 @@ BEGIN_TEST(testGCRootedStaticStructInter JS::Rooted<MyContainer> r1(cx); JS::Rooted<MyContainer> r2(cx, 3.4); JS::Rooted<MyContainer> r3(cx, MyContainer(cx)); JS::Rooted<MyContainer> r4(cx, cx); JS::Rooted<MyContainer> r5(cx, cx, cx, cx); JS::Rooted<Value> rv(cx); - CHECK_EQUAL(r1.constructor(), 1); // direct SafelyInitialized<T> + CHECK_EQUAL(r1.constructor(), 101); // copy of SafelyInitialized<T> CHECK_EQUAL(r2.constructor(), 2); // direct MyContainer(3.4) CHECK_EQUAL(r3.constructor(), 103); // copy of MyContainer(cx) CHECK_EQUAL(r4.constructor(), 3); // direct MyContainer(cx) CHECK_EQUAL(r5.constructor(), 4); // direct MyContainer(cx, cx, cx) // Test Rooted constructor forwarding for a non-copyable type. JS::Rooted<MyNonCopyableContainer> nc1(cx); JS::Rooted<MyNonCopyableContainer> nc2(cx, 3.4); @@ -164,17 +164,17 @@ BEGIN_TEST(testGCRootedStaticStructInter JS::PersistentRooted<MyContainer> heap(cx, container); // Copyable types in place. JS::PersistentRooted<MyContainer> cp1(cx); JS::PersistentRooted<MyContainer> cp2(cx, 7.8); JS::PersistentRooted<MyContainer> cp3(cx, cx); JS::PersistentRooted<MyContainer> cp4(cx, cx, cx, cx); - CHECK_EQUAL(cp1.constructor(), 1); // direct SafelyInitialized<T> + CHECK_EQUAL(cp1.constructor(), 101); // copy of SafelyInitialized<T> CHECK_EQUAL(cp2.constructor(), 2); // direct MyContainer(double) CHECK_EQUAL(cp3.constructor(), 3); // direct MyContainer(cx) CHECK_EQUAL(cp4.constructor(), 4); // direct MyContainer(cx, cx, cx) // Construct uncopyable type in place. JS::PersistentRooted<MyNonCopyableContainer> ncp1(cx); JS::PersistentRooted<MyNonCopyableContainer> ncp2(cx, 7.8);
--- a/js/src/vm/Interpreter.cpp +++ b/js/src/vm/Interpreter.cpp @@ -1788,17 +1788,17 @@ static MOZ_ALWAYS_INLINE void InitElemAr * upon entry. ReservedRooted "borrows" a reserved Rooted variable and uses it * within a local scope, resetting the value to nullptr (or the appropriate * equivalent for T) at scope end. This avoids inserting/removing the Rooted * from the rooter list, while preventing stale values from being kept alive * unnecessarily. */ template <typename T> -class ReservedRooted : public RootedOperations<T, ReservedRooted<T>> { +class ReservedRooted : public RootedBase<T, ReservedRooted<T>> { Rooted<T>* savedRoot; public: ReservedRooted(Rooted<T>* root, const T& ptr) : savedRoot(root) { *root = ptr; } explicit ReservedRooted(Rooted<T>* root) : savedRoot(root) {
--- a/js/src/vm/JSObject.h +++ b/js/src/vm/JSObject.h @@ -559,27 +559,27 @@ class JSObject template <> inline bool JSObject::is<JSObject>() const { return true; } template <typename Wrapper> template <typename U> -MOZ_ALWAYS_INLINE JS::Handle<U*> js::RootedOperations<JSObject*, Wrapper>::as() +MOZ_ALWAYS_INLINE JS::Handle<U*> js::RootedBase<JSObject*, Wrapper>::as() const { const Wrapper& self = *static_cast<const Wrapper*>(this); MOZ_ASSERT(self->template is<U>()); return Handle<U*>::fromMarkedLocation( reinterpret_cast<U* const*>(self.address())); } template <typename Wrapper> template <class U> -MOZ_ALWAYS_INLINE JS::Handle<U*> js::HandleOperations<JSObject*, Wrapper>::as() +MOZ_ALWAYS_INLINE JS::Handle<U*> js::HandleBase<JSObject*, Wrapper>::as() const { const JS::Handle<JSObject*>& self = *static_cast<const JS::Handle<JSObject*>*>(this); MOZ_ASSERT(self->template is<U>()); return Handle<U*>::fromMarkedLocation( reinterpret_cast<U* const*>(self.address())); }
--- a/js/src/vm/Runtime.h +++ b/js/src/vm/Runtime.h @@ -427,19 +427,19 @@ struct JSRuntime { private: /* Gecko profiling metadata */ js::UnprotectedData<js::GeckoProfilerRuntime> geckoProfiler_; public: js::GeckoProfilerRuntime& geckoProfiler() { return geckoProfiler_.ref(); } // Heap GC roots for PersistentRooted pointers. - js::MainThreadData< - mozilla::EnumeratedArray<JS::RootKind, JS::RootKind::Limit, - mozilla::LinkedList<js::PersistentRootedBase>>> + js::MainThreadData<mozilla::EnumeratedArray< + JS::RootKind, JS::RootKind::Limit, + mozilla::LinkedList<JS::PersistentRooted<JS::detail::RootListEntry*>>>> heapRoots; void tracePersistentRoots(JSTracer* trc); void finishPersistentRoots(); void finishRoots(); private: