TraceKind.h 7.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212
  1. /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 4 -*-
  2. * vim: set ts=8 sts=4 et sw=4 tw=99:
  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. #ifndef js_TraceKind_h
  7. #define js_TraceKind_h
  8. #include "mozilla/UniquePtr.h"
  9. #include "js/TypeDecls.h"
  10. // Forward declarations of all the types a TraceKind can denote.
  11. namespace js {
  12. class BaseShape;
  13. class LazyScript;
  14. class ObjectGroup;
  15. class Shape;
  16. class Scope;
  17. namespace jit {
  18. class JitCode;
  19. } // namespace jit
  20. } // namespace js
  21. namespace JS {
  22. // When tracing a thing, the GC needs to know about the layout of the object it
  23. // is looking at. There are a fixed number of different layouts that the GC
  24. // knows about. The "trace kind" is a static map which tells which layout a GC
  25. // thing has.
  26. //
  27. // Although this map is public, the details are completely hidden. Not all of
  28. // the matching C++ types are exposed, and those that are, are opaque.
  29. //
  30. // See Value::gcKind() and JSTraceCallback in Tracer.h for more details.
  31. enum class TraceKind
  32. {
  33. // These trace kinds have a publicly exposed, although opaque, C++ type.
  34. // Note: The order here is determined by our Value packing. Other users
  35. // should sort alphabetically, for consistency.
  36. Object = 0x00,
  37. String = 0x01,
  38. Symbol = 0x02,
  39. Script = 0x03,
  40. // Shape details are exposed through JS_TraceShapeCycleCollectorChildren.
  41. Shape = 0x04,
  42. // ObjectGroup details are exposed through JS_TraceObjectGroupCycleCollectorChildren.
  43. ObjectGroup = 0x05,
  44. // The kind associated with a nullptr.
  45. Null = 0x06,
  46. // The following kinds do not have an exposed C++ idiom.
  47. BaseShape = 0x0F,
  48. JitCode = 0x1F,
  49. LazyScript = 0x2F,
  50. Scope = 0x3F
  51. };
  52. const static uintptr_t OutOfLineTraceKindMask = 0x07;
  53. static_assert(uintptr_t(JS::TraceKind::BaseShape) & OutOfLineTraceKindMask, "mask bits are set");
  54. static_assert(uintptr_t(JS::TraceKind::JitCode) & OutOfLineTraceKindMask, "mask bits are set");
  55. static_assert(uintptr_t(JS::TraceKind::LazyScript) & OutOfLineTraceKindMask, "mask bits are set");
  56. static_assert(uintptr_t(JS::TraceKind::Scope) & OutOfLineTraceKindMask, "mask bits are set");
  57. // When this header is imported inside SpiderMonkey, the class definitions are
  58. // available and we can query those definitions to find the correct kind
  59. // directly from the class hierarchy.
  60. template <typename T>
  61. struct MapTypeToTraceKind {
  62. static const JS::TraceKind kind = T::TraceKind;
  63. };
  64. // When this header is used outside SpiderMonkey, the class definitions are not
  65. // available, so the following table containing all public GC types is used.
  66. #define JS_FOR_EACH_TRACEKIND(D) \
  67. /* PrettyName TypeName AddToCCKind */ \
  68. D(BaseShape, js::BaseShape, true) \
  69. D(JitCode, js::jit::JitCode, true) \
  70. D(LazyScript, js::LazyScript, true) \
  71. D(Scope, js::Scope, true) \
  72. D(Object, JSObject, true) \
  73. D(ObjectGroup, js::ObjectGroup, true) \
  74. D(Script, JSScript, true) \
  75. D(Shape, js::Shape, true) \
  76. D(String, JSString, false) \
  77. D(Symbol, JS::Symbol, false)
  78. // Map from all public types to their trace kind.
  79. #define JS_EXPAND_DEF(name, type, _) \
  80. template <> struct MapTypeToTraceKind<type> { \
  81. static const JS::TraceKind kind = JS::TraceKind::name; \
  82. };
  83. JS_FOR_EACH_TRACEKIND(JS_EXPAND_DEF);
  84. #undef JS_EXPAND_DEF
  85. // RootKind is closely related to TraceKind. Whereas TraceKind's indices are
  86. // laid out for convenient embedding as a pointer tag, the indicies of RootKind
  87. // are designed for use as array keys via EnumeratedArray.
  88. enum class RootKind : int8_t
  89. {
  90. // These map 1:1 with trace kinds.
  91. #define EXPAND_ROOT_KIND(name, _0, _1) \
  92. name,
  93. JS_FOR_EACH_TRACEKIND(EXPAND_ROOT_KIND)
  94. #undef EXPAND_ROOT_KIND
  95. // These tagged pointers are special-cased for performance.
  96. Id,
  97. Value,
  98. // Everything else.
  99. Traceable,
  100. Limit
  101. };
  102. // Most RootKind correspond directly to a trace kind.
  103. template <TraceKind traceKind> struct MapTraceKindToRootKind {};
  104. #define JS_EXPAND_DEF(name, _0, _1) \
  105. template <> struct MapTraceKindToRootKind<JS::TraceKind::name> { \
  106. static const JS::RootKind kind = JS::RootKind::name; \
  107. };
  108. JS_FOR_EACH_TRACEKIND(JS_EXPAND_DEF)
  109. #undef JS_EXPAND_DEF
  110. // Specify the RootKind for all types. Value and jsid map to special cases;
  111. // pointer types we can derive directly from the TraceKind; everything else
  112. // should go in the Traceable list and use GCPolicy<T>::trace for tracing.
  113. template <typename T>
  114. struct MapTypeToRootKind {
  115. static const JS::RootKind kind = JS::RootKind::Traceable;
  116. };
  117. template <typename T>
  118. struct MapTypeToRootKind<T*> {
  119. static const JS::RootKind kind =
  120. JS::MapTraceKindToRootKind<JS::MapTypeToTraceKind<T>::kind>::kind;
  121. };
  122. template <typename T>
  123. struct MapTypeToRootKind<mozilla::UniquePtr<T>> {
  124. static const JS::RootKind kind = JS::MapTypeToRootKind<T>::kind;
  125. };
  126. template <> struct MapTypeToRootKind<JS::Value> {
  127. static const JS::RootKind kind = JS::RootKind::Value;
  128. };
  129. template <> struct MapTypeToRootKind<jsid> {
  130. static const JS::RootKind kind = JS::RootKind::Id;
  131. };
  132. template <> struct MapTypeToRootKind<JSFunction*> : public MapTypeToRootKind<JSObject*> {};
  133. // Fortunately, few places in the system need to deal with fully abstract
  134. // cells. In those places that do, we generally want to move to a layout
  135. // templated function as soon as possible. This template wraps the upcast
  136. // for that dispatch.
  137. //
  138. // Given a call:
  139. //
  140. // DispatchTraceKindTyped(f, thing, traceKind, ... args)
  141. //
  142. // Downcast the |void *thing| to the specific type designated by |traceKind|,
  143. // and pass it to the functor |f| along with |... args|, forwarded. Pass the
  144. // type designated by |traceKind| as the functor's template argument. The
  145. // |thing| parameter is optional; without it, we simply pass through |... args|.
  146. // GCC and Clang require an explicit template declaration in front of the
  147. // specialization of operator() because it is a dependent template. MSVC, on
  148. // the other hand, gets very confused if we have a |template| token there.
  149. // The clang-cl front end defines _MSC_VER, but still requires the explicit
  150. // template declaration, so we must test for __clang__ here as well.
  151. #if defined(_MSC_VER) && !defined(__clang__)
  152. # define JS_DEPENDENT_TEMPLATE_HINT
  153. #else
  154. # define JS_DEPENDENT_TEMPLATE_HINT template
  155. #endif
  156. template <typename F, typename... Args>
  157. auto
  158. DispatchTraceKindTyped(F f, JS::TraceKind traceKind, Args&&... args)
  159. -> decltype(f. JS_DEPENDENT_TEMPLATE_HINT operator()<JSObject>(mozilla::Forward<Args>(args)...))
  160. {
  161. switch (traceKind) {
  162. #define JS_EXPAND_DEF(name, type, _) \
  163. case JS::TraceKind::name: \
  164. return f. JS_DEPENDENT_TEMPLATE_HINT operator()<type>(mozilla::Forward<Args>(args)...);
  165. JS_FOR_EACH_TRACEKIND(JS_EXPAND_DEF);
  166. #undef JS_EXPAND_DEF
  167. default:
  168. MOZ_CRASH("Invalid trace kind in DispatchTraceKindTyped.");
  169. }
  170. }
  171. #undef JS_DEPENDENT_TEMPLATE_HINT
  172. template <typename F, typename... Args>
  173. auto
  174. DispatchTraceKindTyped(F f, void* thing, JS::TraceKind traceKind, Args&&... args)
  175. -> decltype(f(static_cast<JSObject*>(nullptr), mozilla::Forward<Args>(args)...))
  176. {
  177. switch (traceKind) {
  178. #define JS_EXPAND_DEF(name, type, _) \
  179. case JS::TraceKind::name: \
  180. return f(static_cast<type*>(thing), mozilla::Forward<Args>(args)...);
  181. JS_FOR_EACH_TRACEKIND(JS_EXPAND_DEF);
  182. #undef JS_EXPAND_DEF
  183. default:
  184. MOZ_CRASH("Invalid trace kind in DispatchTraceKindTyped.");
  185. }
  186. }
  187. } // namespace JS
  188. #endif // js_TraceKind_h