tor-browser

The Tor Browser
git clone https://git.dasho.dev/tor-browser.git
Log | Files | Refs | README | LICENSE

TraceKind.h (9662B)


      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/. */
      6 
      7 #ifndef js_TraceKind_h
      8 #define js_TraceKind_h
      9 
     10 #include "mozilla/UniquePtr.h"
     11 
     12 #include "js/TypeDecls.h"
     13 
     14 // Forward declarations of all the types a TraceKind can denote.
     15 class JSLinearString;
     16 
     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
     29 
     30 namespace JS {
     31 
     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.
     36 //
     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.
     39 //
     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  GetterSetter = 0x03,
     50  Symbol = 0x04,
     51 
     52  // Shape details are exposed through JS_TraceShapeCycleCollectorChildren.
     53  Shape = 0x05,
     54 
     55  // The kind associated with a nullptr.
     56  Null = 0x06,
     57 
     58  // The following kinds do not have an exposed C++ idiom.
     59  BaseShape,
     60  JitCode,
     61  Script,
     62  Scope,
     63  RegExpShared,
     64  PropMap
     65 };
     66 
     67 // GCCellPtr packs the trace kind into the low bits of the pointer for common
     68 // kinds.
     69 const static uintptr_t OutOfLineTraceKindMask = 0x07;
     70 static_assert(uintptr_t(JS::TraceKind::Null) < OutOfLineTraceKindMask,
     71              "GCCellPtr requires an inline representation for nullptr");
     72 
     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.
     76 template <typename T>
     77 struct MapTypeToTraceKind {
     78  static const JS::TraceKind kind = T::TraceKind;
     79 };
     80 
     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.
     83 //
     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.
     88 
     89 // clang-format off
     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,          true,      true)        \
    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,         true,      false)
    104 // clang-format on
    105 
    106 // Returns true if the JS::TraceKind is represented as a node in cycle collector
    107 // graph.
    108 inline constexpr bool IsCCTraceKind(JS::TraceKind aKind) {
    109  switch (aKind) {
    110 #define JS_EXPAND_DEF(name, _1, _2, inCCGraph) \
    111  case JS::TraceKind::name:                    \
    112    return inCCGraph;
    113    JS_FOR_EACH_TRACEKIND(JS_EXPAND_DEF);
    114 #undef JS_EXPAND_DEF
    115    default:
    116      return false;
    117  }
    118 }
    119 
    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 {};
    125 
    126 #define JS_EXPAND_DEF(_, type, _1, _2) \
    127  template <>                          \
    128  struct IsBaseTraceType<type> : std::true_type {};
    129 JS_FOR_EACH_TRACEKIND(JS_EXPAND_DEF);
    130 #undef JS_EXPAND_DEF
    131 
    132 template <typename T>
    133 inline constexpr bool IsBaseTraceType_v = IsBaseTraceType<T>::value;
    134 
    135 // Map from all public types to their trace kind.
    136 #define JS_EXPAND_DEF(name, type, _, _1)                   \
    137  template <>                                              \
    138  struct MapTypeToTraceKind<type> {                        \
    139    static const JS::TraceKind kind = JS::TraceKind::name; \
    140  };
    141 JS_FOR_EACH_TRACEKIND(JS_EXPAND_DEF);
    142 #undef JS_EXPAND_DEF
    143 
    144 template <>
    145 struct MapTypeToTraceKind<JSLinearString> {
    146  static const JS::TraceKind kind = JS::TraceKind::String;
    147 };
    148 template <>
    149 struct MapTypeToTraceKind<JSFunction> {
    150  static const JS::TraceKind kind = JS::TraceKind::Object;
    151 };
    152 template <>
    153 struct MapTypeToTraceKind<JSScript> {
    154  static const JS::TraceKind kind = JS::TraceKind::Script;
    155 };
    156 
    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
    165 
    166  // These tagged pointers are special-cased for performance.
    167  Id,
    168  Value,
    169 
    170  // Everything else.
    171  Traceable,
    172 
    173  Limit
    174 };
    175 
    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)                  \
    180  template <>                                            \
    181  struct MapTraceKindToRootKind<JS::TraceKind::name> {   \
    182    static const JS::RootKind kind = JS::RootKind::name; \
    183  };
    184 JS_FOR_EACH_TRACEKIND(JS_EXPAND_DEF)
    185 #undef JS_EXPAND_DEF
    186 
    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;
    193 };
    194 template <typename T>
    195 struct MapTypeToRootKind<T*> {
    196  static const JS::RootKind kind =
    197      JS::MapTraceKindToRootKind<JS::MapTypeToTraceKind<T>::kind>::kind;
    198 };
    199 template <>
    200 struct MapTypeToRootKind<JS::Realm*> {
    201  // Not a pointer to a GC cell. Use GCPolicy.
    202  static const JS::RootKind kind = JS::RootKind::Traceable;
    203 };
    204 template <typename T>
    205 struct MapTypeToRootKind<mozilla::UniquePtr<T>> {
    206  static const JS::RootKind kind = JS::MapTypeToRootKind<T>::kind;
    207 };
    208 template <>
    209 struct MapTypeToRootKind<JS::Value> {
    210  static const JS::RootKind kind = JS::RootKind::Value;
    211 };
    212 template <>
    213 struct MapTypeToRootKind<jsid> {
    214  static const JS::RootKind kind = JS::RootKind::Id;
    215 };
    216 
    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.
    221 //
    222 // Given a call:
    223 //
    224 //    DispatchTraceKindTyped(f, thing, traceKind, ... args)
    225 //
    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) {
    232  switch (traceKind) {
    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);
    237 #undef JS_EXPAND_DEF
    238    default:
    239      MOZ_CRASH("Invalid trace kind in DispatchTraceKindTyped.");
    240  }
    241 }
    242 
    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
    245 // result.
    246 template <typename F>
    247 auto MapGCThingTyped(void* thing, JS::TraceKind traceKind, F&& f) {
    248  switch (traceKind) {
    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);
    253 #undef JS_EXPAND_DEF
    254    default:
    255      MOZ_CRASH("Invalid trace kind in MapGCThingTyped.");
    256  }
    257 }
    258 
    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
    261 // result.
    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));
    268 }
    269 
    270 }  // namespace JS
    271 
    272 #endif  // js_TraceKind_h