Merge mozilla-central to autoland. a=merge CLOSED TREE
[gecko.git] / js / public / TraceKind.h
blob268db56957d58ac0b6d327d2e9913252e2c024a0
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/. */
7 #ifndef js_TraceKind_h
8 #define js_TraceKind_h
10 #include "mozilla/UniquePtr.h"
12 #include "js/TypeDecls.h"
14 // Forward declarations of all the types a TraceKind can denote.
15 class JSLinearString;
17 namespace js {
18 class BaseScript;
19 class BaseShape;
20 class GetterSetter;
21 class PropMap;
22 class RegExpShared;
23 class Shape;
24 class Scope;
25 namespace jit {
26 class JitCode;
27 } // namespace jit
28 } // namespace js
30 namespace JS {
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
35 // thing has.
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.
46 Object = 0x00,
47 BigInt = 0x01,
48 String = 0x02,
49 Symbol = 0x03,
51 // Shape details are exposed through JS_TraceShapeCycleCollectorChildren.
52 Shape = 0x04,
54 BaseShape = 0x05,
56 // The kind associated with a nullptr.
57 Null = 0x06,
59 // The following kinds do not have an exposed C++ idiom.
60 JitCode,
61 Script,
62 Scope,
63 RegExpShared,
64 GetterSetter,
65 PropMap,
68 // GCCellPtr packs the trace kind into the low bits of the pointer for common
69 // kinds.
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.
77 template <typename T>
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.
90 // clang-format off
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)
105 // clang-format on
107 // Returns true if the JS::TraceKind is represented as a node in cycle collector
108 // graph.
109 inline constexpr bool IsCCTraceKind(JS::TraceKind aKind) {
110 switch (aKind) {
111 #define JS_EXPAND_DEF(name, _1, _2, inCCGraph) \
112 case JS::TraceKind::name: \
113 return inCCGraph;
114 JS_FOR_EACH_TRACEKIND(JS_EXPAND_DEF);
115 #undef JS_EXPAND_DEF
116 default:
117 return false;
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) \
128 template <> \
129 struct IsBaseTraceType<type> : std::true_type {};
130 JS_FOR_EACH_TRACEKIND(JS_EXPAND_DEF);
131 #undef 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) \
138 template <> \
139 struct MapTypeToTraceKind<type> { \
140 static const JS::TraceKind kind = JS::TraceKind::name; \
142 JS_FOR_EACH_TRACEKIND(JS_EXPAND_DEF);
143 #undef JS_EXPAND_DEF
145 template <>
146 struct MapTypeToTraceKind<JSLinearString> {
147 static const JS::TraceKind kind = JS::TraceKind::String;
149 template <>
150 struct MapTypeToTraceKind<JSFunction> {
151 static const JS::TraceKind kind = JS::TraceKind::Object;
153 template <>
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.
169 Value,
171 // Everything else.
172 Traceable,
174 Limit
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) \
181 template <> \
182 struct MapTraceKindToRootKind<JS::TraceKind::name> { \
183 static const JS::RootKind kind = JS::RootKind::name; \
185 JS_FOR_EACH_TRACEKIND(JS_EXPAND_DEF)
186 #undef 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;
200 template <>
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;
209 template <>
210 struct MapTypeToRootKind<JS::Value> {
211 static const JS::RootKind kind = JS::RootKind::Value;
213 template <>
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.
223 // Given a call:
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) {
233 switch (traceKind) {
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);
238 #undef JS_EXPAND_DEF
239 default:
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
246 // result.
247 template <typename F>
248 auto MapGCThingTyped(void* thing, JS::TraceKind traceKind, F&& f) {
249 switch (traceKind) {
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);
254 #undef JS_EXPAND_DEF
255 default:
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
262 // result.
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));
271 } // namespace JS
273 #endif // js_TraceKind_h