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.
50 // Shape details are exposed through JS_TraceShapeCycleCollectorChildren.
55 // The kind associated with a nullptr.
58 // The following kinds do not have an exposed C++ idiom.
67 // GCCellPtr packs the trace kind into the low bits of the pointer for common
69 const static uintptr_t OutOfLineTraceKindMask
= 0x07;
70 static_assert(uintptr_t(JS::TraceKind::Null
) < OutOfLineTraceKindMask
,
71 "GCCellPtr requires an inline representation for nullptr");
73 // When this header is imported inside SpiderMonkey, the class definitions are
74 // available and we can query those definitions to find the correct kind
75 // directly from the class hierarchy.
77 struct MapTypeToTraceKind
{
78 static const JS::TraceKind kind
= T::TraceKind
;
81 // When this header is used outside SpiderMonkey, the class definitions are not
82 // available, so the following table containing all public GC types is used.
84 // canBeGray: GC can mark things of this kind gray. The cycle collector
85 // traverses gray GC things when looking for cycles.
86 // inCCGraph: Things of this kind are represented as nodes in the CC graph. This
87 // also means they can be used as a keys in WeakMap.
90 #define JS_FOR_EACH_TRACEKIND(D) \
91 /* name type canBeGray inCCGraph */ \
92 D(BaseShape, js::BaseShape, true, false) \
93 D(JitCode, js::jit::JitCode, true, false) \
94 D(Scope, js::Scope, true, true) \
95 D(Object, JSObject, true, true) \
96 D(Script, js::BaseScript, true, true) \
97 D(Shape, js::Shape, true, false) \
98 D(String, JSString, false, false) \
99 D(Symbol, JS::Symbol, false, false) \
100 D(BigInt, JS::BigInt, false, false) \
101 D(RegExpShared, js::RegExpShared, true, true) \
102 D(GetterSetter, js::GetterSetter, true, true) \
103 D(PropMap, js::PropMap, false, false)
106 // Returns true if the JS::TraceKind is represented as a node in cycle collector
108 inline constexpr bool IsCCTraceKind(JS::TraceKind aKind
) {
110 #define JS_EXPAND_DEF(name, _1, _2, inCCGraph) \
111 case JS::TraceKind::name: \
113 JS_FOR_EACH_TRACEKIND(JS_EXPAND_DEF
);
120 // Helper for SFINAE to ensure certain methods are only used on appropriate base
121 // types. This avoids common footguns such as `Cell::is<JSFunction>()` which
122 // match any type of JSObject.
123 template <typename T
>
124 struct IsBaseTraceType
: std::false_type
{};
126 #define JS_EXPAND_DEF(_, type, _1, _2) \
128 struct IsBaseTraceType<type> : std::true_type {};
129 JS_FOR_EACH_TRACEKIND(JS_EXPAND_DEF
);
132 template <typename T
>
133 inline constexpr bool IsBaseTraceType_v
= IsBaseTraceType
<T
>::value
;
135 // Map from all public types to their trace kind.
136 #define JS_EXPAND_DEF(name, type, _, _1) \
138 struct MapTypeToTraceKind<type> { \
139 static const JS::TraceKind kind = JS::TraceKind::name; \
141 JS_FOR_EACH_TRACEKIND(JS_EXPAND_DEF
);
145 struct MapTypeToTraceKind
<JSLinearString
> {
146 static const JS::TraceKind kind
= JS::TraceKind::String
;
149 struct MapTypeToTraceKind
<JSFunction
> {
150 static const JS::TraceKind kind
= JS::TraceKind::Object
;
153 struct MapTypeToTraceKind
<JSScript
> {
154 static const JS::TraceKind kind
= JS::TraceKind::Script
;
157 // RootKind is closely related to TraceKind. Whereas TraceKind's indices are
158 // laid out for convenient embedding as a pointer tag, the indicies of RootKind
159 // are designed for use as array keys via EnumeratedArray.
160 enum class RootKind
: int8_t {
161 // These map 1:1 with trace kinds.
162 #define EXPAND_ROOT_KIND(name, _0, _1, _2) name,
163 JS_FOR_EACH_TRACEKIND(EXPAND_ROOT_KIND
)
164 #undef EXPAND_ROOT_KIND
166 // These tagged pointers are special-cased for performance.
176 // Most RootKind correspond directly to a trace kind.
177 template <TraceKind traceKind
>
178 struct MapTraceKindToRootKind
{};
179 #define JS_EXPAND_DEF(name, _0, _1, _2) \
181 struct MapTraceKindToRootKind<JS::TraceKind::name> { \
182 static const JS::RootKind kind = JS::RootKind::name; \
184 JS_FOR_EACH_TRACEKIND(JS_EXPAND_DEF
)
187 // Specify the RootKind for all types. Value and jsid map to special cases;
188 // Cell pointer types we can derive directly from the TraceKind; everything else
189 // should go in the Traceable list and use GCPolicy<T>::trace for tracing.
190 template <typename T
>
191 struct MapTypeToRootKind
{
192 static const JS::RootKind kind
= JS::RootKind::Traceable
;
194 template <typename T
>
195 struct MapTypeToRootKind
<T
*> {
196 static const JS::RootKind kind
=
197 JS::MapTraceKindToRootKind
<JS::MapTypeToTraceKind
<T
>::kind
>::kind
;
200 struct MapTypeToRootKind
<JS::Realm
*> {
201 // Not a pointer to a GC cell. Use GCPolicy.
202 static const JS::RootKind kind
= JS::RootKind::Traceable
;
204 template <typename T
>
205 struct MapTypeToRootKind
<mozilla::UniquePtr
<T
>> {
206 static const JS::RootKind kind
= JS::MapTypeToRootKind
<T
>::kind
;
209 struct MapTypeToRootKind
<JS::Value
> {
210 static const JS::RootKind kind
= JS::RootKind::Value
;
213 struct MapTypeToRootKind
<jsid
> {
214 static const JS::RootKind kind
= JS::RootKind::Id
;
217 // Fortunately, few places in the system need to deal with fully abstract
218 // cells. In those places that do, we generally want to move to a layout
219 // templated function as soon as possible. This template wraps the upcast
220 // for that dispatch.
224 // DispatchTraceKindTyped(f, thing, traceKind, ... args)
226 // Downcast the |void *thing| to the specific type designated by |traceKind|,
227 // and pass it to the functor |f| along with |... args|, forwarded. Pass the
228 // type designated by |traceKind| as the functor's template argument. The
229 // |thing| parameter is optional; without it, we simply pass through |... args|.
230 template <typename F
, typename
... Args
>
231 auto DispatchTraceKindTyped(F f
, JS::TraceKind traceKind
, Args
&&... args
) {
233 #define JS_EXPAND_DEF(name, type, _, _1) \
234 case JS::TraceKind::name: \
235 return f.template operator()<type>(std::forward<Args>(args)...);
236 JS_FOR_EACH_TRACEKIND(JS_EXPAND_DEF
);
239 MOZ_CRASH("Invalid trace kind in DispatchTraceKindTyped.");
243 // Given a GC thing specified by pointer and trace kind, calls the functor |f|
244 // with a template argument of the actual type of the pointer and returns the
246 template <typename F
>
247 auto MapGCThingTyped(void* thing
, JS::TraceKind traceKind
, F
&& f
) {
249 #define JS_EXPAND_DEF(name, type, _, _1) \
250 case JS::TraceKind::name: \
251 return f(static_cast<type*>(thing));
252 JS_FOR_EACH_TRACEKIND(JS_EXPAND_DEF
);
255 MOZ_CRASH("Invalid trace kind in MapGCThingTyped.");
259 // Given a GC thing specified by pointer and trace kind, calls the functor |f|
260 // with a template argument of the actual type of the pointer and ignores the
262 template <typename F
>
263 void ApplyGCThingTyped(void* thing
, JS::TraceKind traceKind
, F
&& f
) {
264 // This function doesn't do anything but is supplied for symmetry with other
265 // MapGCThingTyped/ApplyGCThingTyped implementations that have to wrap the
266 // functor to return a dummy value that is ignored.
267 MapGCThingTyped(thing
, traceKind
, std::move(f
));
272 #endif // js_TraceKind_h