1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*-
2 * vim: set ts=8 sts=2 et sw=2 tw=80:
3 * This Source Code Form is subject to the terms of the Mozilla Public
4 * License, v. 2.0. If a copy of the MPL was not distributed with this
5 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
10 #include "mozilla/UniquePtr.h"
12 #include "js/TypeDecls.h"
14 // Forward declarations of all the types a TraceKind can denote.
32 // When tracing a thing, the GC needs to know about the layout of the object it
33 // is looking at. There are a fixed number of different layouts that the GC
34 // knows about. The "trace kind" is a static map which tells which layout a GC
37 // Although this map is public, the details are completely hidden. Not all of
38 // the matching C++ types are exposed, and those that are, are opaque.
40 // See Value::gcKind() and JSTraceCallback in Tracer.h for more details.
41 enum class TraceKind
{
42 // These trace kinds have a publicly exposed, although opaque, C++ type.
43 // Note: The order here is determined by our Value packing. Other users
44 // should sort alphabetically, for consistency.
45 // Note: Nursery allocatable kinds go first. See js::gc::NurseryTraceKinds.
51 // Shape details are exposed through JS_TraceShapeCycleCollectorChildren.
56 // The kind associated with a nullptr.
59 // The following kinds do not have an exposed C++ idiom.
68 // GCCellPtr packs the trace kind into the low bits of the pointer for common
70 const static uintptr_t OutOfLineTraceKindMask
= 0x07;
71 static_assert(uintptr_t(JS::TraceKind::Null
) < OutOfLineTraceKindMask
,
72 "GCCellPtr requires an inline representation for nullptr");
74 // When this header is imported inside SpiderMonkey, the class definitions are
75 // available and we can query those definitions to find the correct kind
76 // directly from the class hierarchy.
78 struct MapTypeToTraceKind
{
79 static const JS::TraceKind kind
= T::TraceKind
;
82 // When this header is used outside SpiderMonkey, the class definitions are not
83 // available, so the following table containing all public GC types is used.
85 // canBeGray: GC can mark things of this kind gray. The cycle collector
86 // traverses gray GC things when looking for cycles.
87 // inCCGraph: Things of this kind are represented as nodes in the CC graph. This
88 // also means they can be used as a keys in WeakMap.
91 #define JS_FOR_EACH_TRACEKIND(D) \
92 /* name type canBeGray inCCGraph */ \
93 D(BaseShape, js::BaseShape, true, false) \
94 D(JitCode, js::jit::JitCode, true, false) \
95 D(Scope, js::Scope, true, true) \
96 D(Object, JSObject, true, true) \
97 D(Script, js::BaseScript, true, true) \
98 D(Shape, js::Shape, true, false) \
99 D(String, JSString, false, false) \
100 D(Symbol, JS::Symbol, false, false) \
101 D(BigInt, JS::BigInt, false, false) \
102 D(RegExpShared, js::RegExpShared, true, true) \
103 D(GetterSetter, js::GetterSetter, true, true) \
104 D(PropMap, js::PropMap, false, false)
107 // Returns true if the JS::TraceKind is represented as a node in cycle collector
109 inline constexpr bool IsCCTraceKind(JS::TraceKind aKind
) {
111 #define JS_EXPAND_DEF(name, _1, _2, inCCGraph) \
112 case JS::TraceKind::name: \
114 JS_FOR_EACH_TRACEKIND(JS_EXPAND_DEF
);
121 // Helper for SFINAE to ensure certain methods are only used on appropriate base
122 // types. This avoids common footguns such as `Cell::is<JSFunction>()` which
123 // match any type of JSObject.
124 template <typename T
>
125 struct IsBaseTraceType
: std::false_type
{};
127 #define JS_EXPAND_DEF(_, type, _1, _2) \
129 struct IsBaseTraceType<type> : std::true_type {};
130 JS_FOR_EACH_TRACEKIND(JS_EXPAND_DEF
);
133 template <typename T
>
134 inline constexpr bool IsBaseTraceType_v
= IsBaseTraceType
<T
>::value
;
136 // Map from all public types to their trace kind.
137 #define JS_EXPAND_DEF(name, type, _, _1) \
139 struct MapTypeToTraceKind<type> { \
140 static const JS::TraceKind kind = JS::TraceKind::name; \
142 JS_FOR_EACH_TRACEKIND(JS_EXPAND_DEF
);
146 struct MapTypeToTraceKind
<JSLinearString
> {
147 static const JS::TraceKind kind
= JS::TraceKind::String
;
150 struct MapTypeToTraceKind
<JSFunction
> {
151 static const JS::TraceKind kind
= JS::TraceKind::Object
;
154 struct MapTypeToTraceKind
<JSScript
> {
155 static const JS::TraceKind kind
= JS::TraceKind::Script
;
158 // RootKind is closely related to TraceKind. Whereas TraceKind's indices are
159 // laid out for convenient embedding as a pointer tag, the indicies of RootKind
160 // are designed for use as array keys via EnumeratedArray.
161 enum class RootKind
: int8_t {
162 // These map 1:1 with trace kinds.
163 #define EXPAND_ROOT_KIND(name, _0, _1, _2) name,
164 JS_FOR_EACH_TRACEKIND(EXPAND_ROOT_KIND
)
165 #undef EXPAND_ROOT_KIND
167 // These tagged pointers are special-cased for performance.
177 // Most RootKind correspond directly to a trace kind.
178 template <TraceKind traceKind
>
179 struct MapTraceKindToRootKind
{};
180 #define JS_EXPAND_DEF(name, _0, _1, _2) \
182 struct MapTraceKindToRootKind<JS::TraceKind::name> { \
183 static const JS::RootKind kind = JS::RootKind::name; \
185 JS_FOR_EACH_TRACEKIND(JS_EXPAND_DEF
)
188 // Specify the RootKind for all types. Value and jsid map to special cases;
189 // Cell pointer types we can derive directly from the TraceKind; everything else
190 // should go in the Traceable list and use GCPolicy<T>::trace for tracing.
191 template <typename T
>
192 struct MapTypeToRootKind
{
193 static const JS::RootKind kind
= JS::RootKind::Traceable
;
195 template <typename T
>
196 struct MapTypeToRootKind
<T
*> {
197 static const JS::RootKind kind
=
198 JS::MapTraceKindToRootKind
<JS::MapTypeToTraceKind
<T
>::kind
>::kind
;
201 struct MapTypeToRootKind
<JS::Realm
*> {
202 // Not a pointer to a GC cell. Use GCPolicy.
203 static const JS::RootKind kind
= JS::RootKind::Traceable
;
205 template <typename T
>
206 struct MapTypeToRootKind
<mozilla::UniquePtr
<T
>> {
207 static const JS::RootKind kind
= JS::MapTypeToRootKind
<T
>::kind
;
210 struct MapTypeToRootKind
<JS::Value
> {
211 static const JS::RootKind kind
= JS::RootKind::Value
;
214 struct MapTypeToRootKind
<jsid
> {
215 static const JS::RootKind kind
= JS::RootKind::Id
;
218 // Fortunately, few places in the system need to deal with fully abstract
219 // cells. In those places that do, we generally want to move to a layout
220 // templated function as soon as possible. This template wraps the upcast
221 // for that dispatch.
225 // DispatchTraceKindTyped(f, thing, traceKind, ... args)
227 // Downcast the |void *thing| to the specific type designated by |traceKind|,
228 // and pass it to the functor |f| along with |... args|, forwarded. Pass the
229 // type designated by |traceKind| as the functor's template argument. The
230 // |thing| parameter is optional; without it, we simply pass through |... args|.
231 template <typename F
, typename
... Args
>
232 auto DispatchTraceKindTyped(F f
, JS::TraceKind traceKind
, Args
&&... args
) {
234 #define JS_EXPAND_DEF(name, type, _, _1) \
235 case JS::TraceKind::name: \
236 return f.template operator()<type>(std::forward<Args>(args)...);
237 JS_FOR_EACH_TRACEKIND(JS_EXPAND_DEF
);
240 MOZ_CRASH("Invalid trace kind in DispatchTraceKindTyped.");
244 // Given a GC thing specified by pointer and trace kind, calls the functor |f|
245 // with a template argument of the actual type of the pointer and returns the
247 template <typename F
>
248 auto MapGCThingTyped(void* thing
, JS::TraceKind traceKind
, F
&& f
) {
250 #define JS_EXPAND_DEF(name, type, _, _1) \
251 case JS::TraceKind::name: \
252 return f(static_cast<type*>(thing));
253 JS_FOR_EACH_TRACEKIND(JS_EXPAND_DEF
);
256 MOZ_CRASH("Invalid trace kind in MapGCThingTyped.");
260 // Given a GC thing specified by pointer and trace kind, calls the functor |f|
261 // with a template argument of the actual type of the pointer and ignores the
263 template <typename F
>
264 void ApplyGCThingTyped(void* thing
, JS::TraceKind traceKind
, F
&& f
) {
265 // This function doesn't do anything but is supplied for symmetry with other
266 // MapGCThingTyped/ApplyGCThingTyped implementations that have to wrap the
267 // functor to return a dummy value that is ignored.
268 MapGCThingTyped(thing
, traceKind
, std::move(f
));
273 #endif // js_TraceKind_h